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 "qemu/osdep.h" 42#include <slirp.h> 43 44/* Number of packets queued before we start sending 45 * (to prevent allocing too many mbufs) */ 46#define IF_THRESH 10 47 48/* 49 * IP output. The packet in mbuf chain m contains a skeletal IP 50 * header (with len, off, ttl, proto, tos, src, dst). 51 * The mbuf chain containing the packet will be freed. 52 * The mbuf opt, if present, will not be freed. 53 */ 54int 55ip_output(struct socket *so, struct mbuf *m0) 56{ 57 Slirp *slirp = m0->slirp; 58 register struct ip *ip; 59 register struct mbuf *m = m0; 60 register int hlen = sizeof(struct ip ); 61 int len, off, error = 0; 62 63 DEBUG_CALL("ip_output"); 64 DEBUG_ARG("so = %p", so); 65 DEBUG_ARG("m0 = %p", m0); 66 67 ip = mtod(m, struct ip *); 68 /* 69 * Fill in IP header. 70 */ 71 ip->ip_v = IPVERSION; 72 ip->ip_off &= IP_DF; 73 ip->ip_id = htons(slirp->ip_id++); 74 ip->ip_hl = hlen >> 2; 75 76 /* 77 * If small enough for interface, can just send directly. 78 */ 79 if ((uint16_t)ip->ip_len <= IF_MTU) { 80 ip->ip_len = htons((uint16_t)ip->ip_len); 81 ip->ip_off = htons((uint16_t)ip->ip_off); 82 ip->ip_sum = 0; 83 ip->ip_sum = cksum(m, hlen); 84 85 if_output(so, m); 86 goto done; 87 } 88 89 /* 90 * Too large for interface; fragment if possible. 91 * Must be able to put at least 8 bytes per fragment. 92 */ 93 if (ip->ip_off & IP_DF) { 94 error = -1; 95 goto bad; 96 } 97 98 len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */ 99 if (len < 8) { 100 error = -1; 101 goto bad; 102 } 103 104 { 105 int mhlen, firstlen = len; 106 struct mbuf **mnext = &m->m_nextpkt; 107 108 /* 109 * Loop through length of segment after first fragment, 110 * make new header and copy data of each part and link onto chain. 111 */ 112 m0 = m; 113 mhlen = sizeof (struct ip); 114 for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) { 115 register struct ip *mhip; 116 m = m_get(slirp); 117 if (m == NULL) { 118 error = -1; 119 goto sendorfree; 120 } 121 m->m_data += IF_MAXLINKHDR; 122 mhip = mtod(m, struct ip *); 123 *mhip = *ip; 124 125 m->m_len = mhlen; 126 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 127 if (ip->ip_off & IP_MF) 128 mhip->ip_off |= IP_MF; 129 if (off + len >= (uint16_t)ip->ip_len) 130 len = (uint16_t)ip->ip_len - off; 131 else 132 mhip->ip_off |= IP_MF; 133 mhip->ip_len = htons((uint16_t)(len + mhlen)); 134 135 if (m_copy(m, m0, off, len) < 0) { 136 error = -1; 137 goto sendorfree; 138 } 139 140 mhip->ip_off = htons((uint16_t)mhip->ip_off); 141 mhip->ip_sum = 0; 142 mhip->ip_sum = cksum(m, mhlen); 143 *mnext = m; 144 mnext = &m->m_nextpkt; 145 } 146 /* 147 * Update first fragment by trimming what's been copied out 148 * and updating header, then send each fragment (in order). 149 */ 150 m = m0; 151 m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len); 152 ip->ip_len = htons((uint16_t)m->m_len); 153 ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF)); 154 ip->ip_sum = 0; 155 ip->ip_sum = cksum(m, hlen); 156sendorfree: 157 for (m = m0; m; m = m0) { 158 m0 = m->m_nextpkt; 159 m->m_nextpkt = NULL; 160 if (error == 0) 161 if_output(so, m); 162 else 163 m_free(m); 164 } 165 } 166 167done: 168 return (error); 169 170bad: 171 m_free(m0); 172 goto done; 173} 174