qemu/slirp/src/ip_output.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause */
   2/*
   3 * Copyright (c) 1982, 1986, 1988, 1990, 1993
   4 *      The Regents of the University of California.  All rights reserved.
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. Neither the name of the University nor the names of its contributors
  15 *    may be used to endorse or promote products derived from this software
  16 *    without specific prior written permission.
  17 *
  18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28 * SUCH DAMAGE.
  29 *
  30 *      @(#)ip_output.c 8.3 (Berkeley) 1/21/94
  31 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
  32 */
  33
  34/*
  35 * Changes and additions relating to SLiRP are
  36 * Copyright (c) 1995 Danny Gasparovski.
  37 */
  38
  39#include "slirp.h"
  40
  41/* Number of packets queued before we start sending
  42 * (to prevent allocing too many mbufs) */
  43#define IF_THRESH 10
  44
  45/*
  46 * IP output.  The packet in mbuf chain m contains a skeletal IP
  47 * header (with len, off, ttl, proto, tos, src, dst).
  48 * The mbuf chain containing the packet will be freed.
  49 * The mbuf opt, if present, will not be freed.
  50 */
  51int
  52ip_output(struct socket *so, struct mbuf *m0)
  53{
  54        Slirp *slirp = m0->slirp;
  55        register struct ip *ip;
  56        register struct mbuf *m = m0;
  57        register int hlen = sizeof(struct ip );
  58        int len, off, error = 0;
  59
  60        DEBUG_CALL("ip_output");
  61        DEBUG_ARG("so = %p", so);
  62        DEBUG_ARG("m0 = %p", m0);
  63
  64        ip = mtod(m, struct ip *);
  65        /*
  66         * Fill in IP header.
  67         */
  68        ip->ip_v = IPVERSION;
  69        ip->ip_off &= IP_DF;
  70        ip->ip_id = htons(slirp->ip_id++);
  71        ip->ip_hl = hlen >> 2;
  72
  73        /*
  74         * If small enough for interface, can just send directly.
  75         */
  76        if ((uint16_t)ip->ip_len <= IF_MTU) {
  77                ip->ip_len = htons((uint16_t)ip->ip_len);
  78                ip->ip_off = htons((uint16_t)ip->ip_off);
  79                ip->ip_sum = 0;
  80                ip->ip_sum = cksum(m, hlen);
  81
  82                if_output(so, m);
  83                goto done;
  84        }
  85
  86        /*
  87         * Too large for interface; fragment if possible.
  88         * Must be able to put at least 8 bytes per fragment.
  89         */
  90        if (ip->ip_off & IP_DF) {
  91                error = -1;
  92                goto bad;
  93        }
  94
  95        len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
  96        if (len < 8) {
  97                error = -1;
  98                goto bad;
  99        }
 100
 101    {
 102        int mhlen, firstlen = len;
 103        struct mbuf **mnext = &m->m_nextpkt;
 104
 105        /*
 106         * Loop through length of segment after first fragment,
 107         * make new header and copy data of each part and link onto chain.
 108         */
 109        m0 = m;
 110        mhlen = sizeof (struct ip);
 111        for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) {
 112          register struct ip *mhip;
 113          m = m_get(slirp);
 114          if (m == NULL) {
 115            error = -1;
 116            goto sendorfree;
 117          }
 118          m->m_data += IF_MAXLINKHDR;
 119          mhip = mtod(m, struct ip *);
 120          *mhip = *ip;
 121
 122          m->m_len = mhlen;
 123          mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
 124          if (ip->ip_off & IP_MF)
 125            mhip->ip_off |= IP_MF;
 126          if (off + len >= (uint16_t)ip->ip_len)
 127            len = (uint16_t)ip->ip_len - off;
 128          else
 129            mhip->ip_off |= IP_MF;
 130          mhip->ip_len = htons((uint16_t)(len + mhlen));
 131
 132          if (m_copy(m, m0, off, len) < 0) {
 133            error = -1;
 134            goto sendorfree;
 135          }
 136
 137          mhip->ip_off = htons((uint16_t)mhip->ip_off);
 138          mhip->ip_sum = 0;
 139          mhip->ip_sum = cksum(m, mhlen);
 140          *mnext = m;
 141          mnext = &m->m_nextpkt;
 142        }
 143        /*
 144         * Update first fragment by trimming what's been copied out
 145         * and updating header, then send each fragment (in order).
 146         */
 147        m = m0;
 148        m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len);
 149        ip->ip_len = htons((uint16_t)m->m_len);
 150        ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF));
 151        ip->ip_sum = 0;
 152        ip->ip_sum = cksum(m, hlen);
 153sendorfree:
 154        for (m = m0; m; m = m0) {
 155                m0 = m->m_nextpkt;
 156                m->m_nextpkt = NULL;
 157                if (error == 0)
 158                        if_output(so, m);
 159                else
 160                        m_free(m);
 161        }
 162    }
 163
 164done:
 165        return (error);
 166
 167bad:
 168        m_free(m0);
 169        goto done;
 170}
 171