fix OneNAND erase/write
[qemu] / slirp / ip_output.c
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 }