|
|
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.