source: mainline/uspace/srv/net/inetsrv/pdu.c

Last change on this file was b4edc96, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Rename and move addr48_t to eth_addr_t

  • Property mode set to 100644
File size: 15.5 KB
RevLine 
[ceba4bed]1/*
[f05edcb]2 * Copyright (c) 2021 Jiri Svoboda
[ceba4bed]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup inet
30 * @{
31 */
32/**
33 * @file
34 * @brief
35 */
36
[e767dbf]37#include <align.h>
38#include <bitops.h>
39#include <byteorder.h>
[ceba4bed]40#include <errno.h>
[1cc8b42]41#include <fibril_synch.h>
[f05edcb]42#include <inet/eth_addr.h>
[e767dbf]43#include <io/log.h>
[347768d]44#include <macros.h>
[e767dbf]45#include <mem.h>
[ceba4bed]46#include <stdlib.h>
[b4ec1ea]47#include "inetsrv.h"
[e767dbf]48#include "inet_std.h"
[ceba4bed]49#include "pdu.h"
50
[1cc8b42]51/** One's complement addition.
52 *
53 * Result is a + b + carry.
54 */
55static uint16_t inet_ocadd16(uint16_t a, uint16_t b)
56{
57 uint32_t s;
58
59 s = (uint32_t)a + (uint32_t)b;
60 return (s & 0xffff) + (s >> 16);
61}
62
[637a3b4]63uint16_t inet_checksum_calc(uint16_t ivalue, void *data, size_t size)
[1cc8b42]64{
65 uint16_t sum;
66 uint16_t w;
67 size_t words, i;
68 uint8_t *bdata;
69
70 sum = ~ivalue;
71 words = size / 2;
72 bdata = (uint8_t *)data;
73
74 for (i = 0; i < words; i++) {
[3bacee1]75 w = ((uint16_t)bdata[2 * i] << 8) | bdata[2 * i + 1];
[1cc8b42]76 sum = inet_ocadd16(sum, w);
77 }
78
79 if (size % 2 != 0) {
[3bacee1]80 w = ((uint16_t)bdata[2 * words] << 8);
[1cc8b42]81 sum = inet_ocadd16(sum, w);
82 }
83
84 return ~sum;
85}
86
[a17356fd]87/** Encode IPv4 PDU.
[347768d]88 *
89 * Encode internet packet into PDU (serialized form). Will encode a
90 * fragment of the payload starting at offset @a offs. The resulting
91 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset
92 * of remaining payload. If some data is remaining, the MF flag will
93 * be set in the header, otherwise the offset will equal @a packet->size.
94 *
[a17356fd]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 *
[ceba4bed]104 */
[b7fd2a0]105errno_t inet_pdu_encode(inet_packet_t *packet, addr32_t src, addr32_t dest,
[313824a]106 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)
[ceba4bed]107{
[a17356fd]108 /* Upper bound for fragment offset field */
[fc6abbe]109 size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l + 1);
[a35b458]110
[a17356fd]111 /* Verify that total size of datagram is within reasonable bounds */
[fc6abbe]112 if (packet->size > FRAG_OFFS_UNIT * fragoff_limit)
[a17356fd]113 return ELIMIT;
[a35b458]114
[a17356fd]115 size_t hdr_size = sizeof(ip_header_t);
[44c9ef4]116 if (hdr_size >= mtu)
117 return EINVAL;
[a35b458]118
[44c9ef4]119 assert(hdr_size % 4 == 0);
[a17356fd]120 assert(offs % FRAG_OFFS_UNIT == 0);
121 assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
[a35b458]122
[a17356fd]123 /* Value for the fragment offset field */
124 uint16_t foff = offs / FRAG_OFFS_UNIT;
[a35b458]125
[a17356fd]126 /* Amount of space in the PDU available for payload */
127 size_t spc_avail = mtu - hdr_size;
128 spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
[a35b458]129
[a17356fd]130 /* Amount of data (payload) to transfer */
131 size_t xfer_size = min(packet->size - offs, spc_avail);
[a35b458]132
[a17356fd]133 /* Total PDU size */
134 size_t size = hdr_size + xfer_size;
[a35b458]135
[a17356fd]136 /* Offset of remaining payload */
137 size_t rem_offs = offs + xfer_size;
[a35b458]138
[a17356fd]139 /* Flags */
140 uint16_t flags_foff =
141 (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
142 (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
143 (foff << FF_FRAGOFF_l);
[a35b458]144
[a17356fd]145 void *data = calloc(size, 1);
146 if (data == NULL)
147 return ENOMEM;
[a35b458]148
[a17356fd]149 /* Encode header fields */
150 ip_header_t *hdr = (ip_header_t *) data;
[a35b458]151
[a17356fd]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);
[313824a]156 hdr->id = host2uint16_t_be(packet->ident);
[a17356fd]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);
[a35b458]163
[a17356fd]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);
[a35b458]168
[a17356fd]169 /* Copy payload */
[44c9ef4]170 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);
[a35b458]171
[a17356fd]172 *rdata = data;
173 *rsize = size;
174 *roffs = rem_offs;
[a35b458]175
[a17356fd]176 return EOK;
177}
178
179/** Encode IPv6 PDU.
180 *
181 * Encode internet packet into PDU (serialized form). Will encode a
182 * fragment of the payload starting at offset @a offs. The resulting
183 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset
184 * of remaining payload. If some data is remaining, the MF flag will
185 * be set in the header, otherwise the offset will equal @a packet->size.
186 *
187 * @param packet Packet to encode
188 * @param src Source address
189 * @param dest Destination address
190 * @param offs Offset into packet payload (in bytes)
191 * @param mtu MTU (Maximum Transmission Unit) in bytes
192 * @param rdata Place to store pointer to allocated data buffer
193 * @param rsize Place to store size of allocated data buffer
[44c9ef4]194 * @param roffs Place to store offset of remaning data
[a17356fd]195 *
196 */
[b7fd2a0]197errno_t inet_pdu_encode6(inet_packet_t *packet, addr128_t src, addr128_t dest,
[a17356fd]198 size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)
199{
[44c9ef4]200 /* IPv6 mandates a minimal MTU of 1280 bytes */
201 if (mtu < 1280)
202 return ELIMIT;
[a35b458]203
[347768d]204 /* Upper bound for fragment offset field */
[44c9ef4]205 size_t fragoff_limit = 1 << (OF_FRAGOFF_h - OF_FRAGOFF_l);
[a35b458]206
[347768d]207 /* Verify that total size of datagram is within reasonable bounds */
208 if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
209 return ELIMIT;
[a35b458]210
[44c9ef4]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 else
216 fragment = true;
[a35b458]217
[44c9ef4]218 size_t hdr_size;
219 if (fragment)
220 hdr_size = sizeof(ip6_header_t) + sizeof(ip6_header_fragment_t);
221 else
222 hdr_size = sizeof(ip6_header_t);
[a35b458]223
[44c9ef4]224 if (hdr_size >= mtu)
225 return EINVAL;
[a35b458]226
[0a520db]227 static_assert(sizeof(ip6_header_t) % 8 == 0, "");
[44c9ef4]228 assert(hdr_size % 8 == 0);
[347768d]229 assert(offs % FRAG_OFFS_UNIT == 0);
230 assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
[a35b458]231
[347768d]232 /* Value for the fragment offset field */
[a2e3ee6]233 uint16_t foff = offs / FRAG_OFFS_UNIT;
[a35b458]234
[347768d]235 /* Amount of space in the PDU available for payload */
[a2e3ee6]236 size_t spc_avail = mtu - hdr_size;
[7fda2e0]237 spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
[a35b458]238
[347768d]239 /* Amount of data (payload) to transfer */
[a2e3ee6]240 size_t xfer_size = min(packet->size - offs, spc_avail);
[a35b458]241
[347768d]242 /* Total PDU size */
[a2e3ee6]243 size_t size = hdr_size + xfer_size;
[a35b458]244
[347768d]245 /* Offset of remaining payload */
[a2e3ee6]246 size_t rem_offs = offs + xfer_size;
[a35b458]247
[347768d]248 /* Flags */
[44c9ef4]249 uint16_t offsmf =
250 (rem_offs < packet->size ? BIT_V(uint16_t, OF_FLAG_M) : 0) +
251 (foff << OF_FRAGOFF_l);
[a35b458]252
[a2e3ee6]253 void *data = calloc(size, 1);
[ceba4bed]254 if (data == NULL)
255 return ENOMEM;
[a35b458]256
[347768d]257 /* Encode header fields */
[a17356fd]258 ip6_header_t *hdr6 = (ip6_header_t *) data;
[a35b458]259
[a17356fd]260 hdr6->ver_tc = (6 << (VI_VERSION_l));
261 memset(hdr6->tc_fl, 0, 3);
262 hdr6->hop_limit = packet->ttl;
[a35b458]263
[a17356fd]264 host2addr128_t_be(src, hdr6->src_addr);
265 host2addr128_t_be(dest, hdr6->dest_addr);
[a35b458]266
[44c9ef4]267 /* Optionally encode Fragment extension header fields */
268 if (fragment) {
269 assert(offsmf != 0);
[a35b458]270
[44c9ef4]271 hdr6->payload_len = host2uint16_t_be(packet->size +
272 sizeof(ip6_header_fragment_t));
273 hdr6->next = IP6_NEXT_FRAGMENT;
[a35b458]274
[44c9ef4]275 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)
276 (hdr6 + 1);
[a35b458]277
[44c9ef4]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);
[a35b458]284
[44c9ef4]285 hdr6->payload_len = host2uint16_t_be(packet->size);
286 hdr6->next = packet->proto;
287 }
[a35b458]288
[347768d]289 /* Copy payload */
[44c9ef4]290 memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);
[a35b458]291
[ceba4bed]292 *rdata = data;
293 *rsize = size;
[347768d]294 *roffs = rem_offs;
[a35b458]295
[ceba4bed]296 return EOK;
297}
298
[1d94e21]299/** Decode IPv4 datagram
300 *
[8d48c7e]301 * @param data Serialized IPv4 datagram
302 * @param size Length of serialized IPv4 datagram
303 * @param link_id Link on which PDU was received
304 * @param packet IP datagram structure to be filled
[1d94e21]305 *
306 * @return EOK on success
307 * @return EINVAL if the datagram is invalid or damaged
308 * @return ENOMEM if not enough memory
309 *
310 */
[b7fd2a0]311errno_t inet_pdu_decode(void *data, size_t size, service_id_t link_id,
[8d48c7e]312 inet_packet_t *packet)
[e767dbf]313{
[a1a101d]314 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
[a35b458]315
[e767dbf]316 if (size < sizeof(ip_header_t)) {
[a1a101d]317 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
[e767dbf]318 return EINVAL;
319 }
[a35b458]320
[02a09ed]321 ip_header_t *hdr = (ip_header_t *) data;
[a35b458]322
[02a09ed]323 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h,
324 VI_VERSION_l, hdr->ver_ihl);
[e767dbf]325 if (version != 4) {
[a1a101d]326 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
[e767dbf]327 return EINVAL;
328 }
[a35b458]329
[02a09ed]330 size_t tot_len = uint16_t_be2host(hdr->tot_len);
[e767dbf]331 if (tot_len < sizeof(ip_header_t)) {
[a1a101d]332 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
[e767dbf]333 return EINVAL;
334 }
[a35b458]335
[e767dbf]336 if (tot_len > size) {
[a1a101d]337 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
[a17356fd]338 tot_len, size);
[e767dbf]339 return EINVAL;
340 }
[a35b458]341
[02a09ed]342 uint16_t ident = uint16_t_be2host(hdr->id);
343 uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff);
344 uint16_t foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l,
[7f95c904]345 flags_foff);
[e767dbf]346 /* XXX Checksum */
[a35b458]347
[02a09ed]348 inet_addr_set(uint32_t_be2host(hdr->src_addr), &packet->src);
349 inet_addr_set(uint32_t_be2host(hdr->dest_addr), &packet->dest);
[fe4310f]350 packet->tos = hdr->tos;
[2ff150e]351 packet->proto = hdr->proto;
[fe4310f]352 packet->ttl = hdr->ttl;
[7f95c904]353 packet->ident = ident;
[a35b458]354
[7f95c904]355 packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
356 packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
357 packet->offs = foff * FRAG_OFFS_UNIT;
[a35b458]358
[e767dbf]359 /* XXX IP options */
[02a09ed]360 size_t data_offs = sizeof(uint32_t) *
361 BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl);
[a35b458]362
[fe4310f]363 packet->size = tot_len - data_offs;
364 packet->data = calloc(packet->size, 1);
365 if (packet->data == NULL) {
[a1a101d]366 log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory.");
[e767dbf]367 return ENOMEM;
368 }
[a35b458]369
[257feec]370 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
[8d48c7e]371 packet->link_id = link_id;
[a35b458]372
[e767dbf]373 return EOK;
374}
375
[1d94e21]376/** Decode IPv6 datagram
377 *
[8d48c7e]378 * @param data Serialized IPv6 datagram
379 * @param size Length of serialized IPv6 datagram
380 * @param link_id Link on which PDU was received
381 * @param packet IP datagram structure to be filled
[1d94e21]382 *
383 * @return EOK on success
384 * @return EINVAL if the datagram is invalid or damaged
385 * @return ENOMEM if not enough memory
386 *
387 */
[b7fd2a0]388errno_t inet_pdu_decode6(void *data, size_t size, service_id_t link_id,
[8d48c7e]389 inet_packet_t *packet)
[1d24ad3]390{
[a17356fd]391 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode6()");
[a35b458]392
[a17356fd]393 if (size < sizeof(ip6_header_t)) {
394 log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
395 return EINVAL;
396 }
[a35b458]397
[a17356fd]398 ip6_header_t *hdr6 = (ip6_header_t *) data;
[a35b458]399
[a17356fd]400 uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h,
401 VI_VERSION_l, hdr6->ver_tc);
402 if (version != 6) {
403 log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 6", version);
404 return EINVAL;
405 }
[a35b458]406
[a17356fd]407 size_t payload_len = uint16_t_be2host(hdr6->payload_len);
408 if (payload_len + sizeof(ip6_header_t) > size) {
[44c9ef4]409 log_msg(LOG_DEFAULT, LVL_DEBUG, "Payload Length = %zu > PDU size = %zu",
[a17356fd]410 payload_len + sizeof(ip6_header_t), size);
411 return EINVAL;
412 }
[a35b458]413
[44c9ef4]414 uint32_t ident;
415 uint16_t offsmf;
416 uint16_t foff;
417 uint16_t next;
418 size_t data_offs = sizeof(ip6_header_t);
[a35b458]419
[44c9ef4]420 /* Fragment extension header */
421 if (hdr6->next == IP6_NEXT_FRAGMENT) {
422 ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)
423 (hdr6 + 1);
[a35b458]424
[44c9ef4]425 ident = uint32_t_be2host(hdr6f->id);
426 offsmf = uint16_t_be2host(hdr6f->offsmf);
427 foff = BIT_RANGE_EXTRACT(uint16_t, OF_FRAGOFF_h, OF_FRAGOFF_l,
428 offsmf);
429 next = hdr6f->next;
430 data_offs += sizeof(ip6_header_fragment_t);
431 payload_len -= sizeof(ip6_header_fragment_t);
432 } else {
433 ident = 0;
434 offsmf = 0;
435 foff = 0;
436 next = hdr6->next;
437 }
[a35b458]438
[a17356fd]439 addr128_t src;
440 addr128_t dest;
[a35b458]441
[a17356fd]442 addr128_t_be2host(hdr6->src_addr, src);
443 inet_addr_set6(src, &packet->src);
[a35b458]444
[a17356fd]445 addr128_t_be2host(hdr6->dest_addr, dest);
446 inet_addr_set6(dest, &packet->dest);
[a35b458]447
[a17356fd]448 packet->tos = 0;
[44c9ef4]449 packet->proto = next;
[a17356fd]450 packet->ttl = hdr6->hop_limit;
451 packet->ident = ident;
[a35b458]452
[44c9ef4]453 packet->df = 1;
454 packet->mf = (offsmf & BIT_V(uint16_t, OF_FLAG_M)) != 0;
455 packet->offs = foff * FRAG_OFFS_UNIT;
[a35b458]456
[a17356fd]457 packet->size = payload_len;
458 packet->data = calloc(packet->size, 1);
459 if (packet->data == NULL) {
460 log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory.");
461 return ENOMEM;
462 }
[a35b458]463
[44c9ef4]464 memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
[8d48c7e]465 packet->link_id = link_id;
[a17356fd]466 return EOK;
467}
468
[1d94e21]469/** Encode NDP packet
470 *
471 * @param ndp NDP packet structure to be serialized
472 * @param dgram IPv6 datagram structure to be filled
473 *
474 * @return EOK on success
475 *
476 */
[b7fd2a0]477errno_t ndp_pdu_encode(ndp_packet_t *ndp, inet_dgram_t *dgram)
[a17356fd]478{
479 inet_addr_set6(ndp->sender_proto_addr, &dgram->src);
480 inet_addr_set6(ndp->target_proto_addr, &dgram->dest);
481 dgram->tos = 0;
482 dgram->size = sizeof(icmpv6_message_t) + sizeof(ndp_message_t);
[a35b458]483
[a17356fd]484 dgram->data = calloc(1, dgram->size);
485 if (dgram->data == NULL)
486 return ENOMEM;
[a35b458]487
[a17356fd]488 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data;
[a35b458]489
[a17356fd]490 icmpv6->type = ndp->opcode;
491 icmpv6->code = 0;
492 memset(icmpv6->un.ndp.reserved, 0, 3);
[a35b458]493
[a17356fd]494 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1);
[a35b458]495
[a17356fd]496 if (ndp->opcode == ICMPV6_NEIGHBOUR_SOLICITATION) {
497 host2addr128_t_be(ndp->solicited_ip, message->target_address);
498 message->option = 1;
499 icmpv6->un.ndp.flags = 0;
500 } else {
501 host2addr128_t_be(ndp->sender_proto_addr, message->target_address);
502 message->option = 2;
503 icmpv6->un.ndp.flags = NDP_FLAG_OVERRIDE | NDP_FLAG_SOLICITED;
504 }
[a35b458]505
[a17356fd]506 message->length = 1;
[b4edc96]507 eth_addr_encode(&ndp->sender_hw_addr, message->mac);
[a35b458]508
[12df1f1]509 icmpv6_phdr_t phdr;
[a35b458]510
[a17356fd]511 host2addr128_t_be(ndp->sender_proto_addr, phdr.src_addr);
512 host2addr128_t_be(ndp->target_proto_addr, phdr.dest_addr);
513 phdr.length = host2uint32_t_be(dgram->size);
514 memset(phdr.zeroes, 0, 3);
515 phdr.next = IP_PROTO_ICMPV6;
[a35b458]516
[a17356fd]517 uint16_t cs_phdr =
518 inet_checksum_calc(INET_CHECKSUM_INIT, &phdr,
[12df1f1]519 sizeof(icmpv6_phdr_t));
[a35b458]520
[a17356fd]521 uint16_t cs_all = inet_checksum_calc(cs_phdr, dgram->data,
522 dgram->size);
[a35b458]523
[a17356fd]524 icmpv6->checksum = host2uint16_t_be(cs_all);
[a35b458]525
[a17356fd]526 return EOK;
527}
528
[1d94e21]529/** Decode NDP packet
530 *
531 * @param dgram Incoming IPv6 datagram encapsulating NDP packet
532 * @param ndp NDP packet structure to be filled
533 *
534 * @return EOK on success
535 * @return EINVAL if the Datagram is invalid
536 *
537 */
[b7fd2a0]538errno_t ndp_pdu_decode(inet_dgram_t *dgram, ndp_packet_t *ndp)
[a17356fd]539{
[f023251]540 ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL,
[a17356fd]541 &ndp->sender_proto_addr);
[f023251]542 if (src_ver != ip_v6)
[a17356fd]543 return EINVAL;
[a35b458]544
[a17356fd]545 if (dgram->size < sizeof(icmpv6_message_t) + sizeof(ndp_message_t))
546 return EINVAL;
[a35b458]547
[a17356fd]548 icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data;
[a35b458]549
[a17356fd]550 ndp->opcode = icmpv6->type;
[a35b458]551
[a17356fd]552 ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1);
[a35b458]553
[a17356fd]554 addr128_t_be2host(message->target_address, ndp->target_proto_addr);
[b4edc96]555 eth_addr_decode(message->mac, &ndp->sender_hw_addr);
[a35b458]556
[a17356fd]557 return EOK;
[1d24ad3]558}
559
[ceba4bed]560/** @}
561 */
Note: See TracBrowser for help on using the repository browser.