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