Changes in uspace/srv/net/inetsrv/pdu.c [5a324d99:a1a101d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/inetsrv/pdu.c
r5a324d99 ra1a101d 44 44 #include <mem.h> 45 45 #include <stdlib.h> 46 46 47 #include "inetsrv.h" 47 48 #include "inet_std.h" 48 49 #include "pdu.h" 50 51 static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock); 52 static uint16_t ip_ident = 0; 49 53 50 54 /** One's complement addition. … … 84 88 } 85 89 86 /** Encode I Pv4PDU.90 /** Encode Internet PDU. 87 91 * 88 92 * Encode internet packet into PDU (serialized form). Will encode a … … 92 96 * be set in the header, otherwise the offset will equal @a packet->size. 93 97 * 94 * @param packet Packet to encode 95 * @param src Source address 96 * @param dest Destination address 97 * @param offs Offset into packet payload (in bytes) 98 * @param mtu MTU (Maximum Transmission Unit) in bytes 99 * @param rdata Place to store pointer to allocated data buffer 100 * @param rsize Place to store size of allocated data buffer 101 * @param roffs Place to store offset of remaning data 102 * 103 */ 104 int inet_pdu_encode(inet_packet_t *packet, addr32_t src, addr32_t dest, 105 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs) 106 { 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 void *data; 109 size_t size; 110 ip_header_t *hdr; 111 size_t hdr_size; 112 size_t data_offs; 113 uint16_t chksum; 114 uint16_t ident; 115 uint16_t flags_foff; 116 uint16_t foff; 117 size_t fragoff_limit; 118 size_t xfer_size; 119 size_t spc_avail; 120 size_t rem_offs; 121 107 122 /* Upper bound for fragment offset field */ 108 size_tfragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);109 123 fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l); 124 110 125 /* Verify that total size of datagram is within reasonable bounds */ 111 126 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit) 112 127 return ELIMIT; 113 114 size_t hdr_size = sizeof(ip_header_t); 115 if (hdr_size >= mtu) 116 return EINVAL; 117 118 assert(hdr_size % 4 == 0); 128 129 hdr_size = sizeof(ip_header_t); 130 data_offs = ROUND_UP(hdr_size, 4); 131 119 132 assert(offs % FRAG_OFFS_UNIT == 0); 120 133 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); 121 134 122 135 /* Value for the fragment offset field */ 123 uint16_t foff = offs / FRAG_OFFS_UNIT; 124 136 foff = offs / FRAG_OFFS_UNIT; 137 138 if (hdr_size >= mtu) 139 return EINVAL; 140 125 141 /* Amount of space in the PDU available for payload */ 126 s ize_t spc_avail = mtu - hdr_size;142 spc_avail = mtu - hdr_size; 127 143 spc_avail -= (spc_avail % FRAG_OFFS_UNIT); 128 144 129 145 /* Amount of data (payload) to transfer */ 130 size_txfer_size = min(packet->size - offs, spc_avail);131 146 xfer_size = min(packet->size - offs, spc_avail); 147 132 148 /* Total PDU size */ 133 size _t size= hdr_size + xfer_size;134 149 size = hdr_size + xfer_size; 150 135 151 /* Offset of remaining payload */ 136 size_trem_offs = offs + xfer_size;137 152 rem_offs = offs + xfer_size; 153 138 154 /* Flags */ 139 uint16_tflags_foff =155 flags_foff = 140 156 (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) + 141 157 (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) + 142 158 (foff << FF_FRAGOFF_l); 143 144 void *data = calloc(size, 1);159 160 data = calloc(size, 1); 145 161 if (data == NULL) 146 162 return ENOMEM; 147 163 164 /* Allocate identifier */ 165 fibril_mutex_lock(&ip_ident_lock); 166 ident = ++ip_ident; 167 fibril_mutex_unlock(&ip_ident_lock); 168 148 169 /* Encode header fields */ 149 ip_header_t *hdr = (ip_header_t *) data; 150 151 hdr->ver_ihl = 152 (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); 170 hdr = (ip_header_t *)data; 171 hdr->ver_ihl = (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); 153 172 hdr->tos = packet->tos; 154 173 hdr->tot_len = host2uint16_t_be(size); 155 hdr->id = host2uint16_t_be( packet->ident);174 hdr->id = host2uint16_t_be(ident); 156 175 hdr->flags_foff = host2uint16_t_be(flags_foff); 157 176 hdr->ttl = packet->ttl; 158 177 hdr->proto = packet->proto; 159 178 hdr->chksum = 0; 160 hdr->src_addr = host2uint32_t_be( src);161 hdr->dest_addr = host2uint32_t_be( dest);162 179 hdr->src_addr = host2uint32_t_be(packet->src.ipv4); 180 hdr->dest_addr = host2uint32_t_be(packet->dest.ipv4); 181 163 182 /* Compute checksum */ 164 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT, 165 (void *) hdr, hdr_size); 183 chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size); 166 184 hdr->chksum = host2uint16_t_be(chksum); 167 185 168 186 /* Copy payload */ 169 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);170 187 memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size); 188 171 189 *rdata = data; 172 190 *rsize = size; 173 191 *roffs = rem_offs; 174 192 175 193 return EOK; 176 194 } 177 195 178 /** Encode IPv6 PDU.179 *180 * Encode internet packet into PDU (serialized form). Will encode a181 * fragment of the payload starting at offset @a offs. The resulting182 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset183 * of remaining payload. If some data is remaining, the MF flag will184 * be set in the header, otherwise the offset will equal @a packet->size.185 *186 * @param packet Packet to encode187 * @param src Source address188 * @param dest Destination address189 * @param offs Offset into packet payload (in bytes)190 * @param mtu MTU (Maximum Transmission Unit) in bytes191 * @param rdata Place to store pointer to allocated data buffer192 * @param rsize Place to store size of allocated data buffer193 * @param roffs Place to store offset of remaning data194 *195 */196 int inet_pdu_encode6(inet_packet_t *packet, addr128_t src, addr128_t dest,197 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)198 {199 /* IPv6 mandates a minimal MTU of 1280 bytes */200 if (mtu < 1280)201 return ELIMIT;202 203 /* Upper bound for fragment offset field */204 size_t fragoff_limit = 1 << (OF_FRAGOFF_h - OF_FRAGOFF_l);205 206 /* Verify that total size of datagram is within reasonable bounds */207 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)208 return ELIMIT;209 210 /* Determine whether we need the Fragment extension header */211 bool fragment;212 if (offs == 0)213 fragment = (packet->size + sizeof(ip6_header_t) > mtu);214 else215 fragment = true;216 217 size_t hdr_size;218 if (fragment)219 hdr_size = sizeof(ip6_header_t) + sizeof(ip6_header_fragment_t);220 else221 hdr_size = sizeof(ip6_header_t);222 223 if (hdr_size >= mtu)224 return EINVAL;225 226 assert(sizeof(ip6_header_t) % 8 == 0);227 assert(hdr_size % 8 == 0);228 assert(offs % FRAG_OFFS_UNIT == 0);229 assert(offs / FRAG_OFFS_UNIT < fragoff_limit);230 231 /* Value for the fragment offset field */232 uint16_t foff = offs / FRAG_OFFS_UNIT;233 234 /* Amount of space in the PDU available for payload */235 size_t spc_avail = mtu - hdr_size;236 spc_avail -= (spc_avail % FRAG_OFFS_UNIT);237 238 /* Amount of data (payload) to transfer */239 size_t xfer_size = min(packet->size - offs, spc_avail);240 241 /* Total PDU size */242 size_t size = hdr_size + xfer_size;243 244 /* Offset of remaining payload */245 size_t rem_offs = offs + xfer_size;246 247 /* Flags */248 uint16_t offsmf =249 (rem_offs < packet->size ? BIT_V(uint16_t, OF_FLAG_M) : 0) +250 (foff << OF_FRAGOFF_l);251 252 void *data = calloc(size, 1);253 if (data == NULL)254 return ENOMEM;255 256 /* Encode header fields */257 ip6_header_t *hdr6 = (ip6_header_t *) data;258 259 hdr6->ver_tc = (6 << (VI_VERSION_l));260 memset(hdr6->tc_fl, 0, 3);261 hdr6->hop_limit = packet->ttl;262 263 host2addr128_t_be(src, hdr6->src_addr);264 host2addr128_t_be(dest, hdr6->dest_addr);265 266 /* Optionally encode Fragment extension header fields */267 if (fragment) {268 assert(offsmf != 0);269 270 hdr6->payload_len = host2uint16_t_be(packet->size +271 sizeof(ip6_header_fragment_t));272 hdr6->next = IP6_NEXT_FRAGMENT;273 274 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)275 (hdr6 + 1);276 277 hdr6f->next = packet->proto;278 hdr6f->reserved = 0;279 hdr6f->offsmf = host2uint16_t_be(offsmf);280 hdr6f->id = host2uint32_t_be(packet->ident);281 } else {282 assert(offsmf == 0);283 284 hdr6->payload_len = host2uint16_t_be(packet->size);285 hdr6->next = packet->proto;286 }287 288 /* Copy payload */289 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);290 291 *rdata = data;292 *rsize = size;293 *roffs = rem_offs;294 295 return EOK;296 }297 298 /** Decode IPv4 datagram299 *300 * @param data Serialized IPv4 datagram301 * @param size Length of serialized IPv4 datagram302 * @param packet IP datagram structure to be filled303 *304 * @return EOK on success305 * @return EINVAL if the datagram is invalid or damaged306 * @return ENOMEM if not enough memory307 *308 */309 196 int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet) 310 197 { 198 ip_header_t *hdr; 199 size_t tot_len; 200 size_t data_offs; 201 uint8_t version; 202 uint16_t ident; 203 uint16_t flags_foff; 204 uint16_t foff; 205 311 206 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()"); 312 207 313 208 if (size < sizeof(ip_header_t)) { 314 209 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 315 210 return EINVAL; 316 211 } 317 318 ip_header_t *hdr = (ip_header_t *)data;319 320 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h,321 VI_VERSION_l,hdr->ver_ihl);212 213 hdr = (ip_header_t *)data; 214 215 version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h, VI_VERSION_l, 216 hdr->ver_ihl); 322 217 if (version != 4) { 323 218 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version); 324 219 return EINVAL; 325 220 } 326 327 size_ttot_len = uint16_t_be2host(hdr->tot_len);221 222 tot_len = uint16_t_be2host(hdr->tot_len); 328 223 if (tot_len < sizeof(ip_header_t)) { 329 224 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len); 330 225 return EINVAL; 331 226 } 332 227 333 228 if (tot_len > size) { 334 229 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu", 335 336 return EINVAL; 337 } 338 339 uint16_tident = uint16_t_be2host(hdr->id);340 uint16_tflags_foff = uint16_t_be2host(hdr->flags_foff);341 uint16_tfoff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l,230 tot_len, size); 231 return EINVAL; 232 } 233 234 ident = uint16_t_be2host(hdr->id); 235 flags_foff = uint16_t_be2host(hdr->flags_foff); 236 foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l, 342 237 flags_foff); 343 238 /* XXX Checksum */ 344 345 inet_addr_set(uint32_t_be2host(hdr->src_addr), &packet->src);346 inet_addr_set(uint32_t_be2host(hdr->dest_addr), &packet->dest);239 240 packet->src.ipv4 = uint32_t_be2host(hdr->src_addr); 241 packet->dest.ipv4 = uint32_t_be2host(hdr->dest_addr); 347 242 packet->tos = hdr->tos; 348 243 packet->proto = hdr->proto; 349 244 packet->ttl = hdr->ttl; 350 245 packet->ident = ident; 351 246 352 247 packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0; 353 248 packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0; 354 249 packet->offs = foff * FRAG_OFFS_UNIT; 355 250 356 251 /* XXX IP options */ 357 size_t data_offs = sizeof(uint32_t) *358 BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h,VI_IHL_l, hdr->ver_ihl);359 252 data_offs = sizeof(uint32_t) * BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, 253 VI_IHL_l, hdr->ver_ihl); 254 360 255 packet->size = tot_len - data_offs; 361 256 packet->data = calloc(packet->size, 1); … … 364 259 return ENOMEM; 365 260 } 366 367 memcpy(packet->data, (uint8_t *) 368 261 262 memcpy(packet->data, (uint8_t *)data + data_offs, packet->size); 263 369 264 return EOK; 370 265 } 371 266 372 /** Decode IPv6 datagram373 *374 * @param data Serialized IPv6 datagram375 * @param size Length of serialized IPv6 datagram376 * @param packet IP datagram structure to be filled377 *378 * @return EOK on success379 * @return EINVAL if the datagram is invalid or damaged380 * @return ENOMEM if not enough memory381 *382 */383 int inet_pdu_decode6(void *data, size_t size, inet_packet_t *packet)384 {385 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode6()");386 387 if (size < sizeof(ip6_header_t)) {388 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);389 return EINVAL;390 }391 392 ip6_header_t *hdr6 = (ip6_header_t *) data;393 394 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h,395 VI_VERSION_l, hdr6->ver_tc);396 if (version != 6) {397 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 6", version);398 return EINVAL;399 }400 401 size_t payload_len = uint16_t_be2host(hdr6->payload_len);402 if (payload_len + sizeof(ip6_header_t) > size) {403 log_msg(LOG_DEFAULT, LVL_DEBUG, "Payload Length = %zu > PDU size = %zu",404 payload_len + sizeof(ip6_header_t), size);405 return EINVAL;406 }407 408 uint32_t ident;409 uint16_t offsmf;410 uint16_t foff;411 uint16_t next;412 size_t data_offs = sizeof(ip6_header_t);413 414 /* Fragment extension header */415 if (hdr6->next == IP6_NEXT_FRAGMENT) {416 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)417 (hdr6 + 1);418 419 ident = uint32_t_be2host(hdr6f->id);420 offsmf = uint16_t_be2host(hdr6f->offsmf);421 foff = BIT_RANGE_EXTRACT(uint16_t, OF_FRAGOFF_h, OF_FRAGOFF_l,422 offsmf);423 next = hdr6f->next;424 data_offs += sizeof(ip6_header_fragment_t);425 payload_len -= sizeof(ip6_header_fragment_t);426 } else {427 ident = 0;428 offsmf = 0;429 foff = 0;430 next = hdr6->next;431 }432 433 addr128_t src;434 addr128_t dest;435 436 addr128_t_be2host(hdr6->src_addr, src);437 inet_addr_set6(src, &packet->src);438 439 addr128_t_be2host(hdr6->dest_addr, dest);440 inet_addr_set6(dest, &packet->dest);441 442 packet->tos = 0;443 packet->proto = next;444 packet->ttl = hdr6->hop_limit;445 packet->ident = ident;446 447 packet->df = 1;448 packet->mf = (offsmf & BIT_V(uint16_t, OF_FLAG_M)) != 0;449 packet->offs = foff * FRAG_OFFS_UNIT;450 451 packet->size = payload_len;452 packet->data = calloc(packet->size, 1);453 if (packet->data == NULL) {454 log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory.");455 return ENOMEM;456 }457 458 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);459 460 return EOK;461 }462 463 /** Encode NDP packet464 *465 * @param ndp NDP packet structure to be serialized466 * @param dgram IPv6 datagram structure to be filled467 *468 * @return EOK on success469 *470 */471 int ndp_pdu_encode(ndp_packet_t *ndp, inet_dgram_t *dgram)472 {473 inet_addr_set6(ndp->sender_proto_addr, &dgram->src);474 inet_addr_set6(ndp->target_proto_addr, &dgram->dest);475 dgram->tos = 0;476 dgram->size = sizeof(icmpv6_message_t) + sizeof(ndp_message_t);477 478 dgram->data = calloc(1, dgram->size);479 if (dgram->data == NULL)480 return ENOMEM;481 482 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data;483 484 icmpv6->type = ndp->opcode;485 icmpv6->code = 0;486 memset(icmpv6->un.ndp.reserved, 0, 3);487 488 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1);489 490 if (ndp->opcode == ICMPV6_NEIGHBOUR_SOLICITATION) {491 host2addr128_t_be(ndp->solicited_ip, message->target_address);492 message->option = 1;493 icmpv6->un.ndp.flags = 0;494 } else {495 host2addr128_t_be(ndp->sender_proto_addr, message->target_address);496 message->option = 2;497 icmpv6->un.ndp.flags = NDP_FLAG_OVERRIDE | NDP_FLAG_SOLICITED;498 }499 500 message->length = 1;501 addr48(ndp->sender_hw_addr, message->mac);502 503 icmpv6_phdr_t phdr;504 505 host2addr128_t_be(ndp->sender_proto_addr, phdr.src_addr);506 host2addr128_t_be(ndp->target_proto_addr, phdr.dest_addr);507 phdr.length = host2uint32_t_be(dgram->size);508 memset(phdr.zeroes, 0, 3);509 phdr.next = IP_PROTO_ICMPV6;510 511 uint16_t cs_phdr =512 inet_checksum_calc(INET_CHECKSUM_INIT, &phdr,513 sizeof(icmpv6_phdr_t));514 515 uint16_t cs_all = inet_checksum_calc(cs_phdr, dgram->data,516 dgram->size);517 518 icmpv6->checksum = host2uint16_t_be(cs_all);519 520 return EOK;521 }522 523 /** Decode NDP packet524 *525 * @param dgram Incoming IPv6 datagram encapsulating NDP packet526 * @param ndp NDP packet structure to be filled527 *528 * @return EOK on success529 * @return EINVAL if the Datagram is invalid530 *531 */532 int ndp_pdu_decode(inet_dgram_t *dgram, ndp_packet_t *ndp)533 {534 ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL,535 &ndp->sender_proto_addr);536 if (src_ver != ip_v6)537 return EINVAL;538 539 if (dgram->size < sizeof(icmpv6_message_t) + sizeof(ndp_message_t))540 return EINVAL;541 542 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data;543 544 ndp->opcode = icmpv6->type;545 546 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1);547 548 addr128_t_be2host(message->target_address, ndp->target_proto_addr);549 addr48(message->mac, ndp->sender_hw_addr);550 551 return EOK;552 }553 554 267 /** @} 555 268 */
Note:
See TracChangeset
for help on using the changeset viewer.