VirtualBox

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

Last change on this file since 532 was 1, checked in by vboxsync, 55 years ago

import

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