VirtualBox

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

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

slirp insque/remque fixes for amd64

  • 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(pData, 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(pData, 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(pData, ifm->ifs_next);
259
260 /* ...And insert in the new. That'll teach ya! */
261 insque(pData, 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(pData, 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(pData, 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