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