Changeset a35b458 in mainline for uspace/srv/net/inetsrv/pdu.c
- Timestamp:
- 2018-03-02T20:10:49Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f1380b7
- Parents:
- 3061bc1
- git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-02-28 17:38:31)
- git-committer:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-02 20:10:49)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/inetsrv/pdu.c
r3061bc1 ra35b458 107 107 /* Upper bound for fragment offset field */ 108 108 size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l + 1); 109 109 110 110 /* Verify that total size of datagram is within reasonable bounds */ 111 111 if (packet->size > FRAG_OFFS_UNIT * fragoff_limit) 112 112 return ELIMIT; 113 113 114 114 size_t hdr_size = sizeof(ip_header_t); 115 115 if (hdr_size >= mtu) 116 116 return EINVAL; 117 117 118 118 assert(hdr_size % 4 == 0); 119 119 assert(offs % FRAG_OFFS_UNIT == 0); 120 120 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); 121 121 122 122 /* Value for the fragment offset field */ 123 123 uint16_t foff = offs / FRAG_OFFS_UNIT; 124 124 125 125 /* Amount of space in the PDU available for payload */ 126 126 size_t spc_avail = mtu - hdr_size; 127 127 spc_avail -= (spc_avail % FRAG_OFFS_UNIT); 128 128 129 129 /* Amount of data (payload) to transfer */ 130 130 size_t xfer_size = min(packet->size - offs, spc_avail); 131 131 132 132 /* Total PDU size */ 133 133 size_t size = hdr_size + xfer_size; 134 134 135 135 /* Offset of remaining payload */ 136 136 size_t rem_offs = offs + xfer_size; 137 137 138 138 /* Flags */ 139 139 uint16_t flags_foff = … … 141 141 (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) + 142 142 (foff << FF_FRAGOFF_l); 143 143 144 144 void *data = calloc(size, 1); 145 145 if (data == NULL) 146 146 return ENOMEM; 147 147 148 148 /* Encode header fields */ 149 149 ip_header_t *hdr = (ip_header_t *) data; 150 150 151 151 hdr->ver_ihl = 152 152 (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); … … 160 160 hdr->src_addr = host2uint32_t_be(src); 161 161 hdr->dest_addr = host2uint32_t_be(dest); 162 162 163 163 /* Compute checksum */ 164 164 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT, 165 165 (void *) hdr, hdr_size); 166 166 hdr->chksum = host2uint16_t_be(chksum); 167 167 168 168 /* Copy payload */ 169 169 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size); 170 170 171 171 *rdata = data; 172 172 *rsize = size; 173 173 *roffs = rem_offs; 174 174 175 175 return EOK; 176 176 } … … 200 200 if (mtu < 1280) 201 201 return ELIMIT; 202 202 203 203 /* Upper bound for fragment offset field */ 204 204 size_t fragoff_limit = 1 << (OF_FRAGOFF_h - OF_FRAGOFF_l); 205 205 206 206 /* Verify that total size of datagram is within reasonable bounds */ 207 207 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit) 208 208 return ELIMIT; 209 209 210 210 /* Determine whether we need the Fragment extension header */ 211 211 bool fragment; … … 214 214 else 215 215 fragment = true; 216 216 217 217 size_t hdr_size; 218 218 if (fragment) … … 220 220 else 221 221 hdr_size = sizeof(ip6_header_t); 222 222 223 223 if (hdr_size >= mtu) 224 224 return EINVAL; 225 225 226 226 static_assert(sizeof(ip6_header_t) % 8 == 0); 227 227 assert(hdr_size % 8 == 0); 228 228 assert(offs % FRAG_OFFS_UNIT == 0); 229 229 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); 230 230 231 231 /* Value for the fragment offset field */ 232 232 uint16_t foff = offs / FRAG_OFFS_UNIT; 233 233 234 234 /* Amount of space in the PDU available for payload */ 235 235 size_t spc_avail = mtu - hdr_size; 236 236 spc_avail -= (spc_avail % FRAG_OFFS_UNIT); 237 237 238 238 /* Amount of data (payload) to transfer */ 239 239 size_t xfer_size = min(packet->size - offs, spc_avail); 240 240 241 241 /* Total PDU size */ 242 242 size_t size = hdr_size + xfer_size; 243 243 244 244 /* Offset of remaining payload */ 245 245 size_t rem_offs = offs + xfer_size; 246 246 247 247 /* Flags */ 248 248 uint16_t offsmf = 249 249 (rem_offs < packet->size ? BIT_V(uint16_t, OF_FLAG_M) : 0) + 250 250 (foff << OF_FRAGOFF_l); 251 251 252 252 void *data = calloc(size, 1); 253 253 if (data == NULL) 254 254 return ENOMEM; 255 255 256 256 /* Encode header fields */ 257 257 ip6_header_t *hdr6 = (ip6_header_t *) data; 258 258 259 259 hdr6->ver_tc = (6 << (VI_VERSION_l)); 260 260 memset(hdr6->tc_fl, 0, 3); 261 261 hdr6->hop_limit = packet->ttl; 262 262 263 263 host2addr128_t_be(src, hdr6->src_addr); 264 264 host2addr128_t_be(dest, hdr6->dest_addr); 265 265 266 266 /* Optionally encode Fragment extension header fields */ 267 267 if (fragment) { 268 268 assert(offsmf != 0); 269 269 270 270 hdr6->payload_len = host2uint16_t_be(packet->size + 271 271 sizeof(ip6_header_fragment_t)); 272 272 hdr6->next = IP6_NEXT_FRAGMENT; 273 273 274 274 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *) 275 275 (hdr6 + 1); 276 276 277 277 hdr6f->next = packet->proto; 278 278 hdr6f->reserved = 0; … … 281 281 } else { 282 282 assert(offsmf == 0); 283 283 284 284 hdr6->payload_len = host2uint16_t_be(packet->size); 285 285 hdr6->next = packet->proto; 286 286 } 287 287 288 288 /* Copy payload */ 289 289 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size); 290 290 291 291 *rdata = data; 292 292 *rsize = size; 293 293 *roffs = rem_offs; 294 294 295 295 return EOK; 296 296 } … … 312 312 { 313 313 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()"); 314 314 315 315 if (size < sizeof(ip_header_t)) { 316 316 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 317 317 return EINVAL; 318 318 } 319 319 320 320 ip_header_t *hdr = (ip_header_t *) data; 321 321 322 322 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h, 323 323 VI_VERSION_l, hdr->ver_ihl); … … 326 326 return EINVAL; 327 327 } 328 328 329 329 size_t tot_len = uint16_t_be2host(hdr->tot_len); 330 330 if (tot_len < sizeof(ip_header_t)) { … … 332 332 return EINVAL; 333 333 } 334 334 335 335 if (tot_len > size) { 336 336 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu", … … 338 338 return EINVAL; 339 339 } 340 340 341 341 uint16_t ident = uint16_t_be2host(hdr->id); 342 342 uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff); … … 344 344 flags_foff); 345 345 /* XXX Checksum */ 346 346 347 347 inet_addr_set(uint32_t_be2host(hdr->src_addr), &packet->src); 348 348 inet_addr_set(uint32_t_be2host(hdr->dest_addr), &packet->dest); … … 351 351 packet->ttl = hdr->ttl; 352 352 packet->ident = ident; 353 353 354 354 packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0; 355 355 packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0; 356 356 packet->offs = foff * FRAG_OFFS_UNIT; 357 357 358 358 /* XXX IP options */ 359 359 size_t data_offs = sizeof(uint32_t) * 360 360 BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl); 361 361 362 362 packet->size = tot_len - data_offs; 363 363 packet->data = calloc(packet->size, 1); … … 366 366 return ENOMEM; 367 367 } 368 368 369 369 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size); 370 370 packet->link_id = link_id; 371 371 372 372 return EOK; 373 373 } … … 389 389 { 390 390 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode6()"); 391 391 392 392 if (size < sizeof(ip6_header_t)) { 393 393 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 394 394 return EINVAL; 395 395 } 396 396 397 397 ip6_header_t *hdr6 = (ip6_header_t *) data; 398 398 399 399 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h, 400 400 VI_VERSION_l, hdr6->ver_tc); … … 403 403 return EINVAL; 404 404 } 405 405 406 406 size_t payload_len = uint16_t_be2host(hdr6->payload_len); 407 407 if (payload_len + sizeof(ip6_header_t) > size) { … … 410 410 return EINVAL; 411 411 } 412 412 413 413 uint32_t ident; 414 414 uint16_t offsmf; … … 416 416 uint16_t next; 417 417 size_t data_offs = sizeof(ip6_header_t); 418 418 419 419 /* Fragment extension header */ 420 420 if (hdr6->next == IP6_NEXT_FRAGMENT) { 421 421 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *) 422 422 (hdr6 + 1); 423 423 424 424 ident = uint32_t_be2host(hdr6f->id); 425 425 offsmf = uint16_t_be2host(hdr6f->offsmf); … … 435 435 next = hdr6->next; 436 436 } 437 437 438 438 addr128_t src; 439 439 addr128_t dest; 440 440 441 441 addr128_t_be2host(hdr6->src_addr, src); 442 442 inet_addr_set6(src, &packet->src); 443 443 444 444 addr128_t_be2host(hdr6->dest_addr, dest); 445 445 inet_addr_set6(dest, &packet->dest); 446 446 447 447 packet->tos = 0; 448 448 packet->proto = next; 449 449 packet->ttl = hdr6->hop_limit; 450 450 packet->ident = ident; 451 451 452 452 packet->df = 1; 453 453 packet->mf = (offsmf & BIT_V(uint16_t, OF_FLAG_M)) != 0; 454 454 packet->offs = foff * FRAG_OFFS_UNIT; 455 455 456 456 packet->size = payload_len; 457 457 packet->data = calloc(packet->size, 1); … … 460 460 return ENOMEM; 461 461 } 462 462 463 463 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size); 464 464 packet->link_id = link_id; … … 480 480 dgram->tos = 0; 481 481 dgram->size = sizeof(icmpv6_message_t) + sizeof(ndp_message_t); 482 482 483 483 dgram->data = calloc(1, dgram->size); 484 484 if (dgram->data == NULL) 485 485 return ENOMEM; 486 486 487 487 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data; 488 488 489 489 icmpv6->type = ndp->opcode; 490 490 icmpv6->code = 0; 491 491 memset(icmpv6->un.ndp.reserved, 0, 3); 492 492 493 493 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1); 494 494 495 495 if (ndp->opcode == ICMPV6_NEIGHBOUR_SOLICITATION) { 496 496 host2addr128_t_be(ndp->solicited_ip, message->target_address); … … 502 502 icmpv6->un.ndp.flags = NDP_FLAG_OVERRIDE | NDP_FLAG_SOLICITED; 503 503 } 504 504 505 505 message->length = 1; 506 506 addr48(ndp->sender_hw_addr, message->mac); 507 507 508 508 icmpv6_phdr_t phdr; 509 509 510 510 host2addr128_t_be(ndp->sender_proto_addr, phdr.src_addr); 511 511 host2addr128_t_be(ndp->target_proto_addr, phdr.dest_addr); … … 513 513 memset(phdr.zeroes, 0, 3); 514 514 phdr.next = IP_PROTO_ICMPV6; 515 515 516 516 uint16_t cs_phdr = 517 517 inet_checksum_calc(INET_CHECKSUM_INIT, &phdr, 518 518 sizeof(icmpv6_phdr_t)); 519 519 520 520 uint16_t cs_all = inet_checksum_calc(cs_phdr, dgram->data, 521 521 dgram->size); 522 522 523 523 icmpv6->checksum = host2uint16_t_be(cs_all); 524 524 525 525 return EOK; 526 526 } … … 541 541 if (src_ver != ip_v6) 542 542 return EINVAL; 543 543 544 544 if (dgram->size < sizeof(icmpv6_message_t) + sizeof(ndp_message_t)) 545 545 return EINVAL; 546 546 547 547 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data; 548 548 549 549 ndp->opcode = icmpv6->type; 550 550 551 551 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1); 552 552 553 553 addr128_t_be2host(message->target_address, ndp->target_proto_addr); 554 554 addr48(message->mac, ndp->sender_hw_addr); 555 555 556 556 return EOK; 557 557 }
Note:
See TracChangeset
for help on using the changeset viewer.