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(struct socket *so, struct mbuf *m0) 57 { 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 = %lx", (long)so); 65 DEBUG_ARG("m0 = %lx", (long)m0); 66 67 /* We do no options */ 68 /* if (opt) { 69 * m = ip_insertoptions(m, opt, &len); 70 * hlen = len; 71 * } 72 */ 73 ip = mtod(m, struct ip *); 74 /* 75 * Fill in IP header. 76 */ 77 ip->ip_v = IPVERSION; 78 ip->ip_off &= IP_DF; 79 ip->ip_id = htons(ip_id++); 80 ip->ip_hl = hlen >> 2; 81 STAT(ipstat.ips_localout++); 82 83 /* 84 * Verify that we have any chance at all of being able to queue 85 * the packet or packet fragments 86 */ 87 /* XXX Hmmm... */ 88 /* if (if_queued > IF_THRESH && towrite <= 0) { 89 * error = ENOBUFS; 90 * goto bad; 91 * } 92 */ 93 94 /* 95 * If small enough for interface, can just send directly. 96 */ 97 if ((u_int16_t)ip->ip_len <= IF_MTU) { 98 ip->ip_len = htons((u_int16_t)ip->ip_len); 99 ip->ip_off = htons((u_int16_t)ip->ip_off); 100 ip->ip_sum = 0; 101 ip->ip_sum = cksum(m, hlen); 102 103 if_output(so, m); 104 goto done; 105 } 106 107 /* 108 * Too large for interface; fragment if possible. 109 * Must be able to put at least 8 bytes per fragment. 110 */ 111 if (ip->ip_off & IP_DF) { 112 error = -1; 113 STAT(ipstat.ips_cantfrag++); 114 goto bad; 115 } 116 117 len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */ 118 if (len < 8) { 119 error = -1; 120 goto bad; 121 } 122 123 { 124 int mhlen, firstlen = len; 125 struct mbuf **mnext = &m->m_nextpkt; 126 127 /* 128 * Loop through length of segment after first fragment, 129 * make new header and copy data of each part and link onto chain. 130 */ 131 m0 = m; 132 mhlen = sizeof (struct ip); 133 for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { 134 register struct ip *mhip; 135 m = m_get(); 136 if (m == NULL) { 137 error = -1; 138 STAT(ipstat.ips_odropped++); 139 goto sendorfree; 140 } 141 m->m_data += IF_MAXLINKHDR; 142 mhip = mtod(m, struct ip *); 143 *mhip = *ip; 144 145 /* No options */ 146 /* if (hlen > sizeof (struct ip)) { 147 * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 148 * mhip->ip_hl = mhlen >> 2; 149 * } 150 */ 151 m->m_len = mhlen; 152 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 153 if (ip->ip_off & IP_MF) 154 mhip->ip_off |= IP_MF; 155 if (off + len >= (u_int16_t)ip->ip_len) 156 len = (u_int16_t)ip->ip_len - off; 157 else 158 mhip->ip_off |= IP_MF; 159 mhip->ip_len = htons((u_int16_t)(len + mhlen)); 160 161 if (m_copy(m, m0, off, len) < 0) { 162 error = -1; 163 goto sendorfree; 164 } 165 166 mhip->ip_off = htons((u_int16_t)mhip->ip_off); 167 mhip->ip_sum = 0; 168 mhip->ip_sum = cksum(m, mhlen); 169 *mnext = m; 170 mnext = &m->m_nextpkt; 171 STAT(ipstat.ips_ofragments++); 172 } 173 /* 174 * Update first fragment by trimming what's been copied out 175 * and updating header, then send each fragment (in order). 176 */ 177 m = m0; 178 m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len); 179 ip->ip_len = htons((u_int16_t)m->m_len); 180 ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); 181 ip->ip_sum = 0; 182 ip->ip_sum = cksum(m, hlen); 183 sendorfree: 184 for (m = m0; m; m = m0) { 185 m0 = m->m_nextpkt; 186 m->m_nextpkt = NULL; 187 if (error == 0) 188 if_output(so, m); 189 else 190 m_freem(m); 191 } 192 193 if (error == 0) 194 STAT(ipstat.ips_fragmented++); 195 } 196 197 done: 198 return (error); 199 200 bad: 201 m_freem(m0); 202 goto done; 203 } 204