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_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 sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_ICMP, 301 "network/protocols/icmp/v1", 302 "network/protocols/ipv4/v1", 303 NULL); 304 305 sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_ICMP, 306 "network/protocols/icmp/v1"); 307 return B_OK; 308 } 309 310 case B_MODULE_UNINIT: 311 return B_OK; 312 313 default: 314 return B_ERROR; 315 } 316 } 317 318 319 net_protocol_module_info sICMPModule = { 320 { 321 "network/protocols/icmp/v1", 322 0, 323 icmp_std_ops 324 }, 325 icmp_init_protocol, 326 icmp_uninit_protocol, 327 icmp_open, 328 icmp_close, 329 icmp_free, 330 icmp_connect, 331 icmp_accept, 332 icmp_control, 333 icmp_bind, 334 icmp_unbind, 335 icmp_listen, 336 icmp_shutdown, 337 icmp_send_data, 338 icmp_send_routed_data, 339 icmp_send_avail, 340 icmp_read_data, 341 icmp_read_avail, 342 icmp_get_domain, 343 icmp_get_mtu, 344 icmp_receive_data, 345 icmp_error, 346 icmp_error_reply, 347 }; 348 349 module_dependency module_dependencies[] = { 350 {NET_STACK_MODULE_NAME, (module_info **)&sStackModule}, 351 {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 352 {} 353 }; 354 355 module_info *modules[] = { 356 (module_info *)&sICMPModule, 357 NULL 358 }; 359