Changeset 44c9ef4 in mainline


Ignore:
Timestamp:
2013-07-18T17:14:32Z (11 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0aa70f4
Parents:
34c1bba
Message:

IPv6 fragmentation support

Location:
uspace/srv/net/inetsrv
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/inetsrv/inet_std.h

    r34c1bba r44c9ef4  
    3939
    4040#include <sys/types.h>
     41
     42#define IP6_NEXT_FRAGMENT  44
    4143
    4244/** IPv4 Datagram header (fixed part) */
     
    9092};
    9193
    92 /** Bits in ip6_frag_header_t.offsmf */
     94/** Bits in ip6_header_fragment_t.offsmf */
    9395enum flags_offsmt_bits {
    9496        /** More fragments */
  • uspace/srv/net/inetsrv/pdu.c

    r34c1bba r44c9ef4  
    114114       
    115115        size_t hdr_size = sizeof(ip_header_t);
    116        
    117         size_t data_offs = ROUND_UP(hdr_size, 4);
    118        
     116        if (hdr_size >= mtu)
     117                return EINVAL;
     118       
     119        assert(hdr_size % 4 == 0);
    119120        assert(offs % FRAG_OFFS_UNIT == 0);
    120121        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
     
    122123        /* Value for the fragment offset field */
    123124        uint16_t foff = offs / FRAG_OFFS_UNIT;
    124        
    125         if (hdr_size >= mtu)
    126                 return EINVAL;
    127125       
    128126        /* Amount of space in the PDU available for payload */
     
    170168       
    171169        /* Copy payload */
    172         memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);
     170        memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);
    173171       
    174172        *rdata = data;
     
    194192 * @param rdata  Place to store pointer to allocated data buffer
    195193 * @param rsize  Place to store size of allocated data buffer
    196  * @param roffs Place to store offset of remaning data
     194 * @param roffs  Place to store offset of remaning data
    197195 *
    198196 */
     
    200198    size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)
    201199{
     200        /* IPv6 mandates a minimal MTU of 1280 bytes */
     201        if (mtu < 1280)
     202                return ELIMIT;
     203       
    202204        /* Upper bound for fragment offset field */
    203         size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     205        size_t fragoff_limit = 1 << (OF_FRAGOFF_h - OF_FRAGOFF_l);
    204206       
    205207        /* Verify that total size of datagram is within reasonable bounds */
     
    207209                return ELIMIT;
    208210       
    209         size_t hdr_size = sizeof(ip6_header_t);
    210        
    211         size_t data_offs = ROUND_UP(hdr_size, 4);
    212        
     211        /* Determine whether we need the Fragment extension header */
     212        bool fragment;
     213        if (offs == 0)
     214                fragment = (packet->size + sizeof(ip6_header_t) > mtu);
     215        else
     216                fragment = true;
     217       
     218        size_t hdr_size;
     219        if (fragment)
     220                hdr_size = sizeof(ip6_header_t) + sizeof(ip6_header_fragment_t);
     221        else
     222                hdr_size = sizeof(ip6_header_t);
     223       
     224        if (hdr_size >= mtu)
     225                return EINVAL;
     226       
     227        assert(sizeof(ip6_header_t) % 8 == 0);
     228        assert(hdr_size % 8 == 0);
    213229        assert(offs % FRAG_OFFS_UNIT == 0);
    214230        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
    215231       
    216 #if 0
    217         // FIXME TODO fragmentation
    218        
    219232        /* Value for the fragment offset field */
    220233        uint16_t foff = offs / FRAG_OFFS_UNIT;
    221 #endif
    222        
    223         if (hdr_size >= mtu)
    224                 return EINVAL;
    225234       
    226235        /* Amount of space in the PDU available for payload */
     
    237246        size_t rem_offs = offs + xfer_size;
    238247       
    239 #if 0
    240         // FIXME TODO fragmentation
    241        
    242248        /* Flags */
    243         uint16_t flags_foff =
    244             (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
    245             (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
    246             (foff << FF_FRAGOFF_l);
    247 #endif
     249        uint16_t offsmf =
     250            (rem_offs < packet->size ? BIT_V(uint16_t, OF_FLAG_M) : 0) +
     251            (foff << OF_FRAGOFF_l);
    248252       
    249253        void *data = calloc(size, 1);
     
    256260        hdr6->ver_tc = (6 << (VI_VERSION_l));
    257261        memset(hdr6->tc_fl, 0, 3);
    258         hdr6->payload_len = host2uint16_t_be(packet->size);
    259         hdr6->next = packet->proto;
    260262        hdr6->hop_limit = packet->ttl;
    261263       
     
    263265        host2addr128_t_be(dest, hdr6->dest_addr);
    264266       
     267        /* Optionally encode Fragment extension header fields */
     268        if (fragment) {
     269                assert(offsmf != 0);
     270               
     271                hdr6->payload_len = host2uint16_t_be(packet->size +
     272                    sizeof(ip6_header_fragment_t));
     273                hdr6->next = IP6_NEXT_FRAGMENT;
     274               
     275                ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)
     276                    (hdr6 + 1);
     277               
     278                hdr6f->next = packet->proto;
     279                hdr6f->reserved = 0;
     280                hdr6f->offsmf = host2uint16_t_be(offsmf);
     281                hdr6f->id = host2uint32_t_be(packet->ident);
     282        } else {
     283                assert(offsmf == 0);
     284               
     285                hdr6->payload_len = host2uint16_t_be(packet->size);
     286                hdr6->next = packet->proto;
     287        }
     288       
    265289        /* Copy payload */
    266         memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);
     290        memcpy((uint8_t *) data + hdr_size, packet->data + offs, xfer_size);
    267291       
    268292        *rdata = data;
     
    378402        size_t payload_len = uint16_t_be2host(hdr6->payload_len);
    379403        if (payload_len + sizeof(ip6_header_t) > size) {
    380                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
     404                log_msg(LOG_DEFAULT, LVL_DEBUG, "Payload Length = %zu > PDU size = %zu",
    381405                    payload_len + sizeof(ip6_header_t), size);
    382406                return EINVAL;
    383407        }
    384408       
    385 #if 0
    386         // FIXME TODO fragmentation
    387        
    388         uint16_t ident = uint16_t_be2host(hdr->id);
    389         uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff);
    390         uint16_t foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l,
    391             flags_foff);
    392 #endif
    393        
    394         /* XXX Checksum */
     409        uint32_t ident;
     410        uint16_t offsmf;
     411        uint16_t foff;
     412        uint16_t next;
     413        size_t data_offs = sizeof(ip6_header_t);
     414       
     415        /* Fragment extension header */
     416        if (hdr6->next == IP6_NEXT_FRAGMENT) {
     417                ip6_header_fragment_t *hdr6f = (ip6_header_fragment_t *)
     418                    (hdr6 + 1);
     419               
     420                ident = uint32_t_be2host(hdr6f->id);
     421                offsmf = uint16_t_be2host(hdr6f->offsmf);
     422                foff = BIT_RANGE_EXTRACT(uint16_t, OF_FRAGOFF_h, OF_FRAGOFF_l,
     423                    offsmf);
     424                next = hdr6f->next;
     425                data_offs += sizeof(ip6_header_fragment_t);
     426                payload_len -= sizeof(ip6_header_fragment_t);
     427        } else {
     428                ident = 0;
     429                offsmf = 0;
     430                foff = 0;
     431                next = hdr6->next;
     432        }
    395433       
    396434        addr128_t src;
     
    404442       
    405443        packet->tos = 0;
    406         packet->proto = hdr6->next;
     444        packet->proto = next;
    407445        packet->ttl = hdr6->hop_limit;
    408        
    409 #if 0
    410         // FIXME TODO fragmentation
    411        
    412446        packet->ident = ident;
    413         packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
    414         packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
     447       
     448        packet->df = 1;
     449        packet->mf = (offsmf & BIT_V(uint16_t, OF_FLAG_M)) != 0;
    415450        packet->offs = foff * FRAG_OFFS_UNIT;
    416        
    417         /* XXX IP options */
    418         size_t data_offs = sizeof(uint32_t) *
    419             BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl);
    420 #endif
    421        
    422         packet->ident = 0;
    423         packet->df = 0;
    424         packet->mf = 0;
    425         packet->offs = 0;
    426451       
    427452        packet->size = payload_len;
     
    432457        }
    433458       
    434         memcpy(packet->data, (uint8_t *) data + sizeof(ip6_header_t), packet->size);
     459        memcpy(packet->data, (uint8_t *) data + data_offs, packet->size);
    435460       
    436461        return EOK;
Note: See TracChangeset for help on using the changeset viewer.