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