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