Changeset 347768d in mainline for uspace/srv/inet/pdu.c


Ignore:
Timestamp:
2012-04-11T05:52:47Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
7f95c904
Parents:
7094e196
Message:

Fragmentation of outgoing datagrams, default link MTU.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/inet/pdu.c

    r7094e196 r347768d  
    4141#include <fibril_synch.h>
    4242#include <io/log.h>
     43#include <macros.h>
    4344#include <mem.h>
    4445#include <stdlib.h>
     
    8889
    8990/** Encode Internet PDU.
    90  */
    91 int inet_pdu_encode(inet_packet_t *packet, void **rdata, size_t *rsize)
     91 *
     92 * Encode internet packet into PDU (serialized form). Will encode a
     93 * fragment of the payload starting at offset @a offs. The resulting
     94 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset
     95 * of remaining payload. If some data is remaining, the MF flag will
     96 * be set in the header, otherwise the offset will equal @a packet->size.
     97 *
     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)
    92107{
    93108        void *data;
     
    98113        uint16_t chksum;
    99114        uint16_t ident;
    100 
     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
     122        /* Upper bound for fragment offset field */
     123        fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     124
     125        /* Verify that total size of datagram is within reasonable bounds */
     126        if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
     127                return ELIMIT;
     128
     129        hdr_size = sizeof(ip_header_t);
     130        data_offs = ROUND_UP(hdr_size, 4);
     131
     132        assert(offs % FRAG_OFFS_UNIT == 0);
     133        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
     134
     135        /* Value for the fragment offset field */
     136        foff = offs / FRAG_OFFS_UNIT;
     137
     138        if (hdr_size >= mtu)
     139                return EINVAL;
     140
     141        /* Amount of space in the PDU available for payload */
     142        spc_avail = mtu - hdr_size;
     143
     144        /* Amount of data (payload) to transfer */
     145        xfer_size = min(packet->size - offs, spc_avail);
     146        xfer_size -= (xfer_size % FRAG_OFFS_UNIT);
     147
     148        /* Total PDU size */
     149        size = hdr_size + xfer_size;
     150
     151        /* Offset of remaining payload */
     152        rem_offs = offs + xfer_size;
     153
     154        /* Flags */
     155        flags_foff =
     156            (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
     157            (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
     158            (foff << FF_FRAGOFF_l);
     159
     160        data = calloc(size, 1);
     161        if (data == NULL)
     162                return ENOMEM;
     163
     164        /* Allocate identifier */
    101165        fibril_mutex_lock(&ip_ident_lock);
    102166        ident = ++ip_ident;
    103167        fibril_mutex_unlock(&ip_ident_lock);
    104168
    105         hdr_size = sizeof(ip_header_t);
    106         size = hdr_size + packet->size;
    107         data_offs = ROUND_UP(hdr_size, 4);
    108 
    109         data = calloc(size, 1);
    110         if (data == NULL)
    111                 return ENOMEM;
    112 
     169        /* Encode header fields */
    113170        hdr = (ip_header_t *)data;
    114171        hdr->ver_ihl = (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
     
    116173        hdr->tot_len = host2uint16_t_be(size);
    117174        hdr->id = host2uint16_t_be(ident);
    118         hdr->flags_foff = host2uint16_t_be(packet->df ?
    119             BIT_V(uint16_t, FF_FLAG_DF) : 0);
     175        hdr->flags_foff = host2uint16_t_be(flags_foff);
    120176        hdr->ttl = packet->ttl;
    121177        hdr->proto = packet->proto;
     
    124180        hdr->dest_addr = host2uint32_t_be(packet->dest.ipv4);
    125181
     182        /* Compute checksum */
    126183        chksum = inet_checksum_calc(INET_CHECKSUM_INIT, (void *)hdr, hdr_size);
    127184        hdr->chksum = host2uint16_t_be(chksum);
    128185
    129         memcpy((uint8_t *)data + data_offs, packet->data, packet->size);
     186        /* Copy payload */
     187        memcpy((uint8_t *)data + data_offs, packet->data + offs, xfer_size);
    130188
    131189        *rdata = data;
    132190        *rsize = size;
     191        *roffs = rem_offs;
     192
    133193        return EOK;
    134194}
Note: See TracChangeset for help on using the changeset viewer.