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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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