Ignore:
File:
1 edited

Legend:

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

    r5a324d99 ra1a101d  
    4444#include <mem.h>
    4545#include <stdlib.h>
     46
    4647#include "inetsrv.h"
    4748#include "inet_std.h"
    4849#include "pdu.h"
     50
     51static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
     52static uint16_t ip_ident = 0;
    4953
    5054/** One's complement addition.
     
    8488}
    8589
    86 /** Encode IPv4 PDU.
     90/** Encode Internet PDU.
    8791 *
    8892 * Encode internet packet into PDU (serialized form). Will encode a
     
    9296 * be set in the header, otherwise the offset will equal @a packet->size.
    9397 *
    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  */
    104 int 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 {
     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 */
     105int 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
    107122        /* Upper bound for fragment offset field */
    108         size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
    109        
     123        fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     124
    110125        /* Verify that total size of datagram is within reasonable bounds */
    111126        if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
    112127                return ELIMIT;
    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);
     128
     129        hdr_size = sizeof(ip_header_t);
     130        data_offs = ROUND_UP(hdr_size, 4);
     131
    119132        assert(offs % FRAG_OFFS_UNIT == 0);
    120133        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
    121        
     134
    122135        /* Value for the fragment offset field */
    123         uint16_t foff = offs / FRAG_OFFS_UNIT;
    124        
     136        foff = offs / FRAG_OFFS_UNIT;
     137
     138        if (hdr_size >= mtu)
     139                return EINVAL;
     140
    125141        /* Amount of space in the PDU available for payload */
    126         size_t spc_avail = mtu - hdr_size;
     142        spc_avail = mtu - hdr_size;
    127143        spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
    128        
     144
    129145        /* Amount of data (payload) to transfer */
    130         size_t xfer_size = min(packet->size - offs, spc_avail);
    131        
     146        xfer_size = min(packet->size - offs, spc_avail);
     147
    132148        /* Total PDU size */
    133         size_t size = hdr_size + xfer_size;
    134        
     149        size = hdr_size + xfer_size;
     150
    135151        /* Offset of remaining payload */
    136         size_t rem_offs = offs + xfer_size;
    137        
     152        rem_offs = offs + xfer_size;
     153
    138154        /* Flags */
    139         uint16_t flags_foff =
     155        flags_foff =
    140156            (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
    141157            (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
    142158            (foff << FF_FRAGOFF_l);
    143        
    144         void *data = calloc(size, 1);
     159
     160        data = calloc(size, 1);
    145161        if (data == NULL)
    146162                return ENOMEM;
    147        
     163
     164        /* Allocate identifier */
     165        fibril_mutex_lock(&ip_ident_lock);
     166        ident = ++ip_ident;
     167        fibril_mutex_unlock(&ip_ident_lock);
     168
    148169        /* Encode header fields */
    149         ip_header_t *hdr = (ip_header_t *) data;
    150        
    151         hdr->ver_ihl =
    152             (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));
    153172        hdr->tos = packet->tos;
    154173        hdr->tot_len = host2uint16_t_be(size);
    155         hdr->id = host2uint16_t_be(packet->ident);
     174        hdr->id = host2uint16_t_be(ident);
    156175        hdr->flags_foff = host2uint16_t_be(flags_foff);
    157176        hdr->ttl = packet->ttl;
    158177        hdr->proto = packet->proto;
    159178        hdr->chksum = 0;
    160         hdr->src_addr = host2uint32_t_be(src);
    161         hdr->dest_addr = host2uint32_t_be(dest);
    162        
     179        hdr->src_addr = host2uint32_t_be(packet->src.ipv4);
     180        hdr->dest_addr = host2uint32_t_be(packet->dest.ipv4);
     181
    163182        /* Compute checksum */
    164         uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
    165             (void *) hdr, hdr_size);
     183        chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size);
    166184        hdr->chksum = host2uint16_t_be(chksum);
    167        
     185
    168186        /* Copy payload */
    169         memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);
    170        
     187        memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size);
     188
    171189        *rdata = data;
    172190        *rsize = size;
    173191        *roffs = rem_offs;
    174        
     192
    175193        return EOK;
    176194}
    177195
    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  */
    196 int 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  */
    309196int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet)
    310197{
     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
    311206        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
    312        
     207
    313208        if (size < sizeof(ip_header_t)) {
    314209                log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
    315210                return EINVAL;
    316211        }
    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);
     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);
    322217        if (version != 4) {
    323218                log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
    324219                return EINVAL;
    325220        }
    326        
    327         size_t tot_len = uint16_t_be2host(hdr->tot_len);
     221
     222        tot_len = uint16_t_be2host(hdr->tot_len);
    328223        if (tot_len < sizeof(ip_header_t)) {
    329224                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
    330225                return EINVAL;
    331226        }
    332        
     227
    333228        if (tot_len > size) {
    334229                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
    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,
     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,
    342237            flags_foff);
    343238        /* XXX Checksum */
    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);
     239
     240        packet->src.ipv4 = uint32_t_be2host(hdr->src_addr);
     241        packet->dest.ipv4 = uint32_t_be2host(hdr->dest_addr);
    347242        packet->tos = hdr->tos;
    348243        packet->proto = hdr->proto;
    349244        packet->ttl = hdr->ttl;
    350245        packet->ident = ident;
    351        
     246
    352247        packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
    353248        packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
    354249        packet->offs = foff * FRAG_OFFS_UNIT;
    355        
     250
    356251        /* XXX IP options */
    357         size_t data_offs = sizeof(uint32_t) *
    358             BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl);
    359        
     252        data_offs = sizeof(uint32_t) * BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h,
     253            VI_IHL_l, hdr->ver_ihl);
     254
    360255        packet->size = tot_len - data_offs;
    361256        packet->data = calloc(packet->size, 1);
     
    364259                return ENOMEM;
    365260        }
    366        
    367         memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
    368        
     261
     262        memcpy(packet->data, (uint8_t *)data + data_offs, packet->size);
     263
    369264        return EOK;
    370265}
    371266
    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  */
    383 int 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  */
    471 int 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  */
    532 int 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 
    554267/** @}
    555268 */
Note: See TracChangeset for help on using the changeset viewer.