Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/if.c
2 views
/* SPDX-License-Identifier: BSD-3-Clause */1/*2* Copyright (c) 1995 Danny Gasparovski.3*/45#include "slirp.h"67static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)8{9ifm->m_nextpkt = ifmhead->m_nextpkt;10ifmhead->m_nextpkt = ifm;11ifm->m_prevpkt = ifmhead;12ifm->m_nextpkt->m_prevpkt = ifm;13}1415void if_init(Slirp *slirp)16{17slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;18slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;19}2021/*22* if_output: Queue packet into an output queue.23* There are 2 output queue's, if_fastq and if_batchq.24* Each output queue is a doubly linked list of double linked lists25* of mbufs, each list belonging to one "session" (socket). This26* way, we can output packets fairly by sending one packet from each27* session, instead of all the packets from one session, then all packets28* from the next session, etc. Packets on the if_fastq get absolute29* priority, but if one session hogs the link, it gets "downgraded"30* to the batchq until it runs out of packets, then it'll return31* to the fastq (eg. if the user does an ls -alR in a telnet session,32* it'll temporarily get downgraded to the batchq)33*/34void if_output(struct socket *so, struct mbuf *ifm)35{36Slirp *slirp = ifm->slirp;37M_DUP_DEBUG(slirp, ifm, 0, 0);3839struct mbuf *ifq;40int on_fastq = 1;4142DEBUG_CALL("if_output");43DEBUG_ARG("so = %p", so);44DEBUG_ARG("ifm = %p", ifm);4546/*47* First remove the mbuf from m_usedlist,48* since we're gonna use m_next and m_prev ourselves49* XXX Shouldn't need this, gotta change dtom() etc.50*/51if (ifm->m_flags & M_USEDLIST) {52slirp_remque(ifm);53ifm->m_flags &= ~M_USEDLIST;54}5556/*57* See if there's already a batchq list for this session.58* This can include an interactive session, which should go on fastq,59* but gets too greedy... hence it'll be downgraded from fastq to batchq.60* We mustn't put this packet back on the fastq (or we'll send it out of61* order)62* XXX add cache here?63*/64if (so) {65for (ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;66(struct slirp_quehead *)ifq != &slirp->if_batchq;67ifq = ifq->m_prev) {68if (so == ifq->m_so) {69/* A match! */70ifm->m_so = so;71ifs_insque(ifm, ifq->m_prevpkt);72goto diddit;73}74}75}7677/* No match, check which queue to put it on */78if (so && (so->so_iptos & IPTOS_LOWDELAY)) {79ifq = (struct mbuf *)slirp->if_fastq.qh_rlink;80on_fastq = 1;81/*82* Check if this packet is a part of the last83* packet's session84*/85if (ifq->m_so == so) {86ifm->m_so = so;87ifs_insque(ifm, ifq->m_prevpkt);88goto diddit;89}90} else {91ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;92}9394/* Create a new doubly linked list for this session */95ifm->m_so = so;96ifs_init(ifm);97slirp_insque(ifm, ifq);9899diddit:100if (so) {101/* Update *_queued */102so->so_queued++;103so->so_nqueued++;104/*105* Check if the interactive session should be downgraded to106* the batchq. A session is downgraded if it has queued 6107* packets without pausing, and at least 3 of those packets108* have been sent over the link109* (XXX These are arbitrary numbers, probably not optimal..)110*/111if (on_fastq &&112((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) {113/* Remove from current queue... */114slirp_remque(ifm->m_nextpkt);115116/* ...And insert in the new. That'll teach ya! */117slirp_insque(ifm->m_nextpkt, &slirp->if_batchq);118}119}120121/*122* This prevents us from malloc()ing too many mbufs123*/124if_start(ifm->slirp);125}126127void if_start(Slirp *slirp)128{129uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);130bool from_batchq = false;131struct mbuf *ifm, *ifm_next, *ifqt;132133DEBUG_VERBOSE_CALL("if_start");134135if (slirp->if_start_busy) {136return;137}138slirp->if_start_busy = true;139140struct mbuf *batch_head = NULL;141if (slirp->if_batchq.qh_link != &slirp->if_batchq) {142batch_head = (struct mbuf *)slirp->if_batchq.qh_link;143}144145if (slirp->if_fastq.qh_link != &slirp->if_fastq) {146ifm_next = (struct mbuf *)slirp->if_fastq.qh_link;147} else if (batch_head) {148/* Nothing on fastq, pick up from batchq */149ifm_next = batch_head;150from_batchq = true;151} else {152ifm_next = NULL;153}154155while (ifm_next) {156ifm = ifm_next;157158ifm_next = ifm->m_next;159if ((struct slirp_quehead *)ifm_next == &slirp->if_fastq) {160/* No more packets in fastq, switch to batchq */161ifm_next = batch_head;162from_batchq = true;163}164if ((struct slirp_quehead *)ifm_next == &slirp->if_batchq) {165/* end of batchq */166ifm_next = NULL;167}168169/* Try to send packet unless it already expired */170if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {171/* Packet is delayed due to pending ARP or NDP resolution */172continue;173}174175/* Remove it from the queue */176ifqt = ifm->m_prev;177slirp_remque(ifm);178179/* If there are more packets for this session, re-queue them */180if (ifm->m_nextpkt != ifm) {181struct mbuf *next = ifm->m_nextpkt;182183slirp_insque(next, ifqt);184ifs_remque(ifm);185if (!from_batchq) {186ifm_next = next;187}188}189190/* Update so_queued */191if (ifm->m_so && --ifm->m_so->so_queued == 0) {192/* If there's no more queued, reset nqueued */193ifm->m_so->so_nqueued = 0;194}195196m_free(ifm);197}198199slirp->if_start_busy = false;200}201202203