1
2
3
4
5
6
7
8
9
10
11
/*
* Copyright ( c ) 1995 Danny Gasparovski .
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright .
*/
# include < slirp . h >
# define ifs_init ( ifm ) (( ifm ) -> ifs_next = ( ifm ) -> ifs_prev = ( ifm ))
12
static void
13
ifs_insque ( struct mbuf * ifm , struct mbuf * ifmhead )
14
15
16
17
18
19
20
{
ifm -> ifs_next = ifmhead -> ifs_next ;
ifmhead -> ifs_next = ifm ;
ifm -> ifs_prev = ifmhead ;
ifm -> ifs_next -> ifs_prev = ifm ;
}
21
static void
22
ifs_remque ( struct mbuf * ifm )
23
24
25
26
27
28
{
ifm -> ifs_prev -> ifs_next = ifm -> ifs_next ;
ifm -> ifs_next -> ifs_prev = ifm -> ifs_prev ;
}
void
29
if_init ( Slirp * slirp )
30
{
31
32
33
slirp -> if_fastq . ifq_next = slirp -> if_fastq . ifq_prev = & slirp -> if_fastq ;
slirp -> if_batchq . ifq_next = slirp -> if_batchq . ifq_prev = & slirp -> if_batchq ;
slirp -> next_m = & slirp -> if_batchq ;
34
35
36
37
}
/*
* if_output : Queue packet into an output queue .
ths
authored
18 years ago
38
* There are 2 output queue ' s , if_fastq and if_batchq .
39
40
41
42
* Each output queue is a doubly linked list of double linked lists
* of mbufs , each list belonging to one "session" ( socket ). This
* way , we can output packets fairly by sending one packet from each
* session , instead of all the packets from one session , then all packets
ths
authored
18 years ago
43
* from the next session , etc . Packets on the if_fastq get absolute
44
45
46
47
48
49
* priority , but if one session hogs the link , it gets "downgraded"
* to the batchq until it runs out of packets , then it ' ll return
* to the fastq ( eg . if the user does an ls - alR in a telnet session ,
* it ' ll temporarily get downgraded to the batchq )
*/
void
50
if_output ( struct socket * so , struct mbuf * ifm )
51
{
52
Slirp * slirp = ifm -> slirp ;
53
54
struct mbuf * ifq ;
int on_fastq = 1 ;
ths
authored
18 years ago
55
56
57
58
DEBUG_CALL ( "if_output" );
DEBUG_ARG ( "so = %lx" , ( long ) so );
DEBUG_ARG ( "ifm = %lx" , ( long ) ifm );
ths
authored
18 years ago
59
60
61
62
63
64
65
66
67
68
/*
* First remove the mbuf from m_usedlist ,
* since we ' re gonna use m_next and m_prev ourselves
* XXX Shouldn ' t need this , gotta change dtom () etc .
*/
if ( ifm -> m_flags & M_USEDLIST ) {
remque ( ifm );
ifm -> m_flags &= ~ M_USEDLIST ;
}
ths
authored
18 years ago
69
70
/*
ths
authored
18 years ago
71
* See if there ' s already a batchq list for this session .
72
73
74
75
76
* This can include an interactive session , which should go on fastq ,
* but gets too greedy ... hence it ' ll be downgraded from fastq to batchq .
* We mustn ' t put this packet back on the fastq ( or we ' ll send it out of order )
* XXX add cache here ?
*/
77
78
for ( ifq = slirp -> if_batchq . ifq_prev ; ifq != & slirp -> if_batchq ;
ifq = ifq -> ifq_prev ) {
79
80
81
82
83
84
85
if ( so == ifq -> ifq_so ) {
/* A match! */
ifm -> ifq_so = so ;
ifs_insque ( ifm , ifq -> ifs_prev );
goto diddit ;
}
}
ths
authored
18 years ago
86
87
88
/* No match, check which queue to put it on */
if ( so && ( so -> so_iptos & IPTOS_LOWDELAY )) {
89
ifq = slirp -> if_fastq . ifq_prev ;
90
91
92
93
94
95
96
97
98
99
100
on_fastq = 1 ;
/*
* Check if this packet is a part of the last
* packet ' s session
*/
if ( ifq -> ifq_so == so ) {
ifm -> ifq_so = so ;
ifs_insque ( ifm , ifq -> ifs_prev );
goto diddit ;
}
} else
101
ifq = slirp -> if_batchq . ifq_prev ;
ths
authored
18 years ago
102
103
104
105
106
/* Create a new doubly linked list for this session */
ifm -> ifq_so = so ;
ifs_init ( ifm );
insque ( ifm , ifq );
ths
authored
18 years ago
107
108
diddit :
109
slirp -> if_queued ++ ;
ths
authored
18 years ago
110
111
112
113
114
115
116
117
118
119
120
121
if ( so ) {
/* Update *_queued */
so -> so_queued ++ ;
so -> so_nqueued ++ ;
/*
* Check if the interactive session should be downgraded to
* the batchq . A session is downgraded if it has queued 6
* packets without pausing , and at least 3 of those packets
* have been sent over the link
* ( XXX These are arbitrary numbers , probably not optimal ..)
*/
ths
authored
18 years ago
122
if ( on_fastq && (( so -> so_nqueued >= 6 ) &&
123
( so -> so_nqueued - so -> so_queued ) >= 3 )) {
ths
authored
18 years ago
124
125
126
/* Remove from current queue... */
remque ( ifm -> ifs_next );
ths
authored
18 years ago
127
128
/* ...And insert in the new. That'll teach ya! */
129
insque ( ifm -> ifs_next , & slirp -> if_batchq );
130
131
132
133
134
135
136
}
}
# ifndef FULL_BOLT
/*
* This prevents us from malloc () ing too many mbufs
*/
137
if_start ( ifm -> slirp );
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# endif
}
/*
* Send a packet
* We choose a packet based on it ' s position in the output queues ;
* If there are packets on the fastq , they are sent FIFO , before
* everything else . Otherwise we choose the first packet from the
* batchq and send it . the next packet chosen will be from the session
* after this one , then the session after that one , and so on .. So ,
* for example , if there are 3 ftp session ' s fighting for bandwidth ,
* one packet will be sent from the first session , then one packet
* from the second session , then one packet from the third , then back
* to the first , etc . etc .
*/
void
154
if_start ( Slirp * slirp )
155
156
{
struct mbuf * ifm , * ifqt ;
ths
authored
18 years ago
157
158
DEBUG_CALL ( "if_start" );
ths
authored
18 years ago
159
160
if ( slirp -> if_queued == 0 )
161
return ; /* Nothing to do */
ths
authored
18 years ago
162
163
164
again :
/* check if we can really output */
165
if ( ! slirp_can_output ( slirp -> opaque ))
166
167
168
169
170
171
return ;
/*
* See which queue to get next packet from
* If there ' s something in the fastq , select it immediately
*/
172
173
if ( slirp -> if_fastq . ifq_next != & slirp -> if_fastq ) {
ifm = slirp -> if_fastq . ifq_next ;
174
175
} else {
/* Nothing on fastq, see if next_m is valid */
176
177
if ( slirp -> next_m != & slirp -> if_batchq )
ifm = slirp -> next_m ;
178
else
179
ifm = slirp -> if_batchq . ifq_next ;
ths
authored
18 years ago
180
181
/* Set which packet to send on next iteration */
182
slirp -> next_m = ifm -> ifq_next ;
183
184
185
186
}
/* Remove it from the queue */
ifqt = ifm -> ifq_prev ;
remque ( ifm );
187
slirp -> if_queued -- ;
ths
authored
18 years ago
188
189
190
191
192
193
/* If there are more packets for this session, re-queue them */
if ( ifm -> ifs_next != /* ifm->ifs_prev != */ ifm ) {
insque ( ifm -> ifs_next , ifqt );
ifs_remque ( ifm );
}
ths
authored
18 years ago
194
195
196
197
198
199
200
/* Update so_queued */
if ( ifm -> ifq_so ) {
if ( -- ifm -> ifq_so -> so_queued == 0 )
/* If there's no more queued, reset nqueued */
ifm -> ifq_so -> so_nqueued = 0 ;
}
ths
authored
18 years ago
201
202
/* Encapsulate the packet for sending */
203
if_encap ( slirp , ( uint8_t * ) ifm -> m_data , ifm -> m_len );
204
205
206
m_free ( ifm );
207
if ( slirp -> if_queued )
208
209
goto again ;
}