ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/if.c
Revision: 1.1
Committed: 2005-05-13T09:00:59Z (19 years ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-17
Log Message:
slirp user mode network emulation code from qemu

File Contents

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