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


Ignore:
Timestamp:
2013-07-15T12:14:55Z (12 years ago)
Author:
Manuele Conti <conti.ma@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c84146d3
Parents:
87159eb8 (diff), 956d4281 (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:

Merge with mainline changes.

File:
1 edited

Legend:

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

    r87159eb8 rb86a32e  
    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         addr32_t src_v4;
    109         addr128_t src_v6;
    110         uint16_t src_af = inet_addr_get(&packet->src, &src_v4, &src_v6);
    111        
    112         addr32_t dest_v4;
    113         addr128_t dest_v6;
    114         uint16_t dest_af = inet_addr_get(&packet->dest, &dest_v4, &dest_v6);
    115        
    116         if (src_af != dest_af)
    117                 return EINVAL;
    118        
     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{
    119111        /* Upper bound for fragment offset field */
    120112        size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     
    124116                return ELIMIT;
    125117       
    126         size_t hdr_size;
    127        
    128         switch (src_af) {
    129         case AF_INET:
    130                 hdr_size = sizeof(ip_header_t);
    131                 break;
    132         case AF_INET6:
    133                 hdr_size = sizeof(ip6_header_t);
    134                 break;
    135         default:
    136                 assert(false);
    137         }
     118        size_t hdr_size = sizeof(ip_header_t);
    138119       
    139120        size_t data_offs = ROUND_UP(hdr_size, 4);
     
    177158       
    178159        /* Encode header fields */
    179         ip_header_t *hdr;
    180         ip6_header_t *hdr6;
    181        
    182         switch (src_af) {
    183         case AF_INET:
    184                 hdr = (ip_header_t *) data;
    185                
    186                 hdr->ver_ihl =
    187                     (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
    188                 hdr->tos = packet->tos;
    189                 hdr->tot_len = host2uint16_t_be(size);
    190                 hdr->id = host2uint16_t_be(ident);
    191                 hdr->flags_foff = host2uint16_t_be(flags_foff);
    192                 hdr->ttl = packet->ttl;
    193                 hdr->proto = packet->proto;
    194                 hdr->chksum = 0;
    195                 hdr->src_addr = host2uint32_t_be(src_v4);
    196                 hdr->dest_addr = host2uint32_t_be(dest_v4);
    197                
    198                 /* Compute checksum */
    199                 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
    200                     (void *) hdr, hdr_size);
    201                 hdr->chksum = host2uint16_t_be(chksum);
    202                
    203                 break;
    204         case AF_INET6:
    205                 // TODO FIXME: fragmentation
    206                
    207                 hdr6 = (ip6_header_t *) data;
    208                
    209                 hdr6->ver_tc = (6 << (VI_VERSION_l));
    210                 memset(hdr6->tc_fl, 0, 3);
    211                 hdr6->payload_len = host2uint16_t_be(packet->size);
    212                 hdr6->next = packet->proto;
    213                 hdr6->hop_limit = packet->ttl;
    214                
    215                 host2addr128_t_be(src_v6, hdr6->src_addr);
    216                 host2addr128_t_be(dest_v6, hdr6->dest_addr);
    217                
    218                 break;
    219         default:
    220                 assert(false);
    221         }
     160        ip_header_t *hdr = (ip_header_t *) data;
     161       
     162        hdr->ver_ihl =
     163            (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
     164        hdr->tos = packet->tos;
     165        hdr->tot_len = host2uint16_t_be(size);
     166        hdr->id = host2uint16_t_be(ident);
     167        hdr->flags_foff = host2uint16_t_be(flags_foff);
     168        hdr->ttl = packet->ttl;
     169        hdr->proto = packet->proto;
     170        hdr->chksum = 0;
     171        hdr->src_addr = host2uint32_t_be(src);
     172        hdr->dest_addr = host2uint32_t_be(dest);
     173       
     174        /* Compute checksum */
     175        uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
     176            (void *) hdr, hdr_size);
     177        hdr->chksum = host2uint16_t_be(chksum);
     178       
     179        /* Copy payload */
     180        memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);
     181       
     182        *rdata = data;
     183        *rsize = size;
     184        *roffs = rem_offs;
     185       
     186        return EOK;
     187}
     188
     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);
    222281       
    223282        /* Copy payload */
     
    257316        if (tot_len > size) {
    258317                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
    259                         tot_len, size);
     318                    tot_len, size);
    260319                return EINVAL;
    261320        }
     
    296355int inet_pdu_decode6(void *data, size_t size, inet_packet_t *packet)
    297356{
    298         // FIXME TODO
    299         return ENOTSUP;
     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_pseudo_header 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_pseudo_header));
     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;
    300506}
    301507
Note: See TracChangeset for help on using the changeset viewer.