Changes in uspace/srv/net/inetsrv/pdu.c [44c9ef4:1d24ad3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/inetsrv/pdu.c
r44c9ef4 r1d24ad3 49 49 #include "pdu.h" 50 50 51 static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock); 52 static uint16_t ip_ident = 0; 53 51 54 /** One's complement addition. 52 55 * … … 85 88 } 86 89 87 /** Encode I Pv4PDU.90 /** Encode Internet PDU. 88 91 * 89 92 * Encode internet packet into PDU (serialized form). Will encode a … … 93 96 * be set in the header, otherwise the offset will equal @a packet->size. 94 97 * 95 * @param packet Packet to encode 96 * @param src Source address 97 * @param dest Destination address 98 * @param offs Offset into packet payload (in bytes) 99 * @param mtu MTU (Maximum Transmission Unit) in bytes 100 * @param rdata Place to store pointer to allocated data buffer 101 * @param rsize Place to store size of allocated data buffer 102 * @param roffs Place to store offset of remaning data 103 * 104 */ 105 int inet_pdu_encode(inet_packet_t *packet, addr32_t src, addr32_t dest, 106 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs) 107 { 98 * @param packet Packet to encode 99 * @param offs Offset into packet payload (in bytes) 100 * @param mtu MTU (Maximum Transmission Unit) in bytes 101 * @param rdata Place to store pointer to allocated data buffer 102 * @param rsize Place to store size of allocated data buffer 103 * @param roffs Place to store offset of remaning data 104 */ 105 int inet_pdu_encode(inet_packet_t *packet, size_t offs, size_t mtu, 106 void **rdata, size_t *rsize, size_t *roffs) 107 { 108 addr32_t src_v4; 109 addr128_t src_v6; 110 uint16_t src_af = inet_addr_get(&packet->src, &src_v4, &src_v6); 111 112 addr32_t dest_v4; 113 addr128_t dest_v6; 114 uint16_t dest_af = inet_addr_get(&packet->dest, &dest_v4, &dest_v6); 115 116 if (src_af != dest_af) 117 return EINVAL; 118 108 119 /* Upper bound for fragment offset field */ 109 120 size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l); … … 113 124 return ELIMIT; 114 125 115 size_t hdr_size = sizeof(ip_header_t); 116 if (hdr_size >= mtu) 117 return EINVAL; 118 119 assert(hdr_size % 4 == 0); 126 size_t hdr_size; 127 128 switch (src_af) { 129 case AF_INET: 130 hdr_size = sizeof(ip_header_t); 131 break; 132 case AF_INET6: 133 hdr_size = sizeof(ip6_header_t); 134 break; 135 default: 136 assert(false); 137 } 138 139 size_t data_offs = ROUND_UP(hdr_size, 4); 140 120 141 assert(offs % FRAG_OFFS_UNIT == 0); 121 142 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); … … 123 144 /* Value for the fragment offset field */ 124 145 uint16_t foff = offs / FRAG_OFFS_UNIT; 146 147 if (hdr_size >= mtu) 148 return EINVAL; 125 149 126 150 /* Amount of space in the PDU available for payload */ … … 147 171 return ENOMEM; 148 172 173 /* Allocate identifier */ 174 fibril_mutex_lock(&ip_ident_lock); 175 uint16_t ident = ++ip_ident; 176 fibril_mutex_unlock(&ip_ident_lock); 177 149 178 /* Encode header fields */ 150 ip_header_t *hdr = (ip_header_t *) data; 151 152 hdr->ver_ihl = 153 (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); 154 hdr->tos = packet->tos; 155 hdr->tot_len = host2uint16_t_be(size); 156 hdr->id = host2uint16_t_be(packet->ident); 157 hdr->flags_foff = host2uint16_t_be(flags_foff); 158 hdr->ttl = packet->ttl; 159 hdr->proto = packet->proto; 160 hdr->chksum = 0; 161 hdr->src_addr = host2uint32_t_be(src); 162 hdr->dest_addr = host2uint32_t_be(dest); 163 164 /* Compute checksum */ 165 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT, 166 (void *) hdr, hdr_size); 167 hdr->chksum = host2uint16_t_be(chksum); 179 ip_header_t *hdr; 180 ip6_header_t *hdr6; 181 182 switch (src_af) { 183 case AF_INET: 184 hdr = (ip_header_t *) data; 185 186 hdr->ver_ihl = 187 (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); 188 hdr->tos = packet->tos; 189 hdr->tot_len = host2uint16_t_be(size); 190 hdr->id = host2uint16_t_be(ident); 191 hdr->flags_foff = host2uint16_t_be(flags_foff); 192 hdr->ttl = packet->ttl; 193 hdr->proto = packet->proto; 194 hdr->chksum = 0; 195 hdr->src_addr = host2uint32_t_be(src_v4); 196 hdr->dest_addr = host2uint32_t_be(dest_v4); 197 198 /* Compute checksum */ 199 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT, 200 (void *) hdr, hdr_size); 201 hdr->chksum = host2uint16_t_be(chksum); 202 203 break; 204 case AF_INET6: 205 // TODO FIXME: fragmentation 206 207 hdr6 = (ip6_header_t *) data; 208 209 hdr6->ver_tc = (6 << (VI_VERSION_l)); 210 memset(hdr6->tc_fl, 0, 3); 211 hdr6->payload_len = host2uint16_t_be(packet->size); 212 hdr6->next = packet->proto; 213 hdr6->hop_limit = packet->ttl; 214 215 host2addr128_t_be(src_v6, hdr6->src_addr); 216 host2addr128_t_be(dest_v6, hdr6->dest_addr); 217 218 break; 219 default: 220 assert(false); 221 } 168 222 169 223 /* Copy payload */ 170 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);224 memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size); 171 225 172 226 *rdata = data; … … 177 231 } 178 232 179 /** Encode IPv6 PDU.180 *181 * Encode internet packet into PDU (serialized form). Will encode a182 * fragment of the payload starting at offset @a offs. The resulting183 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset184 * of remaining payload. If some data is remaining, the MF flag will185 * be set in the header, otherwise the offset will equal @a packet->size.186 *187 * @param packet Packet to encode188 * @param src Source address189 * @param dest Destination address190 * @param offs Offset into packet payload (in bytes)191 * @param mtu MTU (Maximum Transmission Unit) in bytes192 * @param rdata Place to store pointer to allocated data buffer193 * @param rsize Place to store size of allocated data buffer194 * @param roffs Place to store offset of remaning data195 *196 */197 int inet_pdu_encode6(inet_packet_t *packet, addr128_t src, addr128_t dest,198 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)199 {200 /* IPv6 mandates a minimal MTU of 1280 bytes */201 if (mtu < 1280)202 return ELIMIT;203 204 /* Upper bound for fragment offset field */205 size_t fragoff_limit = 1 << (OF_FRAGOFF_h - OF_FRAGOFF_l);206 207 /* Verify that total size of datagram is within reasonable bounds */208 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)209 return ELIMIT;210 211 /* Determine whether we need the Fragment extension header */212 bool fragment;213 if (offs == 0)214 fragment = (packet->size + sizeof(ip6_header_t) > mtu);215 else216 fragment = true;217 218 size_t hdr_size;219 if (fragment)220 hdr_size = sizeof(ip6_header_t) + sizeof(ip6_header_fragment_t);221 else222 hdr_size = sizeof(ip6_header_t);223 224 if (hdr_size >= mtu)225 return EINVAL;226 227 assert(sizeof(ip6_header_t) % 8 == 0);228 assert(hdr_size % 8 == 0);229 assert(offs % FRAG_OFFS_UNIT == 0);230 assert(offs / FRAG_OFFS_UNIT < fragoff_limit);231 232 /* Value for the fragment offset field */233 uint16_t foff = offs / FRAG_OFFS_UNIT;234 235 /* Amount of space in the PDU available for payload */236 size_t spc_avail = mtu - hdr_size;237 spc_avail -= (spc_avail % FRAG_OFFS_UNIT);238 239 /* Amount of data (payload) to transfer */240 size_t xfer_size = min(packet->size - offs, spc_avail);241 242 /* Total PDU size */243 size_t size = hdr_size + xfer_size;244 245 /* Offset of remaining payload */246 size_t rem_offs = offs + xfer_size;247 248 /* Flags */249 uint16_t offsmf =250 (rem_offs < packet->size ? BIT_V(uint16_t, OF_FLAG_M) : 0) +251 (foff << OF_FRAGOFF_l);252 253 void *data = calloc(size, 1);254 if (data == NULL)255 return ENOMEM;256 257 /* Encode header fields */258 ip6_header_t *hdr6 = (ip6_header_t *) data;259 260 hdr6->ver_tc = (6 << (VI_VERSION_l));261 memset(hdr6->tc_fl, 0, 3);262 hdr6->hop_limit = packet->ttl;263 264 host2addr128_t_be(src, hdr6->src_addr);265 host2addr128_t_be(dest, hdr6->dest_addr);266 267 /* Optionally encode Fragment extension header fields */268 if (fragment) {269 assert(offsmf != 0);270 271 hdr6->payload_len = host2uint16_t_be(packet->size +272 sizeof(ip6_header_fragment_t));273 hdr6->next = IP6_NEXT_FRAGMENT;274 275 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)276 (hdr6 + 1);277 278 hdr6f->next = packet->proto;279 hdr6f->reserved = 0;280 hdr6f->offsmf = host2uint16_t_be(offsmf);281 hdr6f->id = host2uint32_t_be(packet->ident);282 } else {283 assert(offsmf == 0);284 285 hdr6->payload_len = host2uint16_t_be(packet->size);286 hdr6->next = packet->proto;287 }288 289 /* Copy payload */290 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);291 292 *rdata = data;293 *rsize = size;294 *roffs = rem_offs;295 296 return EOK;297 }298 299 /** Decode IPv4 datagram300 *301 * @param data Serialized IPv4 datagram302 * @param size Length of serialized IPv4 datagram303 * @param packet IP datagram structure to be filled304 *305 * @return EOK on success306 * @return EINVAL if the datagram is invalid or damaged307 * @return ENOMEM if not enough memory308 *309 */310 233 int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet) 311 234 { … … 334 257 if (tot_len > size) { 335 258 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu", 336 259 tot_len, size); 337 260 return EINVAL; 338 261 } … … 371 294 } 372 295 373 /** Decode IPv6 datagram374 *375 * @param data Serialized IPv6 datagram376 * @param size Length of serialized IPv6 datagram377 * @param packet IP datagram structure to be filled378 *379 * @return EOK on success380 * @return EINVAL if the datagram is invalid or damaged381 * @return ENOMEM if not enough memory382 *383 */384 296 int inet_pdu_decode6(void *data, size_t size, inet_packet_t *packet) 385 297 { 386 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode6()"); 387 388 if (size < sizeof(ip6_header_t)) { 389 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 390 return EINVAL; 391 } 392 393 ip6_header_t *hdr6 = (ip6_header_t *) data; 394 395 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h, 396 VI_VERSION_l, hdr6->ver_tc); 397 if (version != 6) { 398 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 6", version); 399 return EINVAL; 400 } 401 402 size_t payload_len = uint16_t_be2host(hdr6->payload_len); 403 if (payload_len + sizeof(ip6_header_t) > size) { 404 log_msg(LOG_DEFAULT, LVL_DEBUG, "Payload Length = %zu > PDU size = %zu", 405 payload_len + sizeof(ip6_header_t), size); 406 return EINVAL; 407 } 408 409 uint32_t ident; 410 uint16_t offsmf; 411 uint16_t foff; 412 uint16_t next; 413 size_t data_offs = sizeof(ip6_header_t); 414 415 /* Fragment extension header */ 416 if (hdr6->next == IP6_NEXT_FRAGMENT) { 417 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *) 418 (hdr6 + 1); 419 420 ident = uint32_t_be2host(hdr6f->id); 421 offsmf = uint16_t_be2host(hdr6f->offsmf); 422 foff = BIT_RANGE_EXTRACT(uint16_t, OF_FRAGOFF_h, OF_FRAGOFF_l, 423 offsmf); 424 next = hdr6f->next; 425 data_offs += sizeof(ip6_header_fragment_t); 426 payload_len -= sizeof(ip6_header_fragment_t); 427 } else { 428 ident = 0; 429 offsmf = 0; 430 foff = 0; 431 next = hdr6->next; 432 } 433 434 addr128_t src; 435 addr128_t dest; 436 437 addr128_t_be2host(hdr6->src_addr, src); 438 inet_addr_set6(src, &packet->src); 439 440 addr128_t_be2host(hdr6->dest_addr, dest); 441 inet_addr_set6(dest, &packet->dest); 442 443 packet->tos = 0; 444 packet->proto = next; 445 packet->ttl = hdr6->hop_limit; 446 packet->ident = ident; 447 448 packet->df = 1; 449 packet->mf = (offsmf & BIT_V(uint16_t, OF_FLAG_M)) != 0; 450 packet->offs = foff * FRAG_OFFS_UNIT; 451 452 packet->size = payload_len; 453 packet->data = calloc(packet->size, 1); 454 if (packet->data == NULL) { 455 log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory."); 456 return ENOMEM; 457 } 458 459 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size); 460 461 return EOK; 462 } 463 464 /** Encode NDP packet 465 * 466 * @param ndp NDP packet structure to be serialized 467 * @param dgram IPv6 datagram structure to be filled 468 * 469 * @return EOK on success 470 * 471 */ 472 int ndp_pdu_encode(ndp_packet_t *ndp, inet_dgram_t *dgram) 473 { 474 inet_addr_set6(ndp->sender_proto_addr, &dgram->src); 475 inet_addr_set6(ndp->target_proto_addr, &dgram->dest); 476 dgram->tos = 0; 477 dgram->size = sizeof(icmpv6_message_t) + sizeof(ndp_message_t); 478 479 dgram->data = calloc(1, dgram->size); 480 if (dgram->data == NULL) 481 return ENOMEM; 482 483 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data; 484 485 icmpv6->type = ndp->opcode; 486 icmpv6->code = 0; 487 memset(icmpv6->un.ndp.reserved, 0, 3); 488 489 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1); 490 491 if (ndp->opcode == ICMPV6_NEIGHBOUR_SOLICITATION) { 492 host2addr128_t_be(ndp->solicited_ip, message->target_address); 493 message->option = 1; 494 icmpv6->un.ndp.flags = 0; 495 } else { 496 host2addr128_t_be(ndp->sender_proto_addr, message->target_address); 497 message->option = 2; 498 icmpv6->un.ndp.flags = NDP_FLAG_OVERRIDE | NDP_FLAG_SOLICITED; 499 } 500 501 message->length = 1; 502 addr48(ndp->sender_hw_addr, message->mac); 503 504 icmpv6_phdr_t phdr; 505 506 host2addr128_t_be(ndp->sender_proto_addr, phdr.src_addr); 507 host2addr128_t_be(ndp->target_proto_addr, phdr.dest_addr); 508 phdr.length = host2uint32_t_be(dgram->size); 509 memset(phdr.zeroes, 0, 3); 510 phdr.next = IP_PROTO_ICMPV6; 511 512 uint16_t cs_phdr = 513 inet_checksum_calc(INET_CHECKSUM_INIT, &phdr, 514 sizeof(icmpv6_phdr_t)); 515 516 uint16_t cs_all = inet_checksum_calc(cs_phdr, dgram->data, 517 dgram->size); 518 519 icmpv6->checksum = host2uint16_t_be(cs_all); 520 521 return EOK; 522 } 523 524 /** Decode NDP packet 525 * 526 * @param dgram Incoming IPv6 datagram encapsulating NDP packet 527 * @param ndp NDP packet structure to be filled 528 * 529 * @return EOK on success 530 * @return EINVAL if the Datagram is invalid 531 * 532 */ 533 int ndp_pdu_decode(inet_dgram_t *dgram, ndp_packet_t *ndp) 534 { 535 uint16_t src_af = inet_addr_get(&dgram->src, NULL, 536 &ndp->sender_proto_addr); 537 if (src_af != AF_INET6) 538 return EINVAL; 539 540 if (dgram->size < sizeof(icmpv6_message_t) + sizeof(ndp_message_t)) 541 return EINVAL; 542 543 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data; 544 545 ndp->opcode = icmpv6->type; 546 547 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1); 548 549 addr128_t_be2host(message->target_address, ndp->target_proto_addr); 550 addr48(message->mac, ndp->sender_hw_addr); 551 552 return EOK; 298 // FIXME TODO 299 return ENOTSUP; 553 300 } 554 301
Note:
See TracChangeset
for help on using the changeset viewer.