File:  [Qemu by Fabrice Bellard] / qemu / slirp / ip_output.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:54:30 2018 UTC (3 years ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

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

unix.superglobalmegacorp.com