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 static net_stack_module_info *sStackModule; 66 struct net_buffer_module_info *gBufferModule; 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_bind(net_protocol *protocol, struct sockaddr *address) 134 { 135 return B_ERROR; 136 } 137 138 139 status_t 140 icmp_unbind(net_protocol *protocol, struct sockaddr *address) 141 { 142 return B_ERROR; 143 } 144 145 146 status_t 147 icmp_listen(net_protocol *protocol, int count) 148 { 149 return EOPNOTSUPP; 150 } 151 152 153 status_t 154 icmp_shutdown(net_protocol *protocol, int direction) 155 { 156 return EOPNOTSUPP; 157 } 158 159 160 status_t 161 icmp_send_data(net_protocol *protocol, net_buffer *buffer) 162 { 163 return protocol->next->module->send_data(protocol->next, buffer); 164 } 165 166 167 status_t 168 icmp_send_routed_data(net_protocol *protocol, struct net_route *route, 169 net_buffer *buffer) 170 { 171 return protocol->next->module->send_routed_data(protocol->next, route, buffer); 172 } 173 174 175 ssize_t 176 icmp_send_avail(net_protocol *protocol) 177 { 178 return B_ERROR; 179 } 180 181 182 status_t 183 icmp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 184 net_buffer **_buffer) 185 { 186 return B_ERROR; 187 } 188 189 190 ssize_t 191 icmp_read_avail(net_protocol *protocol) 192 { 193 return B_ERROR; 194 } 195 196 197 struct net_domain * 198 icmp_get_domain(net_protocol *protocol) 199 { 200 return protocol->next->module->get_domain(protocol->next); 201 } 202 203 204 size_t 205 icmp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 206 { 207 return protocol->next->module->get_mtu(protocol->next, address); 208 } 209 210 211 status_t 212 icmp_receive_data(net_buffer *buffer) 213 { 214 TRACE(("ICMP received some data, buffer length %lu\n", buffer->size)); 215 216 NetBufferHeaderReader<icmp_header> bufferHeader(buffer); 217 if (bufferHeader.Status() < B_OK) 218 return bufferHeader.Status(); 219 220 icmp_header &header = bufferHeader.Data(); 221 222 TRACE((" got type %u, code %u, checksum %u\n", header.type, header.code, 223 ntohs(header.checksum))); 224 TRACE((" computed checksum: %ld\n", gBufferModule->checksum(buffer, 0, buffer->size, true))); 225 226 if (gBufferModule->checksum(buffer, 0, buffer->size, true) != 0) 227 return B_BAD_DATA; 228 229 switch (header.type) { 230 case ICMP_TYPE_ECHO_REPLY: 231 break; 232 233 case ICMP_TYPE_ECHO_REQUEST: 234 { 235 net_domain *domain; 236 if (buffer->interface != NULL) 237 domain = buffer->interface->domain; 238 else 239 domain = sStackModule->get_domain(buffer->source.ss_family); 240 if (domain == NULL || domain->module == NULL) 241 break; 242 243 net_buffer *reply = gBufferModule->duplicate(buffer); 244 if (reply == NULL) 245 return B_NO_MEMORY; 246 247 // switch source/destination address 248 memcpy(&reply->source, &buffer->destination, buffer->destination.ss_len); 249 memcpy(&reply->destination, &buffer->source, buffer->source.ss_len); 250 251 // There already is an ICMP header, and we'll reuse it 252 NetBufferHeaderReader<icmp_header> header(reply); 253 254 header->type = ICMP_TYPE_ECHO_REPLY; 255 header->code = 0; 256 header->checksum = 0; 257 258 header.Sync(); 259 260 *ICMPChecksumField(reply) = gBufferModule->checksum(reply, 0, 261 reply->size, true); 262 263 status_t status = domain->module->send_data(NULL, reply); 264 if (status < B_OK) { 265 gBufferModule->free(reply); 266 return status; 267 } 268 } 269 } 270 271 gBufferModule->free(buffer); 272 return B_OK; 273 } 274 275 276 status_t 277 icmp_error(uint32 code, net_buffer *data) 278 { 279 return B_ERROR; 280 } 281 282 283 status_t 284 icmp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, 285 void *errorData) 286 { 287 return B_ERROR; 288 } 289 290 291 // #pragma mark - 292 293 294 static status_t 295 icmp_std_ops(int32 op, ...) 296 { 297 switch (op) { 298 case B_MODULE_INIT: 299 { 300 status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); 301 if (status < B_OK) 302 return status; 303 status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); 304 if (status < B_OK) { 305 put_module(NET_STACK_MODULE_NAME); 306 return status; 307 } 308 309 sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_ICMP, 310 "network/protocols/icmp/v1", 311 "network/protocols/ipv4/v1", 312 NULL); 313 314 sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_ICMP, 315 "network/protocols/icmp/v1"); 316 return B_OK; 317 } 318 319 case B_MODULE_UNINIT: 320 put_module(NET_BUFFER_MODULE_NAME); 321 put_module(NET_STACK_MODULE_NAME); 322 return B_OK; 323 324 default: 325 return B_ERROR; 326 } 327 } 328 329 330 net_protocol_module_info sICMPModule = { 331 { 332 "network/protocols/icmp/v1", 333 0, 334 icmp_std_ops 335 }, 336 icmp_init_protocol, 337 icmp_uninit_protocol, 338 icmp_open, 339 icmp_close, 340 icmp_free, 341 icmp_connect, 342 icmp_accept, 343 icmp_control, 344 icmp_bind, 345 icmp_unbind, 346 icmp_listen, 347 icmp_shutdown, 348 icmp_send_data, 349 icmp_send_routed_data, 350 icmp_send_avail, 351 icmp_read_data, 352 icmp_read_avail, 353 icmp_get_domain, 354 icmp_get_mtu, 355 icmp_receive_data, 356 icmp_error, 357 icmp_error_reply, 358 }; 359 360 module_info *modules[] = { 361 (module_info *)&sICMPModule, 362 NULL 363 }; 364