Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/if.c
2 views
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
* Copyright (c) 1995 Danny Gasparovski.
4
*/
5
6
#include "slirp.h"
7
8
static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
9
{
10
ifm->m_nextpkt = ifmhead->m_nextpkt;
11
ifmhead->m_nextpkt = ifm;
12
ifm->m_prevpkt = ifmhead;
13
ifm->m_nextpkt->m_prevpkt = ifm;
14
}
15
16
void if_init(Slirp *slirp)
17
{
18
slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;
19
slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;
20
}
21
22
/*
23
* if_output: Queue packet into an output queue.
24
* There are 2 output queue's, if_fastq and if_batchq.
25
* Each output queue is a doubly linked list of double linked lists
26
* of mbufs, each list belonging to one "session" (socket). This
27
* way, we can output packets fairly by sending one packet from each
28
* session, instead of all the packets from one session, then all packets
29
* from the next session, etc. Packets on the if_fastq get absolute
30
* priority, but if one session hogs the link, it gets "downgraded"
31
* to the batchq until it runs out of packets, then it'll return
32
* to the fastq (eg. if the user does an ls -alR in a telnet session,
33
* it'll temporarily get downgraded to the batchq)
34
*/
35
void if_output(struct socket *so, struct mbuf *ifm)
36
{
37
Slirp *slirp = ifm->slirp;
38
M_DUP_DEBUG(slirp, ifm, 0, 0);
39
40
struct mbuf *ifq;
41
int on_fastq = 1;
42
43
DEBUG_CALL("if_output");
44
DEBUG_ARG("so = %p", so);
45
DEBUG_ARG("ifm = %p", ifm);
46
47
/*
48
* First remove the mbuf from m_usedlist,
49
* since we're gonna use m_next and m_prev ourselves
50
* XXX Shouldn't need this, gotta change dtom() etc.
51
*/
52
if (ifm->m_flags & M_USEDLIST) {
53
slirp_remque(ifm);
54
ifm->m_flags &= ~M_USEDLIST;
55
}
56
57
/*
58
* See if there's already a batchq list for this session.
59
* This can include an interactive session, which should go on fastq,
60
* but gets too greedy... hence it'll be downgraded from fastq to batchq.
61
* We mustn't put this packet back on the fastq (or we'll send it out of
62
* order)
63
* XXX add cache here?
64
*/
65
if (so) {
66
for (ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
67
(struct slirp_quehead *)ifq != &slirp->if_batchq;
68
ifq = ifq->m_prev) {
69
if (so == ifq->m_so) {
70
/* A match! */
71
ifm->m_so = so;
72
ifs_insque(ifm, ifq->m_prevpkt);
73
goto diddit;
74
}
75
}
76
}
77
78
/* No match, check which queue to put it on */
79
if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
80
ifq = (struct mbuf *)slirp->if_fastq.qh_rlink;
81
on_fastq = 1;
82
/*
83
* Check if this packet is a part of the last
84
* packet's session
85
*/
86
if (ifq->m_so == so) {
87
ifm->m_so = so;
88
ifs_insque(ifm, ifq->m_prevpkt);
89
goto diddit;
90
}
91
} else {
92
ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
93
}
94
95
/* Create a new doubly linked list for this session */
96
ifm->m_so = so;
97
ifs_init(ifm);
98
slirp_insque(ifm, ifq);
99
100
diddit:
101
if (so) {
102
/* Update *_queued */
103
so->so_queued++;
104
so->so_nqueued++;
105
/*
106
* Check if the interactive session should be downgraded to
107
* the batchq. A session is downgraded if it has queued 6
108
* packets without pausing, and at least 3 of those packets
109
* have been sent over the link
110
* (XXX These are arbitrary numbers, probably not optimal..)
111
*/
112
if (on_fastq &&
113
((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) {
114
/* Remove from current queue... */
115
slirp_remque(ifm->m_nextpkt);
116
117
/* ...And insert in the new. That'll teach ya! */
118
slirp_insque(ifm->m_nextpkt, &slirp->if_batchq);
119
}
120
}
121
122
/*
123
* This prevents us from malloc()ing too many mbufs
124
*/
125
if_start(ifm->slirp);
126
}
127
128
void if_start(Slirp *slirp)
129
{
130
uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
131
bool from_batchq = false;
132
struct mbuf *ifm, *ifm_next, *ifqt;
133
134
DEBUG_VERBOSE_CALL("if_start");
135
136
if (slirp->if_start_busy) {
137
return;
138
}
139
slirp->if_start_busy = true;
140
141
struct mbuf *batch_head = NULL;
142
if (slirp->if_batchq.qh_link != &slirp->if_batchq) {
143
batch_head = (struct mbuf *)slirp->if_batchq.qh_link;
144
}
145
146
if (slirp->if_fastq.qh_link != &slirp->if_fastq) {
147
ifm_next = (struct mbuf *)slirp->if_fastq.qh_link;
148
} else if (batch_head) {
149
/* Nothing on fastq, pick up from batchq */
150
ifm_next = batch_head;
151
from_batchq = true;
152
} else {
153
ifm_next = NULL;
154
}
155
156
while (ifm_next) {
157
ifm = ifm_next;
158
159
ifm_next = ifm->m_next;
160
if ((struct slirp_quehead *)ifm_next == &slirp->if_fastq) {
161
/* No more packets in fastq, switch to batchq */
162
ifm_next = batch_head;
163
from_batchq = true;
164
}
165
if ((struct slirp_quehead *)ifm_next == &slirp->if_batchq) {
166
/* end of batchq */
167
ifm_next = NULL;
168
}
169
170
/* Try to send packet unless it already expired */
171
if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
172
/* Packet is delayed due to pending ARP or NDP resolution */
173
continue;
174
}
175
176
/* Remove it from the queue */
177
ifqt = ifm->m_prev;
178
slirp_remque(ifm);
179
180
/* If there are more packets for this session, re-queue them */
181
if (ifm->m_nextpkt != ifm) {
182
struct mbuf *next = ifm->m_nextpkt;
183
184
slirp_insque(next, ifqt);
185
ifs_remque(ifm);
186
if (!from_batchq) {
187
ifm_next = next;
188
}
189
}
190
191
/* Update so_queued */
192
if (ifm->m_so && --ifm->m_so->so_queued == 0) {
193
/* If there's no more queued, reset nqueued */
194
ifm->m_so->so_nqueued = 0;
195
}
196
197
m_free(ifm);
198
}
199
200
slirp->if_start_busy = false;
201
}
202
203