Changeset f3386d7 in mainline for uspace/srv/net/inetsrv/pdu.c


Ignore:
Timestamp:
2013-07-15T20:44:54Z (11 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f8d3df3
Parents:
273c976 (diff), a940f1d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

mainline changes

File:
1 edited

Legend:

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

    r273c976 rf3386d7  
    4444#include <mem.h>
    4545#include <stdlib.h>
    46 
     46#include <net/socket_codes.h>
    4747#include "inetsrv.h"
    4848#include "inet_std.h"
     
    8888}
    8989
    90 /** Encode Internet PDU.
     90/** Encode IPv4 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 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 
     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 */
     108int 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{
    122111        /* Upper bound for fragment offset field */
    123         fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
    124 
     112        size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     113       
    125114        /* Verify that total size of datagram is within reasonable bounds */
    126115        if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
    127116                return ELIMIT;
    128 
    129         hdr_size = sizeof(ip_header_t);
    130         data_offs = ROUND_UP(hdr_size, 4);
    131 
     117       
     118        size_t hdr_size = sizeof(ip_header_t);
     119       
     120        size_t data_offs = ROUND_UP(hdr_size, 4);
     121       
    132122        assert(offs % FRAG_OFFS_UNIT == 0);
    133123        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
    134 
     124       
    135125        /* Value for the fragment offset field */
    136         foff = offs / FRAG_OFFS_UNIT;
    137 
     126        uint16_t foff = offs / FRAG_OFFS_UNIT;
     127       
    138128        if (hdr_size >= mtu)
    139129                return EINVAL;
    140 
     130       
    141131        /* Amount of space in the PDU available for payload */
    142         spc_avail = mtu - hdr_size;
     132        size_t spc_avail = mtu - hdr_size;
    143133        spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
    144 
     134       
    145135        /* Amount of data (payload) to transfer */
    146         xfer_size = min(packet->size - offs, spc_avail);
    147 
     136        size_t xfer_size = min(packet->size - offs, spc_avail);
     137       
    148138        /* Total PDU size */
    149         size = hdr_size + xfer_size;
    150 
     139        size_t size = hdr_size + xfer_size;
     140       
    151141        /* Offset of remaining payload */
    152         rem_offs = offs + xfer_size;
    153 
     142        size_t rem_offs = offs + xfer_size;
     143       
    154144        /* Flags */
    155         flags_foff =
     145        uint16_t flags_foff =
    156146            (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
    157147            (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
    158148            (foff << FF_FRAGOFF_l);
    159 
    160         data = calloc(size, 1);
     149       
     150        void *data = calloc(size, 1);
    161151        if (data == NULL)
    162152                return ENOMEM;
    163 
     153       
    164154        /* Allocate identifier */
    165155        fibril_mutex_lock(&ip_ident_lock);
    166         ident = ++ip_ident;
     156        uint16_t ident = ++ip_ident;
    167157        fibril_mutex_unlock(&ip_ident_lock);
    168 
     158       
    169159        /* Encode header fields */
    170         hdr = (ip_header_t *)data;
    171         hdr->ver_ihl = (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
     160        ip_header_t *hdr = (ip_header_t *) data;
     161       
     162        hdr->ver_ihl =
     163            (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
    172164        hdr->tos = packet->tos;
    173165        hdr->tot_len = host2uint16_t_be(size);
     
    177169        hdr->proto = packet->proto;
    178170        hdr->chksum = 0;
    179         hdr->src_addr = host2uint32_t_be(packet->src.ipv4);
    180         hdr->dest_addr = host2uint32_t_be(packet->dest.ipv4);
    181 
     171        hdr->src_addr = host2uint32_t_be(src);
     172        hdr->dest_addr = host2uint32_t_be(dest);
     173       
    182174        /* Compute checksum */
    183         chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size);
     175        uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
     176            (void *) hdr, hdr_size);
    184177        hdr->chksum = host2uint16_t_be(chksum);
    185 
     178       
    186179        /* Copy payload */
    187         memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size);
    188 
     180        memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);
     181       
    189182        *rdata = data;
    190183        *rsize = size;
    191184        *roffs = rem_offs;
    192 
     185       
    193186        return EOK;
    194187}
    195188
     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 */
     207int 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
    196292int inet_pdu_decode(void *data, size_t size, inet_packet_t *packet)
    197293{
    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 
    206294        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
    207 
     295       
    208296        if (size < sizeof(ip_header_t)) {
    209297                log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
    210298                return EINVAL;
    211299        }
    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);
     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);
    217305        if (version != 4) {
    218306                log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
    219307                return EINVAL;
    220308        }
    221 
    222         tot_len = uint16_t_be2host(hdr->tot_len);
     309       
     310        size_t tot_len = uint16_t_be2host(hdr->tot_len);
    223311        if (tot_len < sizeof(ip_header_t)) {
    224312                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
    225313                return EINVAL;
    226314        }
    227 
     315       
    228316        if (tot_len > size) {
    229317                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,
     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,
    237325            flags_foff);
    238326        /* XXX Checksum */
    239 
    240         packet->src.ipv4 = uint32_t_be2host(hdr->src_addr);
    241         packet->dest.ipv4 = uint32_t_be2host(hdr->dest_addr);
     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);
    242330        packet->tos = hdr->tos;
    243331        packet->proto = hdr->proto;
    244332        packet->ttl = hdr->ttl;
    245333        packet->ident = ident;
    246 
     334       
    247335        packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
    248336        packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
    249337        packet->offs = foff * FRAG_OFFS_UNIT;
    250 
     338       
    251339        /* 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 
     340        size_t data_offs = sizeof(uint32_t) *
     341            BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl);
     342       
    255343        packet->size = tot_len - data_offs;
    256344        packet->data = calloc(packet->size, 1);
     
    259347                return ENOMEM;
    260348        }
    261 
    262         memcpy(packet->data, (uint8_t *)data + data_offs, packet->size);
    263 
     349       
     350        memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
     351       
    264352        return EOK;
    265353}
    266354
     355int 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
     434int 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
     486int 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
    267508/** @}
    268509 */
Note: See TracChangeset for help on using the changeset viewer.