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