Ignore:
File:
1 edited

Legend:

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

    r12df1f1 ra1a101d  
    4444#include <mem.h>
    4545#include <stdlib.h>
    46 #include <net/socket_codes.h>
     46
    4747#include "inetsrv.h"
    4848#include "inet_std.h"
     
    8888}
    8989
    90 /** Encode IPv4 PDU.
     90/** Encode Internet PDU.
    9191 *
    9292 * Encode internet packet into PDU (serialized form). Will encode a
     
    9696 * be set in the header, otherwise the offset will equal @a packet->size.
    9797 *
    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 */
     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
    111122        /* Upper bound for fragment offset field */
    112         size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
    113        
     123        fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     124
    114125        /* Verify that total size of datagram is within reasonable bounds */
    115126        if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
    116127                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
    122132        assert(offs % FRAG_OFFS_UNIT == 0);
    123133        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
    124        
     134
    125135        /* Value for the fragment offset field */
    126         uint16_t foff = offs / FRAG_OFFS_UNIT;
    127        
     136        foff = offs / FRAG_OFFS_UNIT;
     137
    128138        if (hdr_size >= mtu)
    129139                return EINVAL;
    130        
     140
    131141        /* Amount of space in the PDU available for payload */
    132         size_t spc_avail = mtu - hdr_size;
     142        spc_avail = mtu - hdr_size;
    133143        spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
    134        
     144
    135145        /* Amount of data (payload) to transfer */
    136         size_t xfer_size = min(packet->size - offs, spc_avail);
    137        
     146        xfer_size = min(packet->size - offs, spc_avail);
     147
    138148        /* Total PDU size */
    139         size_t size = hdr_size + xfer_size;
    140        
     149        size = hdr_size + xfer_size;
     150
    141151        /* Offset of remaining payload */
    142         size_t rem_offs = offs + xfer_size;
    143        
     152        rem_offs = offs + xfer_size;
     153
    144154        /* Flags */
    145         uint16_t flags_foff =
     155        flags_foff =
    146156            (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
    147157            (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
    148158            (foff << FF_FRAGOFF_l);
    149        
    150         void *data = calloc(size, 1);
     159
     160        data = calloc(size, 1);
    151161        if (data == NULL)
    152162                return ENOMEM;
    153        
     163
    154164        /* Allocate identifier */
    155165        fibril_mutex_lock(&ip_ident_lock);
    156         uint16_t ident = ++ip_ident;
     166        ident = ++ip_ident;
    157167        fibril_mutex_unlock(&ip_ident_lock);
    158        
     168
    159169        /* 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));
    164172        hdr->tos = packet->tos;
    165173        hdr->tot_len = host2uint16_t_be(size);
     
    169177        hdr->proto = packet->proto;
    170178        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
    174182        /* 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);
    177184        hdr->chksum = host2uint16_t_be(chksum);
    178        
     185
    179186        /* Copy payload */
    180         memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);
    181        
     187        memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size);
     188
    182189        *rdata = data;
    183190        *rsize = size;
    184191        *roffs = rem_offs;
    185        
     192
    186193        return EOK;
    187194}
    188195
    189 /** Encode IPv6 PDU.
    190  *
    191  * Encode internet packet into PDU (serialized form). Will encode a
    192  * fragment of the payload starting at offset @a offs. The resulting
    193  * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset
    194  * of remaining payload. If some data is remaining, the MF flag will
    195  * be set in the header, otherwise the offset will equal @a packet->size.
    196  *
    197  * @param packet Packet to encode
    198  * @param src    Source address
    199  * @param dest   Destination address
    200  * @param offs   Offset into packet payload (in bytes)
    201  * @param mtu    MTU (Maximum Transmission Unit) in bytes
    202  * @param rdata  Place to store pointer to allocated data buffer
    203  * @param rsize  Place to store size of allocated data buffer
    204  * @param roffs Place to store offset of remaning data
    205  *
    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 0
    225         // FIXME TODO fragmentation
    226        
    227         /* Value for the fragment offset field */
    228         uint16_t foff = offs / FRAG_OFFS_UNIT;
    229 #endif
    230        
    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 0
    248         // FIXME TODO fragmentation
    249        
    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 #endif
    256        
    257         void *data = calloc(size, 1);
    258         if (data == NULL)
    259                 return ENOMEM;
    260        
    261 #if 0
    262         // FIXME TODO fragmentation
    263        
    264         /* Allocate identifier */
    265         fibril_mutex_lock(&ip_ident_lock);
    266         uint16_t ident = ++ip_ident;
    267         fibril_mutex_unlock(&ip_ident_lock);
    268 #endif
    269        
    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 
    292196int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet)
    293197{
     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
    294206        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
    295        
     207
    296208        if (size < sizeof(ip_header_t)) {
    297209                log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
    298210                return EINVAL;
    299211        }
    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);
    305217        if (version != 4) {
    306218                log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
    307219                return EINVAL;
    308220        }
    309        
    310         size_t tot_len = uint16_t_be2host(hdr->tot_len);
     221
     222        tot_len = uint16_t_be2host(hdr->tot_len);
    311223        if (tot_len < sizeof(ip_header_t)) {
    312224                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
    313225                return EINVAL;
    314226        }
    315        
     227
    316228        if (tot_len > size) {
    317229                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
    318                     tot_len, size);
    319                 return EINVAL;
    320         }
    321        
    322         uint16_t ident = uint16_t_be2host(hdr->id);
    323         uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff);
    324         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,
    325237            flags_foff);
    326238        /* 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);
    330242        packet->tos = hdr->tos;
    331243        packet->proto = hdr->proto;
    332244        packet->ttl = hdr->ttl;
    333245        packet->ident = ident;
    334        
     246
    335247        packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
    336248        packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
    337249        packet->offs = foff * FRAG_OFFS_UNIT;
    338        
     250
    339251        /* 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
    343255        packet->size = tot_len - data_offs;
    344256        packet->data = calloc(packet->size, 1);
     
    347259                return ENOMEM;
    348260        }
    349        
    350         memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
    351        
     261
     262        memcpy(packet->data, (uint8_t *)data + data_offs, packet->size);
     263
    352264        return EOK;
    353265}
    354266
    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 0
    381         // FIXME TODO fragmentation
    382        
    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 #endif
    388        
    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 0
    405         // FIXME TODO fragmentation
    406        
    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 #endif
    416        
    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 
    508267/** @}
    509268 */
Note: See TracChangeset for help on using the changeset viewer.