Changes in uspace/srv/net/inetsrv/pdu.c [12df1f1:a1a101d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/inetsrv/pdu.c
r12df1f1 ra1a101d 44 44 #include <mem.h> 45 45 #include <stdlib.h> 46 #include <net/socket_codes.h> 46 47 47 #include "inetsrv.h" 48 48 #include "inet_std.h" … … 88 88 } 89 89 90 /** Encode I Pv4PDU.90 /** Encode Internet 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 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 { 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 111 122 /* Upper bound for fragment offset field */ 112 size_tfragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);113 123 fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l); 124 114 125 /* Verify that total size of datagram is within reasonable bounds */ 115 126 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit) 116 127 return ELIMIT; 117 118 size_t hdr_size = sizeof(ip_header_t); 119 120 size_t data_offs = ROUND_UP(hdr_size, 4); 121 128 129 hdr_size = sizeof(ip_header_t); 130 data_offs = ROUND_UP(hdr_size, 4); 131 122 132 assert(offs % FRAG_OFFS_UNIT == 0); 123 133 assert(offs / FRAG_OFFS_UNIT < fragoff_limit); 124 134 125 135 /* Value for the fragment offset field */ 126 uint16_tfoff = offs / FRAG_OFFS_UNIT;127 136 foff = offs / FRAG_OFFS_UNIT; 137 128 138 if (hdr_size >= mtu) 129 139 return EINVAL; 130 140 131 141 /* Amount of space in the PDU available for payload */ 132 s ize_t spc_avail = mtu - hdr_size;142 spc_avail = mtu - hdr_size; 133 143 spc_avail -= (spc_avail % FRAG_OFFS_UNIT); 134 144 135 145 /* Amount of data (payload) to transfer */ 136 size_txfer_size = min(packet->size - offs, spc_avail);137 146 xfer_size = min(packet->size - offs, spc_avail); 147 138 148 /* Total PDU size */ 139 size _t size= hdr_size + xfer_size;140 149 size = hdr_size + xfer_size; 150 141 151 /* Offset of remaining payload */ 142 size_trem_offs = offs + xfer_size;143 152 rem_offs = offs + xfer_size; 153 144 154 /* Flags */ 145 uint16_tflags_foff =155 flags_foff = 146 156 (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) + 147 157 (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) + 148 158 (foff << FF_FRAGOFF_l); 149 150 void *data = calloc(size, 1);159 160 data = calloc(size, 1); 151 161 if (data == NULL) 152 162 return ENOMEM; 153 163 154 164 /* Allocate identifier */ 155 165 fibril_mutex_lock(&ip_ident_lock); 156 uint16_tident = ++ip_ident;166 ident = ++ip_ident; 157 167 fibril_mutex_unlock(&ip_ident_lock); 158 168 159 169 /* Encode header fields */ 160 ip_header_t *hdr = (ip_header_t *) data; 161 162 hdr->ver_ihl = 163 (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)); 164 172 hdr->tos = packet->tos; 165 173 hdr->tot_len = host2uint16_t_be(size); … … 169 177 hdr->proto = packet->proto; 170 178 hdr->chksum = 0; 171 hdr->src_addr = host2uint32_t_be( src);172 hdr->dest_addr = host2uint32_t_be( dest);173 179 hdr->src_addr = host2uint32_t_be(packet->src.ipv4); 180 hdr->dest_addr = host2uint32_t_be(packet->dest.ipv4); 181 174 182 /* Compute checksum */ 175 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT, 176 (void *) hdr, hdr_size); 183 chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size); 177 184 hdr->chksum = host2uint16_t_be(chksum); 178 185 179 186 /* Copy payload */ 180 memcpy((uint8_t *) 181 187 memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size); 188 182 189 *rdata = data; 183 190 *rsize = size; 184 191 *roffs = rem_offs; 185 192 186 193 return EOK; 187 194 } 188 195 189 /** Encode IPv6 PDU.190 *191 * Encode internet packet into PDU (serialized form). Will encode a192 * fragment of the payload starting at offset @a offs. The resulting193 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset194 * of remaining payload. If some data is remaining, the MF flag will195 * be set in the header, otherwise the offset will equal @a packet->size.196 *197 * @param packet Packet to encode198 * @param src Source address199 * @param dest Destination address200 * @param offs Offset into packet payload (in bytes)201 * @param mtu MTU (Maximum Transmission Unit) in bytes202 * @param rdata Place to store pointer to allocated data buffer203 * @param rsize Place to store size of allocated data buffer204 * @param roffs Place to store offset of remaning data205 *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 0225 // FIXME TODO fragmentation226 227 /* Value for the fragment offset field */228 uint16_t foff = offs / FRAG_OFFS_UNIT;229 #endif230 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 0248 // FIXME TODO fragmentation249 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 #endif256 257 void *data = calloc(size, 1);258 if (data == NULL)259 return ENOMEM;260 261 #if 0262 // FIXME TODO fragmentation263 264 /* Allocate identifier */265 fibril_mutex_lock(&ip_ident_lock);266 uint16_t ident = ++ip_ident;267 fibril_mutex_unlock(&ip_ident_lock);268 #endif269 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 292 196 int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet) 293 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 294 206 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()"); 295 207 296 208 if (size < sizeof(ip_header_t)) { 297 209 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size); 298 210 return EINVAL; 299 211 } 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);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); 305 217 if (version != 4) { 306 218 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version); 307 219 return EINVAL; 308 220 } 309 310 size_ttot_len = uint16_t_be2host(hdr->tot_len);221 222 tot_len = uint16_t_be2host(hdr->tot_len); 311 223 if (tot_len < sizeof(ip_header_t)) { 312 224 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len); 313 225 return EINVAL; 314 226 } 315 227 316 228 if (tot_len > size) { 317 229 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu", 318 319 return EINVAL; 320 } 321 322 uint16_tident = uint16_t_be2host(hdr->id);323 uint16_tflags_foff = uint16_t_be2host(hdr->flags_foff);324 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, 325 237 flags_foff); 326 238 /* XXX Checksum */ 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);239 240 packet->src.ipv4 = uint32_t_be2host(hdr->src_addr); 241 packet->dest.ipv4 = uint32_t_be2host(hdr->dest_addr); 330 242 packet->tos = hdr->tos; 331 243 packet->proto = hdr->proto; 332 244 packet->ttl = hdr->ttl; 333 245 packet->ident = ident; 334 246 335 247 packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0; 336 248 packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0; 337 249 packet->offs = foff * FRAG_OFFS_UNIT; 338 250 339 251 /* XXX IP options */ 340 size_t data_offs = sizeof(uint32_t) *341 BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h,VI_IHL_l, hdr->ver_ihl);342 252 data_offs = sizeof(uint32_t) * BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, 253 VI_IHL_l, hdr->ver_ihl); 254 343 255 packet->size = tot_len - data_offs; 344 256 packet->data = calloc(packet->size, 1); … … 347 259 return ENOMEM; 348 260 } 349 350 memcpy(packet->data, (uint8_t *) 351 261 262 memcpy(packet->data, (uint8_t *)data + data_offs, packet->size); 263 352 264 return EOK; 353 265 } 354 266 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 0381 // FIXME TODO fragmentation382 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 #endif388 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 0405 // FIXME TODO fragmentation406 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 #endif416 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 508 267 /** @} 509 268 */
Note:
See TracChangeset
for help on using the changeset viewer.