VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/ip_output.c@ 28800

最後變更 在這個檔案從28800是 28800,由 vboxsync 提交於 15 年 前

Automated rebranding to Oracle copyright/license strings via filemuncher

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 13.1 KB
 
1/* $Id: ip_output.c 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * NAT - IP output.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * Copyright (c) 1982, 1986, 1988, 1990, 1993
22 * The Regents of the University of California. All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. All advertising materials mentioning features or use of this software
33 * must display the following acknowledgement:
34 * This product includes software developed by the University of
35 * California, Berkeley and its contributors.
36 * 4. Neither the name of the University nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
53 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp
54 */
55
56/*
57 * Changes and additions relating to SLiRP are
58 * Copyright (c) 1995 Danny Gasparovski.
59 *
60 * Please read the file COPYRIGHT for the
61 * terms and conditions of the copyright.
62 */
63
64#include <slirp.h>
65#include "alias.h"
66
67static const uint8_t broadcast_ethaddr[6] =
68{
69 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
70};
71
72static int rt_lookup_in_cache(PNATState pData, uint32_t dst, uint8_t *ether)
73{
74 int rc;
75 if (dst == INADDR_BROADCAST)
76 {
77 memcpy(ether, broadcast_ethaddr, ETH_ALEN);
78 return VINF_SUCCESS;
79 }
80
81 rc = slirp_arp_lookup_ether_by_ip(pData, dst, ether);
82 if (RT_SUCCESS(rc))
83 return rc;
84
85 rc = bootp_cache_lookup_ether_by_ip(pData, dst, ether);
86 if (RT_SUCCESS(rc))
87 return rc;
88 /*
89 * no chance to send this packet, sorry, we will request ether address via ARP
90 */
91 slirp_arp_who_has(pData, dst);
92 return VERR_NOT_FOUND;
93}
94
95/*
96 * IP output. The packet in mbuf chain m contains a skeletal IP
97 * header (with len, off, ttl, proto, tos, src, dst).
98 * The mbuf chain containing the packet will be freed.
99 * The mbuf opt, if present, will not be freed.
100 */
101int
102ip_output(PNATState pData, struct socket *so, struct mbuf *m0)
103{
104 return ip_output0(pData, so, m0, 0);
105}
106
107int
108ip_output0(PNATState pData, struct socket *so, struct mbuf *m0, int urg)
109{
110 register struct ip *ip;
111 register struct mbuf *m = m0;
112 register int hlen = sizeof(struct ip );
113 int len, off, error = 0;
114 extern uint8_t zerro_ethaddr[ETH_ALEN];
115 struct ethhdr *eh = NULL;
116 uint8_t eth_dst[ETH_ALEN];
117 int rc = 1;
118
119 STAM_PROFILE_START(&pData->StatIP_output, a);
120
121 DEBUG_CALL("ip_output");
122 DEBUG_ARG("so = %lx", (long)so);
123 DEBUG_ARG("m0 = %lx", (long)m0);
124
125#ifndef VBOX_WITH_SLIRP_BSD_MBUF
126 if(m->m_data != (MBUF_HEAD(m) + if_maxlinkhdr))
127 {
128 LogRel(("NAT: ethernet detects corruption of the packet"));
129 AssertMsgFailed(("!!Ethernet frame corrupted!!"));
130 }
131#else
132 M_ASSERTPKTHDR(m);
133 Assert(m->m_pkthdr.header);
134#endif
135
136#if 0 /* We do no options */
137 if (opt)
138 {
139 m = ip_insertoptions(m, opt, &len);
140 hlen = len;
141 }
142#endif
143 ip = mtod(m, struct ip *);
144 /*
145 * Fill in IP header.
146 */
147 ip->ip_v = IPVERSION;
148 ip->ip_off &= IP_DF;
149 ip->ip_id = RT_H2N_U16(ip_currid++);
150 ip->ip_hl = hlen >> 2;
151 ipstat.ips_localout++;
152
153 /*
154 * Verify that we have any chance at all of being able to queue
155 * the packet or packet fragments
156 */
157#if 0 /* XXX Hmmm... */
158 if (if_queued > if_thresh && towrite <= 0)
159 {
160 error = ENOBUFS;
161 goto exit_drop_package;
162 }
163#endif
164 /* Current TCP/IP stack hasn't routing information at
165 * all so we need to calculate destination ethernet address
166 */
167#ifndef VBOX_WITH_SLIRP_BSD_MBUF
168 eh = (struct ethhdr *)MBUF_HEAD(m);
169 if (memcmp(eh->h_source, zerro_ethaddr, ETH_ALEN) == 0)
170 {
171 rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst);
172 if (RT_FAILURE(rc))
173 goto exit_drop_package;
174 }
175 else
176 {
177 memcpy(eth_dst, eh->h_source, ETH_ALEN);
178 rc = 0; /*some times we've already know where to send packet*/
179 }
180#else
181 /*
182 * (vvl) Assumption is that m_data points at the IP header and only
183 * in case of dhcp we know and have header before IP.
184 */
185 rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst);
186 if (RT_FAILURE(rc))
187 goto exit_drop_package;
188
189 eh = (struct ethhdr *)(m->m_data - ETH_HLEN);
190#endif
191 /*
192 * If small enough for interface, can just send directly.
193 */
194 if ((u_int16_t)ip->ip_len <= if_mtu)
195 {
196 ip->ip_len = RT_H2N_U16((u_int16_t)ip->ip_len);
197 ip->ip_off = RT_H2N_U16((u_int16_t)ip->ip_off);
198 ip->ip_sum = 0;
199 ip->ip_sum = cksum(m, hlen);
200
201 {
202#ifndef VBOX_WITH_SLIRP_BSD_MBUF
203 STAM_PROFILE_START(&pData->StatALIAS_output, b);
204 rc = LibAliasOut((m->m_la ? m->m_la : pData->proxy_alias),
205 mtod(m, char *), m->m_len);
206 Log2(("NAT: LibAlias return %d\n", rc));
207#else
208 struct m_tag *t;
209 STAM_PROFILE_START(&pData->StatALIAS_output, b);
210 if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0)
211 rc = LibAliasOut((struct libalias *)&t[1], mtod(m, char *),
212 m_length(m, NULL));
213 else
214 rc = LibAliasOut(pData->proxy_alias, mtod(m, char *),
215 m_length(m, NULL));
216
217 if (rc == PKT_ALIAS_IGNORED)
218 {
219 Log(("NAT: packet was droppped\n"));
220 goto exit_drop_package;
221 }
222#endif
223 STAM_PROFILE_STOP(&pData->StatALIAS_output, b);
224 }
225
226 memcpy(eh->h_source, eth_dst, ETH_ALEN);
227
228 if_encap(pData, ETH_P_IP, m, urg? ETH_ENCAP_URG : 0);
229 goto done;
230 }
231
232 /*
233 * Too large for interface; fragment if possible.
234 * Must be able to put at least 8 bytes per fragment.
235 */
236 if (ip->ip_off & IP_DF)
237 {
238 error = -1;
239 ipstat.ips_cantfrag++;
240 goto exit_drop_package;
241 }
242
243 len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */
244 if (len < 8)
245 {
246 error = -1;
247 goto exit_drop_package;
248 }
249
250 {
251 int mhlen, firstlen = len;
252 struct mbuf **mnext = &m->m_nextpkt;
253#ifdef VBOX_WITH_SLIRP_BSD_MBUF
254 char *buf; /* intermediate buffer we'll use for copy from orriginal packet */
255#endif
256 {
257#ifdef VBOX_WITH_SLIRP_BSD_MBUF
258 struct m_tag *t;
259 char *tmpbuf = NULL;
260 int tmplen = 0;
261#endif
262 int rcLa;
263 HTONS(ip->ip_len);
264 HTONS(ip->ip_off);
265 ip->ip_sum = 0;
266 ip->ip_sum = cksum(m, hlen);
267#ifndef VBOX_WITH_SLIRP_BSD_MBUF
268 rcLa = LibAliasOut((m->m_la ? m->m_la : pData->proxy_alias),
269 mtod(m, char *), m->m_len);
270#else
271 if (m->m_next != NULL)
272 {
273 /*we've receives packet in fragments*/
274 tmplen = m_length(m, NULL);
275 tmpbuf = RTMemAlloc(tmplen);
276 Assert(tmpbuf);
277 m_copydata(m, 0, tmplen, tmpbuf);
278 }
279 else
280 {
281 tmpbuf = mtod(m, char *);
282 tmplen = m_length(m, NULL);
283
284 }
285
286 if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0)
287 rcLa = LibAliasOut((struct libalias *)&t[1], tmpbuf, tmplen);
288 else
289 rcLa = LibAliasOut(pData->proxy_alias, tmpbuf, tmplen);
290
291 if (m->m_next != NULL)
292 {
293 if (rcLa != PKT_ALIAS_IGNORED)
294 {
295 struct ip *tmpip = (struct ip *)tmpbuf;
296 m_copyback(pData, m, 0, RT_N2H_U16(tmpip->ip_len) + (tmpip->ip_hl << 2), tmpbuf);
297 }
298 if (tmpbuf != NULL)
299 RTMemFree(tmpbuf);
300 }
301 if (rcLa == PKT_ALIAS_IGNORED)
302 {
303 Log(("NAT: packet was droppped\n"));
304 goto exit_drop_package;
305 }
306#endif
307 NTOHS(ip->ip_len);
308 NTOHS(ip->ip_off);
309 Log2(("NAT: LibAlias return %d\n", rcLa));
310 }
311
312 /*
313 * Loop through length of segment after first fragment,
314 * make new header and copy data of each part and link onto chain.
315 */
316 m0 = m;
317 mhlen = sizeof (struct ip);
318 for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len)
319 {
320 register struct ip *mhip;
321#ifndef VBOX_WITH_SLIRP_BSD_MBUF
322 m = m_get(pData);
323#else
324 m = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
325#endif
326 if (m == 0)
327 {
328 error = -1;
329 ipstat.ips_odropped++;
330 goto sendorfree;
331 }
332 m->m_data += if_maxlinkhdr;
333 mhip = mtod(m, struct ip *);
334 *mhip = *ip;
335 m->m_len += ip->ip_hl << 2;
336#ifdef VBOX_WITH_SLIRP_BSD_MBUF
337 m->m_pkthdr.header = mtod(m, void *);
338#endif
339 /* we've calculated eth_dst for first packet */
340#if 0 /* No options */
341 if (hlen > sizeof (struct ip))
342 {
343 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
344 mhip->ip_hl = mhlen >> 2;
345 }
346#endif
347 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
348 if (ip->ip_off & IP_MF)
349 mhip->ip_off |= IP_MF;
350 if (off + len >= (u_int16_t)ip->ip_len)
351 len = (u_int16_t)ip->ip_len - off;
352 else
353 mhip->ip_off |= IP_MF;
354 mhip->ip_len = RT_H2N_U16((u_int16_t)(len + mhlen));
355
356#ifndef VBOX_WITH_SLIRP_BSD_MBUF
357 if (m_copy(m, m0, off, len) < 0)
358 {
359 error = -1;
360 goto sendorfree;
361 }
362#else
363 buf = RTMemAlloc(len);
364 m_copydata(m0, off, len, buf); /* copy to buffer */
365 m->m_data += mhlen;
366 m_copyback(pData, m, 0, len, buf); /* copy from buffer */
367 m->m_data -= mhlen;
368 m->m_len += mhlen;
369 RTMemFree(buf);
370 m->m_len += RT_N2H_U16(mhip->ip_len);
371#endif
372
373 mhip->ip_off = RT_H2N_U16((u_int16_t)mhip->ip_off);
374 mhip->ip_sum = 0;
375 mhip->ip_sum = cksum(m, mhlen);
376 *mnext = m;
377 mnext = &m->m_nextpkt;
378 ipstat.ips_ofragments++;
379 }
380 /*
381 * Update first fragment by trimming what's been copied out
382 * and updating header, then send each fragment (in order).
383 */
384 m = m0;
385 m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len);
386 ip->ip_len = RT_H2N_U16((u_int16_t)m->m_len);
387 ip->ip_off = RT_H2N_U16((u_int16_t)(ip->ip_off | IP_MF));
388 ip->ip_sum = 0;
389 ip->ip_sum = cksum(m, hlen);
390
391sendorfree:
392 for (m = m0; m; m = m0)
393 {
394 m0 = m->m_nextpkt;
395 m->m_nextpkt = 0;
396 if (error == 0)
397 {
398#ifndef VBOX_WITH_SLIRP_BSD_MBUF
399 eh = (struct ethhdr *)MBUF_HEAD(m);
400#else
401 m->m_data -= ETH_HLEN;
402 eh = mtod(m, struct ethhdr *);
403 m->m_data += ETH_HLEN;
404#endif
405 memcpy(eh->h_source, eth_dst, ETH_ALEN);
406
407 if_encap(pData, ETH_P_IP, m, 0);
408 }
409 else
410 {
411 m_freem(pData, m);
412 }
413 }
414
415 if (error == 0)
416 ipstat.ips_fragmented++;
417 }
418
419done:
420 STAM_PROFILE_STOP(&pData->StatIP_output, a);
421 return error;
422
423exit_drop_package:
424 m_freem(pData, m0);
425 STAM_PROFILE_STOP(&pData->StatIP_output, a);
426 return error;
427}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette