VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/if.c@ 1033

Last change on this file since 1033 was 1033, checked in by vboxsync, 18 years ago

Big change to make slirp fully instantiatable (replace all global
variables with local ones, passing a reference to the state/config
structure to all places which are interested). You can now have as many
cards in the guest configured for NAT networking as you want.

  • Property svn:eol-style set to native
File size: 8.6 KB
Line 
1/*
2 * Copyright (c) 1995 Danny Gasparovski.
3 *
4 * Please read the file COPYRIGHT for the
5 * terms and conditions of the copyright.
6 */
7
8#include <slirp.h>
9
10#ifndef VBOX
11int if_mtu, if_mru;
12int if_comp;
13int if_maxlinkhdr;
14int if_queued = 0; /* Number of packets queued so far */
15int if_thresh = 10; /* Number of packets queued before we start sending
16 * (to prevent allocing too many mbufs) */
17
18struct mbuf if_fastq; /* fast queue (for interactive data) */
19struct mbuf if_batchq; /* queue for non-interactive data */
20struct mbuf *next_m; /* Pointer to next mbuf to output */
21#endif /* !VBOX */
22
23#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
24
25#ifndef VBOX
26void
27ifs_insque(ifm, ifmhead)
28 struct mbuf *ifm, *ifmhead;
29#else /* VBOX */
30static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
31#endif /* VBOX */
32{
33 ifm->ifs_next = ifmhead->ifs_next;
34 ifmhead->ifs_next = ifm;
35 ifm->ifs_prev = ifmhead;
36 ifm->ifs_next->ifs_prev = ifm;
37}
38
39#ifndef VBOX
40void
41ifs_remque(ifm)
42 struct mbuf *ifm;
43#else /* VBOX */
44static void ifs_remque(struct mbuf *ifm)
45#endif /* VBOX */
46{
47 ifm->ifs_prev->ifs_next = ifm->ifs_next;
48 ifm->ifs_next->ifs_prev = ifm->ifs_prev;
49}
50
51void
52#ifdef VBOX
53if_init(PNATState pData)
54#else /* !VBOX */
55if_init()
56#endif /* !VBOX */
57{
58#if 0
59 /*
60 * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
61 * and 8 bytes for PPP, but need to have it on an 8byte boundary
62 */
63#ifdef USE_PPP
64 if_maxlinkhdr = 48;
65#else
66 if_maxlinkhdr = 40;
67#endif
68#else
69 /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
70 if_maxlinkhdr = 2 + 14 + 40;
71#endif
72#ifdef VBOX
73 if_queued = 0;
74 if_thresh = 10;
75#endif /* VBOX */
76 if_mtu = 1500;
77 if_mru = 1500;
78 if_comp = IF_AUTOCOMP;
79 if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
80 if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
81 /* sl_compress_init(&comp_s); */
82 next_m = &if_batchq;
83}
84
85#if 0
86/*
87 * This shouldn't be needed since the modem is blocking and
88 * we don't expect any signals, but what the hell..
89 */
90inline int
91writen(fd, bptr, n)
92 int fd;
93 char *bptr;
94 int n;
95{
96 int ret;
97 int total;
98
99 /* This should succeed most of the time */
100 ret = send(fd, bptr, n,0);
101 if (ret == n || ret <= 0)
102 return ret;
103
104 /* Didn't write everything, go into the loop */
105 total = ret;
106 while (n > total) {
107 ret = send(fd, bptr+total, n-total,0);
108 if (ret <= 0)
109 return ret;
110 total += ret;
111 }
112 return total;
113}
114
115/*
116 * if_input - read() the tty, do "top level" processing (ie: check for any escapes),
117 * and pass onto (*ttyp->if_input)
118 *
119 * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
120 */
121#define INBUFF_SIZE 2048 /* XXX */
122void
123if_input(ttyp)
124 struct ttys *ttyp;
125{
126 u_char if_inbuff[INBUFF_SIZE];
127 int if_n;
128
129 DEBUG_CALL("if_input");
130 DEBUG_ARG("ttyp = %lx", (long)ttyp);
131
132 if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0);
133
134 DEBUG_MISC((dfd, " read %d bytes\n", if_n));
135
136 if (if_n <= 0) {
137 if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
138 if (ttyp->up)
139 link_up--;
140 tty_detached(ttyp, 0);
141 }
142 return;
143 }
144 if (if_n == 1) {
145 if (*if_inbuff == '0') {
146 ttyp->ones = 0;
147 if (++ttyp->zeros >= 5)
148 slirp_exit(0);
149 return;
150 }
151 if (*if_inbuff == '1') {
152 ttyp->zeros = 0;
153 if (++ttyp->ones >= 5)
154 tty_detached(ttyp, 0);
155 return;
156 }
157 }
158 ttyp->ones = ttyp->zeros = 0;
159
160 (*ttyp->if_input)(ttyp, if_inbuff, if_n);
161}
162#endif
163
164/*
165 * if_output: Queue packet into an output queue.
166 * There are 2 output queue's, if_fastq and if_batchq.
167 * Each output queue is a doubly linked list of double linked lists
168 * of mbufs, each list belonging to one "session" (socket). This
169 * way, we can output packets fairly by sending one packet from each
170 * session, instead of all the packets from one session, then all packets
171 * from the next session, etc. Packets on the if_fastq get absolute
172 * priority, but if one session hogs the link, it gets "downgraded"
173 * to the batchq until it runs out of packets, then it'll return
174 * to the fastq (eg. if the user does an ls -alR in a telnet session,
175 * it'll temporarily get downgraded to the batchq)
176 */
177void
178#ifdef VBOX
179if_output(PNATState pData, struct socket *so, struct mbuf *ifm)
180#else /* !VBOX */
181if_output(so, ifm)
182 struct socket *so;
183 struct mbuf *ifm;
184#endif /* !VBOX */
185{
186 struct mbuf *ifq;
187 int on_fastq = 1;
188
189 DEBUG_CALL("if_output");
190 DEBUG_ARG("so = %lx", (long)so);
191 DEBUG_ARG("ifm = %lx", (long)ifm);
192
193 /*
194 * First remove the mbuf from m_usedlist,
195 * since we're gonna use m_next and m_prev ourselves
196 * XXX Shouldn't need this, gotta change dtom() etc.
197 */
198 if (ifm->m_flags & M_USEDLIST) {
199 remque(ifm);
200 ifm->m_flags &= ~M_USEDLIST;
201 }
202
203 /*
204 * See if there's already a batchq list for this session.
205 * This can include an interactive session, which should go on fastq,
206 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
207 * We mustn't put this packet back on the fastq (or we'll send it out of order)
208 * XXX add cache here?
209 */
210 for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) {
211 if (so == ifq->ifq_so) {
212 /* A match! */
213 ifm->ifq_so = so;
214 ifs_insque(ifm, ifq->ifs_prev);
215 goto diddit;
216 }
217 }
218
219 /* No match, check which queue to put it on */
220 if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
221 ifq = if_fastq.ifq_prev;
222 on_fastq = 1;
223 /*
224 * Check if this packet is a part of the last
225 * packet's session
226 */
227 if (ifq->ifq_so == so) {
228 ifm->ifq_so = so;
229 ifs_insque(ifm, ifq->ifs_prev);
230 goto diddit;
231 }
232 } else
233 ifq = if_batchq.ifq_prev;
234
235 /* Create a new doubly linked list for this session */
236 ifm->ifq_so = so;
237 ifs_init(ifm);
238 insque(ifm, ifq);
239
240diddit:
241 ++if_queued;
242
243 if (so) {
244 /* Update *_queued */
245 so->so_queued++;
246 so->so_nqueued++;
247 /*
248 * Check if the interactive session should be downgraded to
249 * the batchq. A session is downgraded if it has queued 6
250 * packets without pausing, and at least 3 of those packets
251 * have been sent over the link
252 * (XXX These are arbitrary numbers, probably not optimal..)
253 */
254 if (on_fastq && ((so->so_nqueued >= 6) &&
255 (so->so_nqueued - so->so_queued) >= 3)) {
256
257 /* Remove from current queue... */
258 remque(ifm->ifs_next);
259
260 /* ...And insert in the new. That'll teach ya! */
261 insque(ifm->ifs_next, &if_batchq);
262 }
263 }
264
265#ifndef FULL_BOLT
266 /*
267 * This prevents us from malloc()ing too many mbufs
268 */
269 if (link_up) {
270 /* if_start will check towrite */
271#ifdef VBOX
272 if_start(pData);
273#else /* !VBOX */
274 if_start();
275#endif /* !VBOX */
276 }
277#endif
278}
279
280/*
281 * Send a packet
282 * We choose a packet based on it's position in the output queues;
283 * If there are packets on the fastq, they are sent FIFO, before
284 * everything else. Otherwise we choose the first packet from the
285 * batchq and send it. the next packet chosen will be from the session
286 * after this one, then the session after that one, and so on.. So,
287 * for example, if there are 3 ftp session's fighting for bandwidth,
288 * one packet will be sent from the first session, then one packet
289 * from the second session, then one packet from the third, then back
290 * to the first, etc. etc.
291 */
292void
293#ifdef VBOX
294if_start(PNATState pData)
295#else /* !VBOX */
296if_start(void)
297#endif /* !VBOX */
298{
299 struct mbuf *ifm, *ifqt;
300
301 DEBUG_CALL("if_start");
302
303 if (if_queued == 0)
304 return; /* Nothing to do */
305
306 again:
307 /* check if we can really output */
308#ifdef VBOX
309 if (!slirp_can_output(pData->pvUser))
310#else /* !VBOX */
311 if (!slirp_can_output())
312#endif /* !VBOX */
313 return;
314
315 /*
316 * See which queue to get next packet from
317 * If there's something in the fastq, select it immediately
318 */
319 if (if_fastq.ifq_next != &if_fastq) {
320 ifm = if_fastq.ifq_next;
321 } else {
322 /* Nothing on fastq, see if next_m is valid */
323 if (next_m != &if_batchq)
324 ifm = next_m;
325 else
326 ifm = if_batchq.ifq_next;
327
328 /* Set which packet to send on next iteration */
329 next_m = ifm->ifq_next;
330 }
331 /* Remove it from the queue */
332 ifqt = ifm->ifq_prev;
333 remque(ifm);
334 --if_queued;
335
336 /* If there are more packets for this session, re-queue them */
337 if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
338 insque(ifm->ifs_next, ifqt);
339 ifs_remque(ifm);
340 }
341
342 /* Update so_queued */
343 if (ifm->ifq_so) {
344 if (--ifm->ifq_so->so_queued == 0)
345 /* If there's no more queued, reset nqueued */
346 ifm->ifq_so->so_nqueued = 0;
347 }
348
349 /* Encapsulate the packet for sending */
350#ifndef VBOX
351 if_encap(ifm->m_data, ifm->m_len);
352#else /* VBOX */
353 if_encap(pData, (const uint8_t *)ifm->m_data, ifm->m_len);
354#endif /* VBOX */
355
356#ifdef VBOX
357 m_free(pData, ifm);
358#else /* !VBOX */
359 m_free(ifm);
360#endif /* !VBOX */
361
362 if (if_queued)
363 goto again;
364}
Note: See TracBrowser for help on using the repository browser.

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