Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/inetsrv/pdu.c

    ra1a101d r5a324d99  
    4444#include <mem.h>
    4545#include <stdlib.h>
    46 
    4746#include "inetsrv.h"
    4847#include "inet_std.h"
    4948#include "pdu.h"
    50 
    51 static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
    52 static uint16_t ip_ident = 0;
    5349
    5450/** One's complement addition.
     
    8884}
    8985
    90 /** Encode Internet PDU.
     86/** Encode IPv4 PDU.
    9187 *
    9288 * Encode internet packet into PDU (serialized form). Will encode a
     
    9692 * be set in the header, otherwise the offset will equal @a packet->size.
    9793 *
    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 
     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 */
     104int 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{
    122107        /* Upper bound for fragment offset field */
    123         fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
    124 
     108        size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     109       
    125110        /* Verify that total size of datagram is within reasonable bounds */
    126111        if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
    127112                return ELIMIT;
    128 
    129         hdr_size = sizeof(ip_header_t);
    130         data_offs = ROUND_UP(hdr_size, 4);
    131 
     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);
    132119        assert(offs % FRAG_OFFS_UNIT == 0);
    133120        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
    134 
     121       
    135122        /* Value for the fragment offset field */
    136         foff = offs / FRAG_OFFS_UNIT;
    137 
    138         if (hdr_size >= mtu)
    139                 return EINVAL;
    140 
     123        uint16_t foff = offs / FRAG_OFFS_UNIT;
     124       
    141125        /* Amount of space in the PDU available for payload */
    142         spc_avail = mtu - hdr_size;
     126        size_t spc_avail = mtu - hdr_size;
    143127        spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
    144 
     128       
    145129        /* Amount of data (payload) to transfer */
    146         xfer_size = min(packet->size - offs, spc_avail);
    147 
     130        size_t xfer_size = min(packet->size - offs, spc_avail);
     131       
    148132        /* Total PDU size */
    149         size = hdr_size + xfer_size;
    150 
     133        size_t size = hdr_size + xfer_size;
     134       
    151135        /* Offset of remaining payload */
    152         rem_offs = offs + xfer_size;
    153 
     136        size_t rem_offs = offs + xfer_size;
     137       
    154138        /* Flags */
    155         flags_foff =
     139        uint16_t flags_foff =
    156140            (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
    157141            (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
    158142            (foff << FF_FRAGOFF_l);
    159 
    160         data = calloc(size, 1);
     143       
     144        void *data = calloc(size, 1);
    161145        if (data == NULL)
    162146                return ENOMEM;
    163 
    164         /* Allocate identifier */
    165         fibril_mutex_lock(&ip_ident_lock);
    166         ident = ++ip_ident;
    167         fibril_mutex_unlock(&ip_ident_lock);
    168 
     147       
    169148        /* Encode header fields */
    170         hdr = (ip_header_t *)data;
    171         hdr->ver_ihl = (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
     149        ip_header_t *hdr = (ip_header_t *) data;
     150       
     151        hdr->ver_ihl =
     152            (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
    172153        hdr->tos = packet->tos;
    173154        hdr->tot_len = host2uint16_t_be(size);
    174         hdr->id = host2uint16_t_be(ident);
     155        hdr->id = host2uint16_t_be(packet->ident);
    175156        hdr->flags_foff = host2uint16_t_be(flags_foff);
    176157        hdr->ttl = packet->ttl;
    177158        hdr->proto = packet->proto;
    178159        hdr->chksum = 0;
    179         hdr->src_addr = host2uint32_t_be(packet->src.ipv4);
    180         hdr->dest_addr = host2uint32_t_be(packet->dest.ipv4);
    181 
     160        hdr->src_addr = host2uint32_t_be(src);
     161        hdr->dest_addr = host2uint32_t_be(dest);
     162       
    182163        /* Compute checksum */
    183         chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size);
     164        uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
     165            (void *) hdr, hdr_size);
    184166        hdr->chksum = host2uint16_t_be(chksum);
    185 
     167       
    186168        /* Copy payload */
    187         memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size);
    188 
     169        memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);
     170       
    189171        *rdata = data;
    190172        *rsize = size;
    191173        *roffs = rem_offs;
    192 
     174       
    193175        return EOK;
    194176}
    195177
     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
     193 * @param roffs  Place to store offset of remaning data
     194 *
     195 */
     196int 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        else
     215                fragment = true;
     216       
     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);
     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 datagram
     299 *
     300 * @param data   Serialized IPv4 datagram
     301 * @param size   Length of serialized IPv4 datagram
     302 * @param packet IP datagram structure to be filled
     303 *
     304 * @return EOK on success
     305 * @return EINVAL if the datagram is invalid or damaged
     306 * @return ENOMEM if not enough memory
     307 *
     308 */
    196309int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet)
    197310{
    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 
    206311        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
    207 
     312       
    208313        if (size < sizeof(ip_header_t)) {
    209314                log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
    210315                return EINVAL;
    211316        }
    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);
     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);
    217322        if (version != 4) {
    218323                log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
    219324                return EINVAL;
    220325        }
    221 
    222         tot_len = uint16_t_be2host(hdr->tot_len);
     326       
     327        size_t tot_len = uint16_t_be2host(hdr->tot_len);
    223328        if (tot_len < sizeof(ip_header_t)) {
    224329                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
    225330                return EINVAL;
    226331        }
    227 
     332       
    228333        if (tot_len > size) {
    229334                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
    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,
     335                    tot_len, size);
     336                return EINVAL;
     337        }
     338       
     339        uint16_t ident = uint16_t_be2host(hdr->id);
     340        uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff);
     341        uint16_t foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l,
    237342            flags_foff);
    238343        /* XXX Checksum */
    239 
    240         packet->src.ipv4 = uint32_t_be2host(hdr->src_addr);
    241         packet->dest.ipv4 = uint32_t_be2host(hdr->dest_addr);
     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);
    242347        packet->tos = hdr->tos;
    243348        packet->proto = hdr->proto;
    244349        packet->ttl = hdr->ttl;
    245350        packet->ident = ident;
    246 
     351       
    247352        packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
    248353        packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
    249354        packet->offs = foff * FRAG_OFFS_UNIT;
    250 
     355       
    251356        /* 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 
     357        size_t data_offs = sizeof(uint32_t) *
     358            BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl);
     359       
    255360        packet->size = tot_len - data_offs;
    256361        packet->data = calloc(packet->size, 1);
     
    259364                return ENOMEM;
    260365        }
    261 
    262         memcpy(packet->data, (uint8_t *)data + data_offs, packet->size);
    263 
     366       
     367        memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
     368       
    264369        return EOK;
    265370}
    266371
     372/** Decode IPv6 datagram
     373 *
     374 * @param data   Serialized IPv6 datagram
     375 * @param size   Length of serialized IPv6 datagram
     376 * @param packet IP datagram structure to be filled
     377 *
     378 * @return EOK on success
     379 * @return EINVAL if the datagram is invalid or damaged
     380 * @return ENOMEM if not enough memory
     381 *
     382 */
     383int 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 packet
     464 *
     465 * @param ndp   NDP packet structure to be serialized
     466 * @param dgram IPv6 datagram structure to be filled
     467 *
     468 * @return EOK on success
     469 *
     470 */
     471int 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 packet
     524 *
     525 * @param dgram Incoming IPv6 datagram encapsulating NDP packet
     526 * @param ndp   NDP packet structure to be filled
     527 *
     528 * @return EOK on success
     529 * @return EINVAL if the Datagram is invalid
     530 *
     531 */
     532int 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
    267554/** @}
    268555 */
Note: See TracChangeset for help on using the changeset viewer.