Changes in uspace/srv/net/inetsrv/pdu.c [a1a101d:12df1f1] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/inetsrv/pdu.c
ra1a101d r12df1f1 44 44 #include <mem.h> 45 45 #include <stdlib.h> 46 46 #include <net/socket_codes.h> 47 47 #include "inetsrv.h" 48 48 #include "inet_std.h" … … 88 88 } 89 89 90 /** Encode I nternetPDU.90 /** Encode IPv4 PDU. 91 91 * 92 92 * Encode internet packet into PDU (serialized form). Will encode a … … 96 96 * be set in the header, otherwise the offset will equal @a packet->size. 97 97 * 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 98 * @param packet Packet to encode 99 * @param src Source address 100 * @param dest Destination address 101 * @param offs Offset into packet payload (in bytes) 102 * @param mtu MTU (Maximum Transmission Unit) in bytes 103 * @param rdata Place to store pointer to allocated data buffer 104 * @param rsize Place to store size of allocated data buffer 105 * @param roffs Place to store offset of remaning data 106 * 107 */ 108 int inet_pdu_encode(inet_packet_t *packet, addr32_t src, addr32_t dest, 109 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs) 110 { 122 111 /* Upper bound for fragment offset field */ 123 fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);124 112 size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l); 113 125 114 /* Verify that total size of datagram is within reasonable bounds */ 126 115 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit) 127 116 return ELIMIT; 128 129 hdr_size = sizeof(ip_header_t); 130 data_offs = ROUND_UP(hdr_size, 4); 131 117 118 size_t hdr_size = sizeof(ip_header_t); 119 120 size_t data_offs = ROUND_UP(hdr_size, 4); 121 132 122 assert(offs % FRAG_OFFS_UNIT == 0); 133 123 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); 134 124 135 125 /* Value for the fragment offset field */ 136 foff = offs / FRAG_OFFS_UNIT;137 126 uint16_t foff = offs / FRAG_OFFS_UNIT; 127 138 128 if (hdr_size >= mtu) 139 129 return EINVAL; 140 130 141 131 /* Amount of space in the PDU available for payload */ 142 s pc_avail = mtu - hdr_size;132 size_t spc_avail = mtu - hdr_size; 143 133 spc_avail -= (spc_avail % FRAG_OFFS_UNIT); 144 134 145 135 /* Amount of data (payload) to transfer */ 146 xfer_size = min(packet->size - offs, spc_avail);147 136 size_t xfer_size = min(packet->size - offs, spc_avail); 137 148 138 /* Total PDU size */ 149 size = hdr_size + xfer_size;150 139 size_t size = hdr_size + xfer_size; 140 151 141 /* Offset of remaining payload */ 152 rem_offs = offs + xfer_size;153 142 size_t rem_offs = offs + xfer_size; 143 154 144 /* Flags */ 155 flags_foff =145 uint16_t flags_foff = 156 146 (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) + 157 147 (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) + 158 148 (foff << FF_FRAGOFF_l); 159 160 data = calloc(size, 1);149 150 void *data = calloc(size, 1); 161 151 if (data == NULL) 162 152 return ENOMEM; 163 153 164 154 /* Allocate identifier */ 165 155 fibril_mutex_lock(&ip_ident_lock); 166 ident = ++ip_ident;156 uint16_t ident = ++ip_ident; 167 157 fibril_mutex_unlock(&ip_ident_lock); 168 158 169 159 /* Encode header fields */ 170 hdr = (ip_header_t *)data; 171 hdr->ver_ihl = (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); 160 ip_header_t *hdr = (ip_header_t *) data; 161 162 hdr->ver_ihl = 163 (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t)); 172 164 hdr->tos = packet->tos; 173 165 hdr->tot_len = host2uint16_t_be(size); … … 177 169 hdr->proto = packet->proto; 178 170 hdr->chksum = 0; 179 hdr->src_addr = host2uint32_t_be( packet->src.ipv4);180 hdr->dest_addr = host2uint32_t_be( packet->dest.ipv4);181 171 hdr->src_addr = host2uint32_t_be(src); 172 hdr->dest_addr = host2uint32_t_be(dest); 173 182 174 /* Compute checksum */ 183 chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size); 175 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT, 176 (void *) hdr, hdr_size); 184 177 hdr->chksum = host2uint16_t_be(chksum); 185 178 186 179 /* Copy payload */ 187 memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);188 180 memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size); 181 189 182 *rdata = data; 190 183 *rsize = size; 191 184 *roffs = rem_offs; 192 185 193 186 return EOK; 194 187 } 195 188 189 /** Encode IPv6 PDU. 190 * 191 * Encode internet packet into PDU (serialized form). Will encode a 192 * fragment of the payload starting at offset @a offs. The resulting 193 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset 194 * of remaining payload. If some data is remaining, the MF flag will 195 * be set in the header, otherwise the offset will equal @a packet->size. 196 * 197 * @param packet Packet to encode 198 * @param src Source address 199 * @param dest Destination address 200 * @param offs Offset into packet payload (in bytes) 201 * @param mtu MTU (Maximum Transmission Unit) in bytes 202 * @param rdata Place to store pointer to allocated data buffer 203 * @param rsize Place to store size of allocated data buffer 204 * @param roffs Place to store offset of remaning data 205 * 206 */ 207 int inet_pdu_encode6(inet_packet_t *packet, addr128_t src, addr128_t dest, 208 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs) 209 { 210 /* Upper bound for fragment offset field */ 211 size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l); 212 213 /* Verify that total size of datagram is within reasonable bounds */ 214 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit) 215 return ELIMIT; 216 217 size_t hdr_size = sizeof(ip6_header_t); 218 219 size_t data_offs = ROUND_UP(hdr_size, 4); 220 221 assert(offs % FRAG_OFFS_UNIT == 0); 222 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); 223 224 #if 0 225 // FIXME TODO fragmentation 226 227 /* Value for the fragment offset field */ 228 uint16_t foff = offs / FRAG_OFFS_UNIT; 229 #endif 230 231 if (hdr_size >= mtu) 232 return EINVAL; 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 #if 0 248 // FIXME TODO fragmentation 249 250 /* Flags */ 251 uint16_t flags_foff = 252 (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) + 253 (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) + 254 (foff << FF_FRAGOFF_l); 255 #endif 256 257 void *data = calloc(size, 1); 258 if (data == NULL) 259 return ENOMEM; 260 261 #if 0 262 // FIXME TODO fragmentation 263 264 /* Allocate identifier */ 265 fibril_mutex_lock(&ip_ident_lock); 266 uint16_t ident = ++ip_ident; 267 fibril_mutex_unlock(&ip_ident_lock); 268 #endif 269 270 /* Encode header fields */ 271 ip6_header_t *hdr6 = (ip6_header_t *) data; 272 273 hdr6->ver_tc = (6 << (VI_VERSION_l)); 274 memset(hdr6->tc_fl, 0, 3); 275 hdr6->payload_len = host2uint16_t_be(packet->size); 276 hdr6->next = packet->proto; 277 hdr6->hop_limit = packet->ttl; 278 279 host2addr128_t_be(src, hdr6->src_addr); 280 host2addr128_t_be(dest, hdr6->dest_addr); 281 282 /* Copy payload */ 283 memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size); 284 285 *rdata = data; 286 *rsize = size; 287 *roffs = rem_offs; 288 289 return EOK; 290 } 291 196 292 int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet) 197 293 { 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 206 294 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()"); 207 295 208 296 if (size < sizeof(ip_header_t)) { 209 297 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 210 298 return EINVAL; 211 299 } 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);300 301 ip_header_t *hdr = (ip_header_t *) data; 302 303 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h, 304 VI_VERSION_l, hdr->ver_ihl); 217 305 if (version != 4) { 218 306 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version); 219 307 return EINVAL; 220 308 } 221 222 tot_len = uint16_t_be2host(hdr->tot_len);309 310 size_t tot_len = uint16_t_be2host(hdr->tot_len); 223 311 if (tot_len < sizeof(ip_header_t)) { 224 312 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len); 225 313 return EINVAL; 226 314 } 227 315 228 316 if (tot_len > size) { 229 317 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu", 230 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,318 tot_len, size); 319 return EINVAL; 320 } 321 322 uint16_t ident = uint16_t_be2host(hdr->id); 323 uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff); 324 uint16_t foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l, 237 325 flags_foff); 238 326 /* XXX Checksum */ 239 240 packet->src.ipv4 = uint32_t_be2host(hdr->src_addr);241 packet->dest.ipv4 = uint32_t_be2host(hdr->dest_addr);327 328 inet_addr_set(uint32_t_be2host(hdr->src_addr), &packet->src); 329 inet_addr_set(uint32_t_be2host(hdr->dest_addr), &packet->dest); 242 330 packet->tos = hdr->tos; 243 331 packet->proto = hdr->proto; 244 332 packet->ttl = hdr->ttl; 245 333 packet->ident = ident; 246 334 247 335 packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0; 248 336 packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0; 249 337 packet->offs = foff * FRAG_OFFS_UNIT; 250 338 251 339 /* XXX IP options */ 252 data_offs = sizeof(uint32_t) * BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h,253 VI_IHL_l, hdr->ver_ihl);254 340 size_t data_offs = sizeof(uint32_t) * 341 BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl); 342 255 343 packet->size = tot_len - data_offs; 256 344 packet->data = calloc(packet->size, 1); … … 259 347 return ENOMEM; 260 348 } 261 262 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);263 349 350 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size); 351 264 352 return EOK; 265 353 } 266 354 355 int inet_pdu_decode6(void *data, size_t size, inet_packet_t *packet) 356 { 357 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode6()"); 358 359 if (size < sizeof(ip6_header_t)) { 360 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 361 return EINVAL; 362 } 363 364 ip6_header_t *hdr6 = (ip6_header_t *) data; 365 366 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h, 367 VI_VERSION_l, hdr6->ver_tc); 368 if (version != 6) { 369 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 6", version); 370 return EINVAL; 371 } 372 373 size_t payload_len = uint16_t_be2host(hdr6->payload_len); 374 if (payload_len + sizeof(ip6_header_t) > size) { 375 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu", 376 payload_len + sizeof(ip6_header_t), size); 377 return EINVAL; 378 } 379 380 #if 0 381 // FIXME TODO fragmentation 382 383 uint16_t ident = uint16_t_be2host(hdr->id); 384 uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff); 385 uint16_t foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l, 386 flags_foff); 387 #endif 388 389 /* XXX Checksum */ 390 391 addr128_t src; 392 addr128_t dest; 393 394 addr128_t_be2host(hdr6->src_addr, src); 395 inet_addr_set6(src, &packet->src); 396 397 addr128_t_be2host(hdr6->dest_addr, dest); 398 inet_addr_set6(dest, &packet->dest); 399 400 packet->tos = 0; 401 packet->proto = hdr6->next; 402 packet->ttl = hdr6->hop_limit; 403 404 #if 0 405 // FIXME TODO fragmentation 406 407 packet->ident = ident; 408 packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0; 409 packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0; 410 packet->offs = foff * FRAG_OFFS_UNIT; 411 412 /* XXX IP options */ 413 size_t data_offs = sizeof(uint32_t) * 414 BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl); 415 #endif 416 417 packet->ident = 0; 418 packet->df = 0; 419 packet->mf = 0; 420 packet->offs = 0; 421 422 packet->size = payload_len; 423 packet->data = calloc(packet->size, 1); 424 if (packet->data == NULL) { 425 log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory."); 426 return ENOMEM; 427 } 428 429 memcpy(packet->data, (uint8_t *) data + sizeof(ip6_header_t), packet->size); 430 431 return EOK; 432 } 433 434 int ndp_pdu_encode(ndp_packet_t *ndp, inet_dgram_t *dgram) 435 { 436 inet_addr_set6(ndp->sender_proto_addr, &dgram->src); 437 inet_addr_set6(ndp->target_proto_addr, &dgram->dest); 438 dgram->tos = 0; 439 dgram->size = sizeof(icmpv6_message_t) + sizeof(ndp_message_t); 440 441 dgram->data = calloc(1, dgram->size); 442 if (dgram->data == NULL) 443 return ENOMEM; 444 445 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data; 446 447 icmpv6->type = ndp->opcode; 448 icmpv6->code = 0; 449 memset(icmpv6->un.ndp.reserved, 0, 3); 450 451 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1); 452 453 if (ndp->opcode == ICMPV6_NEIGHBOUR_SOLICITATION) { 454 host2addr128_t_be(ndp->solicited_ip, message->target_address); 455 message->option = 1; 456 icmpv6->un.ndp.flags = 0; 457 } else { 458 host2addr128_t_be(ndp->sender_proto_addr, message->target_address); 459 message->option = 2; 460 icmpv6->un.ndp.flags = NDP_FLAG_OVERRIDE | NDP_FLAG_SOLICITED; 461 } 462 463 message->length = 1; 464 addr48(ndp->sender_hw_addr, message->mac); 465 466 icmpv6_phdr_t phdr; 467 468 host2addr128_t_be(ndp->sender_proto_addr, phdr.src_addr); 469 host2addr128_t_be(ndp->target_proto_addr, phdr.dest_addr); 470 phdr.length = host2uint32_t_be(dgram->size); 471 memset(phdr.zeroes, 0, 3); 472 phdr.next = IP_PROTO_ICMPV6; 473 474 uint16_t cs_phdr = 475 inet_checksum_calc(INET_CHECKSUM_INIT, &phdr, 476 sizeof(icmpv6_phdr_t)); 477 478 uint16_t cs_all = inet_checksum_calc(cs_phdr, dgram->data, 479 dgram->size); 480 481 icmpv6->checksum = host2uint16_t_be(cs_all); 482 483 return EOK; 484 } 485 486 int ndp_pdu_decode(inet_dgram_t *dgram, ndp_packet_t *ndp) 487 { 488 uint16_t src_af = inet_addr_get(&dgram->src, NULL, 489 &ndp->sender_proto_addr); 490 if (src_af != AF_INET6) 491 return EINVAL; 492 493 if (dgram->size < sizeof(icmpv6_message_t) + sizeof(ndp_message_t)) 494 return EINVAL; 495 496 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data; 497 498 ndp->opcode = icmpv6->type; 499 500 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1); 501 502 addr128_t_be2host(message->target_address, ndp->target_proto_addr); 503 addr48(message->mac, ndp->sender_hw_addr); 504 505 return EOK; 506 } 507 267 508 /** @} 268 509 */
Note:
See TracChangeset
for help on using the changeset viewer.