1 /* 2 * Copyright 2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include <net_datalink.h> 11 #include <net_protocol.h> 12 #include <net_stack.h> 13 #include <NetBufferUtilities.h> 14 15 #include <KernelExport.h> 16 #include <util/list.h> 17 18 #include <netinet/in.h> 19 #include <new> 20 #include <stdlib.h> 21 #include <string.h> 22 23 24 struct icmp_header { 25 uint8 type; 26 uint8 code; 27 uint16 checksum; 28 union { 29 struct { 30 uint16 id; 31 uint16 sequence; 32 } echo; 33 struct { 34 in_addr_t gateway; 35 } redirect; 36 struct { 37 uint16 _reserved; 38 uint16 next_mtu; 39 } path_mtu; 40 uint32 zero; 41 }; 42 }; 43 44 #define ICMP_TYPE_ECHO_REPLY 0 45 #define ICMP_TYPE_UNREACH 3 46 #define ICMP_TYPE_REDIRECT 5 47 #define ICMP_TYPE_ECHO_REQUEST 8 48 49 // type unreach codes 50 #define ICMP_CODE_UNREACH_NEED_FRAGMENT 4 // this is used for path MTU discovery 51 52 struct icmp_protocol : net_protocol { 53 }; 54 55 56 static net_stack_module_info *sStackModule; 57 struct net_buffer_module_info *sBufferModule; 58 59 60 net_protocol * 61 icmp_init_protocol(net_socket *socket) 62 { 63 icmp_protocol *protocol = new (std::nothrow) icmp_protocol; 64 if (protocol == NULL) 65 return NULL; 66 67 return protocol; 68 } 69 70 71 status_t 72 icmp_uninit_protocol(net_protocol *protocol) 73 { 74 delete protocol; 75 return B_OK; 76 } 77 78 79 status_t 80 icmp_open(net_protocol *protocol) 81 { 82 return B_OK; 83 } 84 85 86 status_t 87 icmp_close(net_protocol *protocol) 88 { 89 return B_OK; 90 } 91 92 93 status_t 94 icmp_free(net_protocol *protocol) 95 { 96 return B_OK; 97 } 98 99 100 status_t 101 icmp_connect(net_protocol *protocol, const struct sockaddr *address) 102 { 103 return B_ERROR; 104 } 105 106 107 status_t 108 icmp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 109 { 110 return EOPNOTSUPP; 111 } 112 113 114 status_t 115 icmp_control(net_protocol *protocol, int level, int option, void *value, 116 size_t *_length) 117 { 118 return protocol->next->module->control(protocol->next, level, option, 119 value, _length); 120 } 121 122 123 status_t 124 icmp_bind(net_protocol *protocol, struct sockaddr *address) 125 { 126 return B_ERROR; 127 } 128 129 130 status_t 131 icmp_unbind(net_protocol *protocol, struct sockaddr *address) 132 { 133 return B_ERROR; 134 } 135 136 137 status_t 138 icmp_listen(net_protocol *protocol, int count) 139 { 140 return EOPNOTSUPP; 141 } 142 143 144 status_t 145 icmp_shutdown(net_protocol *protocol, int direction) 146 { 147 return EOPNOTSUPP; 148 } 149 150 151 status_t 152 icmp_send_data(net_protocol *protocol, net_buffer *buffer) 153 { 154 return protocol->next->module->send_data(protocol->next, buffer); 155 } 156 157 158 status_t 159 icmp_send_routed_data(net_protocol *protocol, struct net_route *route, 160 net_buffer *buffer) 161 { 162 return protocol->next->module->send_routed_data(protocol->next, route, buffer); 163 } 164 165 166 ssize_t 167 icmp_send_avail(net_protocol *protocol) 168 { 169 return B_ERROR; 170 } 171 172 173 status_t 174 icmp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 175 net_buffer **_buffer) 176 { 177 return B_ERROR; 178 } 179 180 181 ssize_t 182 icmp_read_avail(net_protocol *protocol) 183 { 184 return B_ERROR; 185 } 186 187 188 struct net_domain * 189 icmp_get_domain(net_protocol *protocol) 190 { 191 return protocol->next->module->get_domain(protocol->next); 192 } 193 194 195 size_t 196 icmp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 197 { 198 return protocol->next->module->get_mtu(protocol->next, address); 199 } 200 201 202 status_t 203 icmp_receive_data(net_buffer *buffer) 204 { 205 dprintf("ICMP received some data, buffer length %lu\n", buffer->size); 206 207 NetBufferHeader<icmp_header> bufferHeader(buffer); 208 if (bufferHeader.Status() < B_OK) 209 return bufferHeader.Status(); 210 211 icmp_header &header = bufferHeader.Data(); 212 bufferHeader.Detach(); 213 // the pointer stays valid after this 214 215 dprintf(" got type %u, code %u, checksum %u\n", header.type, header.code, 216 ntohs(header.checksum)); 217 dprintf(" computed checksum: %ld\n", sBufferModule->checksum(buffer, 0, buffer->size, true)); 218 if (sBufferModule->checksum(buffer, 0, buffer->size, true) != 0) 219 return B_BAD_DATA; 220 221 switch (header.type) { 222 case ICMP_TYPE_ECHO_REPLY: 223 break; 224 225 case ICMP_TYPE_ECHO_REQUEST: 226 { 227 net_domain *domain; 228 if (buffer->interface != NULL) 229 domain = buffer->interface->domain; 230 else 231 domain = sStackModule->get_domain(buffer->source.ss_family); 232 if (domain == NULL || domain->module == NULL) 233 break; 234 235 net_buffer *reply = sBufferModule->duplicate(buffer); 236 if (reply == NULL) 237 return B_NO_MEMORY; 238 239 // switch source/destination address 240 memcpy(&reply->source, &buffer->destination, buffer->destination.ss_len); 241 memcpy(&reply->destination, &buffer->source, buffer->source.ss_len); 242 243 // There already is an ICMP header, and we'll reuse it 244 icmp_header *header; 245 status_t status = sBufferModule->direct_access(reply, 246 0, sizeof(icmp_header), (void **)&header); 247 if (status == B_OK) { 248 header->type = ICMP_TYPE_ECHO_REPLY; 249 header->code = 0; 250 header->checksum = 0; 251 header->checksum = sBufferModule->checksum(reply, 0, reply->size, true); 252 } 253 254 if (status == B_OK) 255 status = domain->module->send_data(NULL, reply); 256 257 if (status < B_OK) { 258 sBufferModule->free(reply); 259 return status; 260 } 261 } 262 } 263 264 sBufferModule->free(buffer); 265 return B_OK; 266 } 267 268 269 status_t 270 icmp_error(uint32 code, net_buffer *data) 271 { 272 return B_ERROR; 273 } 274 275 276 status_t 277 icmp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, 278 void *errorData) 279 { 280 return B_ERROR; 281 } 282 283 284 // #pragma mark - 285 286 287 static status_t 288 icmp_std_ops(int32 op, ...) 289 { 290 switch (op) { 291 case B_MODULE_INIT: 292 { 293 status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); 294 if (status < B_OK) 295 return status; 296 status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&sBufferModule); 297 if (status < B_OK) { 298 put_module(NET_STACK_MODULE_NAME); 299 return status; 300 } 301 302 sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_ICMP, 303 "network/protocols/icmp/v1", 304 "network/protocols/ipv4/v1", 305 NULL); 306 307 sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_ICMP, 308 "network/protocols/icmp/v1"); 309 return B_OK; 310 } 311 312 case B_MODULE_UNINIT: 313 put_module(NET_BUFFER_MODULE_NAME); 314 put_module(NET_STACK_MODULE_NAME); 315 return B_OK; 316 317 default: 318 return B_ERROR; 319 } 320 } 321 322 323 net_protocol_module_info sICMPModule = { 324 { 325 "network/protocols/icmp/v1", 326 0, 327 icmp_std_ops 328 }, 329 icmp_init_protocol, 330 icmp_uninit_protocol, 331 icmp_open, 332 icmp_close, 333 icmp_free, 334 icmp_connect, 335 icmp_accept, 336 icmp_control, 337 icmp_bind, 338 icmp_unbind, 339 icmp_listen, 340 icmp_shutdown, 341 icmp_send_data, 342 icmp_send_routed_data, 343 icmp_send_avail, 344 icmp_read_data, 345 icmp_read_avail, 346 icmp_get_domain, 347 icmp_get_mtu, 348 icmp_receive_data, 349 icmp_error, 350 icmp_error_reply, 351 }; 352 353 module_info *modules[] = { 354 (module_info *)&sICMPModule, 355 NULL 356 }; 357