1 /* 2 * Copyright 2006-2007, 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 else 257 domain = sStackModule->get_domain(buffer->source->sa_family); 258 if (domain == NULL || domain->module == NULL) 259 break; 260 261 net_buffer *reply = gBufferModule->duplicate(buffer); 262 if (reply == NULL) 263 return B_NO_MEMORY; 264 265 gBufferModule->swap_addresses(reply); 266 267 // There already is an ICMP header, and we'll reuse it 268 NetBufferHeaderReader<icmp_header> header(reply); 269 270 header->type = ICMP_TYPE_ECHO_REPLY; 271 header->code = 0; 272 header->checksum = 0; 273 274 header.Sync(); 275 276 *ICMPChecksumField(reply) = gBufferModule->checksum(reply, 0, 277 reply->size, true); 278 279 status_t status = domain->module->send_data(NULL, reply); 280 if (status < B_OK) { 281 gBufferModule->free(reply); 282 return status; 283 } 284 } 285 } 286 287 gBufferModule->free(buffer); 288 return B_OK; 289 } 290 291 292 status_t 293 icmp_error(uint32 code, net_buffer *data) 294 { 295 return B_ERROR; 296 } 297 298 299 status_t 300 icmp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, 301 void *errorData) 302 { 303 return B_ERROR; 304 } 305 306 307 // #pragma mark - 308 309 310 static status_t 311 icmp_std_ops(int32 op, ...) 312 { 313 switch (op) { 314 case B_MODULE_INIT: 315 { 316 sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_ICMP, 317 "network/protocols/icmp/v1", 318 "network/protocols/ipv4/v1", 319 NULL); 320 321 sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_ICMP, 322 "network/protocols/icmp/v1"); 323 return B_OK; 324 } 325 326 case B_MODULE_UNINIT: 327 return B_OK; 328 329 default: 330 return B_ERROR; 331 } 332 } 333 334 335 net_protocol_module_info sICMPModule = { 336 { 337 "network/protocols/icmp/v1", 338 0, 339 icmp_std_ops 340 }, 341 icmp_init_protocol, 342 icmp_uninit_protocol, 343 icmp_open, 344 icmp_close, 345 icmp_free, 346 icmp_connect, 347 icmp_accept, 348 icmp_control, 349 icmp_getsockopt, 350 icmp_setsockopt, 351 icmp_bind, 352 icmp_unbind, 353 icmp_listen, 354 icmp_shutdown, 355 icmp_send_data, 356 icmp_send_routed_data, 357 icmp_send_avail, 358 icmp_read_data, 359 icmp_read_avail, 360 icmp_get_domain, 361 icmp_get_mtu, 362 icmp_receive_data, 363 NULL, 364 icmp_error, 365 icmp_error_reply, 366 }; 367 368 module_dependency module_dependencies[] = { 369 {NET_STACK_MODULE_NAME, (module_info **)&sStackModule}, 370 {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 371 {} 372 }; 373 374 module_info *modules[] = { 375 (module_info *)&sICMPModule, 376 NULL 377 }; 378