ip.c revision 31195
16059Samurai/* 26059Samurai * PPP IP Protocol Interface 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198857Srgrimes * 2031195Sbrian * $Id: ip.c,v 1.29 1997/11/12 21:04:21 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Return ICMP message for filterd packet 246059Samurai * and optionaly record it into log. 256059Samurai */ 2630715Sbrian#include <sys/param.h> 2731195Sbrian#include <sys/time.h> 2831195Sbrian#include <sys/select.h> 2931195Sbrian#include <sys/socket.h> 3030715Sbrian#include <netinet/in.h> 316059Samurai#include <netinet/in_systm.h> 326059Samurai#include <netinet/ip.h> 336059Samurai#include <netinet/ip_icmp.h> 346059Samurai#include <netinet/udp.h> 356059Samurai#include <netinet/tcp.h> 3613389Sphk#include <arpa/inet.h> 3731195Sbrian#include <net/if.h> 3831195Sbrian#include <net/if_var.h> 3931195Sbrian#include <net/if_tun.h> 4030715Sbrian 4126031Sbrian#include <alias.h> 4230092Sbrian#include <errno.h> 4330715Sbrian#include <stdio.h> 4430715Sbrian#include <stdlib.h> 4530715Sbrian#include <string.h> 4630733Sbrian#include <termios.h> 4730715Sbrian#include <unistd.h> 4830715Sbrian 4930715Sbrian#include "mbuf.h" 5030715Sbrian#include "log.h" 5130715Sbrian#include "defs.h" 5230715Sbrian#include "timer.h" 5330715Sbrian#include "fsm.h" 5430715Sbrian#include "lcpproto.h" 5530715Sbrian#include "hdlc.h" 5626142Sbrian#include "loadalias.h" 5730715Sbrian#include "command.h" 586059Samurai#include "vars.h" 596059Samurai#include "filter.h" 6026516Sbrian#include "log.h" 6129043Sbrian#include "os.h" 6230715Sbrian#include "ipcp.h" 6330715Sbrian#include "vjcomp.h" 6430715Sbrian#include "lcp.h" 6530733Sbrian#include "modem.h" 6631195Sbrian#include "tun.h" 6730715Sbrian#include "ip.h" 686059Samurai 696059Samuraistatic struct pppTimer IdleTimer; 706059Samurai 7128679Sbrianstatic void 7228679SbrianIdleTimeout() 736059Samurai{ 7426516Sbrian LogPrintf(LogPHASE, "Idle timer expired.\n"); 7526098Sbrian reconnect(RECON_FALSE); 766059Samurai LcpClose(); 776059Samurai} 786059Samurai 796059Samurai/* 806059Samurai * Start Idle timer. If timeout is reached, we call LcpClose() to 816059Samurai * close LCP and link. 826059Samurai */ 836059Samuraivoid 846059SamuraiStartIdleTimer() 856059Samurai{ 8628679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 876059Samurai StopTimer(&IdleTimer); 886059Samurai IdleTimer.func = IdleTimeout; 896059Samurai IdleTimer.load = VarIdleTimeout * SECTICKS; 906059Samurai IdleTimer.state = TIMER_STOPPED; 916059Samurai StartTimer(&IdleTimer); 926059Samurai } 936059Samurai} 946059Samurai 956059Samuraivoid 9626516SbrianUpdateIdleTimer() 9726516Sbrian{ 9829043Sbrian if (OsLinkIsUp()) 9926516Sbrian StartIdleTimer(); 10026516Sbrian} 10126516Sbrian 10226516Sbrianvoid 1036059SamuraiStopIdleTimer() 1046059Samurai{ 1056059Samurai StopTimer(&IdleTimer); 1066059Samurai} 1076059Samurai 1086059Samurai/* 1096059Samurai * If any IP layer traffic is detected, refresh IdleTimer. 1106059Samurai */ 1116059Samuraistatic void 1126059SamuraiRestartIdleTimer() 1136059Samurai{ 11428679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 1156059Samurai StartTimer(&IdleTimer); 1166059Samurai ipIdleSecs = 0; 1176059Samurai } 1186059Samurai} 1196059Samurai 12013733Sdfrstatic u_short interactive_ports[32] = { 12128679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12228679Sbrian 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 1236059Samurai}; 1246059Samurai 12513733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1266059Samurai 1276059Samuraistatic char *TcpFlags[] = { 1286059Samurai "FIN", "SYN", "RST", "PSH", "ACK", "URG", 1296059Samurai}; 1306059Samurai 13128679Sbrianstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 13228679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 1336059Samurai 1346059Samuraistatic int 13528679SbrianPortMatch(int op, u_short pport, u_short rport) 1366059Samurai{ 1376059Samurai switch (op) { 13828679Sbrian case OP_EQ: 13928679Sbrian return (pport == rport); 1406059Samurai case OP_GT: 14128679Sbrian return (pport > rport); 1426059Samurai case OP_LT: 14328679Sbrian return (pport < rport); 1446059Samurai default: 14528679Sbrian return (0); 1466059Samurai } 1476059Samurai} 1486059Samurai 1496059Samurai/* 1506059Samurai * Check a packet against with defined filters 1516059Samurai */ 1526059Samuraistatic int 15328679SbrianFilterCheck(struct ip * pip, int direction) 1546059Samurai{ 1556059Samurai struct filterent *fp = Filters[direction]; 1566059Samurai int gotinfo, cproto, estab, n; 1576059Samurai struct tcphdr *th; 1586059Samurai struct udphdr *uh; 1596059Samurai struct icmp *ih; 1606059Samurai char *ptop; 1616059Samurai u_short sport, dport; 1626059Samurai 1636059Samurai if (fp->action) { 1646059Samurai cproto = gotinfo = estab = 0; 1656059Samurai sport = dport = 0; 1666059Samurai for (n = 0; n < MAXFILTERS; n++) { 1676059Samurai if (fp->action) { 16828679Sbrian /* permit fragments on in and out filter */ 16928679Sbrian if ((direction == FL_IN || direction == FL_OUT) && 17028679Sbrian (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 17128679Sbrian return (A_PERMIT); 17228679Sbrian } 17328679Sbrian LogPrintf(LogDEBUG, "rule = %d\n", n); 17431143Sbrian if ((pip->ip_src.s_addr & fp->smask.s_addr) == 17531143Sbrian (fp->saddr.s_addr & fp->smask.s_addr) && 17631143Sbrian (pip->ip_dst.s_addr & fp->dmask.s_addr) == 17731143Sbrian (fp->daddr.s_addr & fp->dmask.s_addr)) { 1786059Samurai if (fp->proto) { 1796059Samurai if (!gotinfo) { 18028679Sbrian ptop = (char *) pip + (pip->ip_hl << 2); 1816059Samurai 1826059Samurai switch (pip->ip_p) { 1836059Samurai case IPPROTO_ICMP: 18428679Sbrian cproto = P_ICMP; 18528679Sbrian ih = (struct icmp *) ptop; 18628679Sbrian sport = ih->icmp_type; 18728679Sbrian estab = 1; 1886059Samurai break; 1896059Samurai case IPPROTO_UDP: 19028679Sbrian cproto = P_UDP; 19128679Sbrian uh = (struct udphdr *) ptop; 19228679Sbrian sport = ntohs(uh->uh_sport); 19328679Sbrian dport = ntohs(uh->uh_dport); 1946059Samurai estab = 1; 1956059Samurai break; 1966059Samurai case IPPROTO_TCP: 19728679Sbrian cproto = P_TCP; 19828679Sbrian th = (struct tcphdr *) ptop; 19928679Sbrian sport = ntohs(th->th_sport); 20028679Sbrian dport = ntohs(th->th_dport); 2016059Samurai estab = (th->th_flags & TH_ACK); 20228679Sbrian if (estab == 0) 20328679Sbrian LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 20428679Sbrian th->th_flags, sport, dport); 2056059Samurai break; 2066059Samurai default: 20728679Sbrian return (A_DENY);/* We'll block unknown type of packet */ 2086059Samurai } 2096059Samurai gotinfo = 1; 21028679Sbrian LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 21128679Sbrian " dstop = %d, estab = %d\n", direction, cproto, 21228679Sbrian fp->opt.srcop, fp->opt.dstop, estab); 2136059Samurai } 21426516Sbrian LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 21528679Sbrian " dport = %d\n", n, cproto, sport, dport); 21626516Sbrian LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 21726516Sbrian 2186059Samurai if (cproto == fp->proto) { 2196059Samurai if ((fp->opt.srcop == OP_NONE || 22028679Sbrian PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 22128679Sbrian && 2226059Samurai (fp->opt.dstop == OP_NONE || 22328679Sbrian PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 22428679Sbrian && 2256059Samurai (fp->opt.estab == 0 || estab)) { 22628679Sbrian return (fp->action); 2276059Samurai } 2286059Samurai } 2296059Samurai } else { 2306059Samurai /* Address is mached. Make a decision. */ 23126516Sbrian LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 23228679Sbrian return (fp->action); 2336059Samurai } 2346059Samurai } 2356059Samurai } 2366059Samurai fp++; 2376059Samurai } 23828679Sbrian return (A_DENY); /* No rule is mached. Deny this packet */ 2396059Samurai } 24028679Sbrian return (A_PERMIT); /* No rule is given. Permit this packet */ 2416059Samurai} 2426059Samurai 2436059Samuraistatic void 24428679SbrianIcmpError(struct ip * pip, int code) 2456059Samurai{ 2466059Samurai#ifdef notdef 2476059Samurai struct mbuf *bp; 2486059Samurai 2496059Samurai if (pip->ip_p != IPPROTO_ICMP) { 2506059Samurai bp = mballoc(cnt, MB_IPIN); 25130715Sbrian memcpy(MBUF_CTOP(bp), ptr, cnt); 25213733Sdfr SendPppFrame(bp); 2536059Samurai RestartIdleTimer(); 2546059Samurai ipOutOctets += cnt; 2556059Samurai } 2566059Samurai#endif 2576059Samurai} 2586059Samurai 2596059Samurai/* 2606059Samurai * For debugging aid. 2616059Samurai */ 2626059Samuraiint 26328679SbrianPacketCheck(char *cp, int nb, int direction) 2646059Samurai{ 2656059Samurai struct ip *pip; 2666059Samurai struct tcphdr *th; 2676059Samurai struct udphdr *uh; 2686059Samurai struct icmp *icmph; 2696059Samurai char *ptop; 2706059Samurai int mask, len, n; 2716059Samurai int pri = PRI_NORMAL; 27226692Sbrian int logit, loglen; 27326692Sbrian static char logbuf[200]; 2746059Samurai 27526516Sbrian logit = LogIsKept(LogTCPIP); 27626692Sbrian loglen = 0; 2776059Samurai 27828679Sbrian pip = (struct ip *) cp; 2798857Srgrimes 28026692Sbrian if (logit && loglen < sizeof logbuf) { 28128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 28228679Sbrian Direction[direction]); 28328679Sbrian loglen += strlen(logbuf + loglen); 28426692Sbrian } 2856059Samurai ptop = (cp + (pip->ip_hl << 2)); 2866059Samurai 2876059Samurai switch (pip->ip_p) { 2886059Samurai case IPPROTO_ICMP: 28926692Sbrian if (logit && loglen < sizeof logbuf) { 29028679Sbrian icmph = (struct icmp *) ptop; 29128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29228679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 29328679Sbrian loglen += strlen(logbuf + loglen); 29428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29528679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 29628679Sbrian loglen += strlen(logbuf + loglen); 2976059Samurai } 2986059Samurai break; 2996059Samurai case IPPROTO_UDP: 30026692Sbrian if (logit && loglen < sizeof logbuf) { 30128679Sbrian uh = (struct udphdr *) ptop; 30228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30328679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 30428679Sbrian loglen += strlen(logbuf + loglen); 30528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30628679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 30728679Sbrian loglen += strlen(logbuf + loglen); 3086059Samurai } 3096059Samurai break; 3106059Samurai case IPPROTO_TCP: 31128679Sbrian th = (struct tcphdr *) ptop; 3126059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 3136059Samurai pri = PRI_FAST; 31413733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 3156059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 31628679Sbrian pri = PRI_FAST; 3176059Samurai } 31826692Sbrian if (logit && loglen < sizeof logbuf) { 3196059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 32028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32128679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 32228679Sbrian loglen += strlen(logbuf + loglen); 32328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32428679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 32528679Sbrian loglen += strlen(logbuf + loglen); 3266059Samurai n = 0; 3276059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 32826692Sbrian if (th->th_flags & mask) { 32928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 33028679Sbrian loglen += strlen(logbuf + loglen); 33128679Sbrian } 3326059Samurai n++; 3336059Samurai } 33428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 33528679Sbrian " seq:%x ack:%x (%d/%d)", 33628679Sbrian ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 33728679Sbrian loglen += strlen(logbuf + loglen); 3386059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 33928679Sbrian u_short *sp; 3406059Samurai 3416059Samurai ptop += 20; 34228679Sbrian sp = (u_short *) ptop; 34326692Sbrian if (ntohs(sp[0]) == 0x0204) { 34428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 34528679Sbrian " MSS = %d", ntohs(sp[1])); 34628679Sbrian loglen += strlen(logbuf + loglen); 34728679Sbrian } 3486059Samurai } 3496059Samurai } 3506059Samurai break; 3516059Samurai } 35226692Sbrian 35313733Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 35431142Sbrian if (logit) 35531142Sbrian LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); 35628679Sbrian if (direction == 0) 35728679Sbrian IcmpError(pip, pri); 35828679Sbrian return (-1); 3596059Samurai } else { 36028679Sbrian if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 36131142Sbrian if (logit) 36231142Sbrian LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 36330715Sbrian ipKeepAlive = 0; 3646735Samurai } else { 36531142Sbrian if (logit) 36631142Sbrian LogPrintf(LogTCPIP, "%s\n", logbuf); 36730715Sbrian ipKeepAlive = 1; 3686735Samurai } 36928679Sbrian return (pri); 3706059Samurai } 3716059Samurai} 3726059Samurai 3736059Samuraivoid 37428679SbrianIpInput(struct mbuf * bp) 37528679Sbrian{ /* IN: Pointer to IP pakcet */ 3766059Samurai u_char *cp; 3776059Samurai struct mbuf *wp; 3786059Samurai int nb, nw; 37931195Sbrian struct tun_data tun, *frag; 3806059Samurai 38131195Sbrian tun_fill_header(tun, AF_INET); 38231195Sbrian cp = tun.data; 3836059Samurai nb = 0; 38428679Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 38530715Sbrian memcpy(cp, MBUF_CTOP(wp), wp->cnt); 3866059Samurai cp += wp->cnt; 3876059Samurai nb += wp->cnt; 3886059Samurai } 3896059Samurai 39020365Sjkh if (mode & MODE_ALIAS) { 39126031Sbrian int iresult; 39226031Sbrian char *fptr; 39326031Sbrian 39431195Sbrian iresult = VarPacketAliasIn(tun.data, sizeof tun.data); 39531195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 39626031Sbrian 39726031Sbrian if (nb > MAX_MRU) { 39826516Sbrian LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 39926031Sbrian pfree(bp); 40026031Sbrian return; 40126031Sbrian } 40226031Sbrian if (iresult == PKT_ALIAS_OK 40328679Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 40431195Sbrian if (PacketCheck(tun.data, nb, FL_IN) < 0) { 40528679Sbrian pfree(bp); 40628679Sbrian return; 40726031Sbrian } 40826031Sbrian ipInOctets += nb; 40926031Sbrian 41031195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 41131195Sbrian nb += sizeof(tun)-sizeof(tun.data); 41231195Sbrian nw = write(tun_out, &tun, nb); 41326031Sbrian if (nw != nb) 41430092Sbrian if (nw == -1) 41530092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 41630092Sbrian strerror(errno)); 41730092Sbrian else 41830092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 41926031Sbrian 42026031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 42131195Sbrian while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) { 42231195Sbrian VarPacketAliasFragmentIn(tun.data, fptr); 42328679Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 42431195Sbrian frag = (struct tun_data *)((char *)fptr-sizeof(tun)+sizeof(tun.data)); 42531195Sbrian nb += sizeof(tun)-sizeof(tun.data); 42631195Sbrian nw = write(tun_out, frag, nb); 42728679Sbrian if (nw != nb) 42830092Sbrian if (nw == -1) 42930092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 43030092Sbrian strerror(errno)); 43130092Sbrian else 43230092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 43331195Sbrian free(frag); 43428679Sbrian } 43526031Sbrian } 43628679Sbrian } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 43731195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 43831195Sbrian nb += sizeof(tun)-sizeof(tun.data); 43931195Sbrian frag = (struct tun_data *)malloc(nb); 44031195Sbrian if (frag == NULL) 44128679Sbrian LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 44226031Sbrian else { 44331195Sbrian tun_fill_header(*frag, AF_INET); 44431195Sbrian memcpy(frag->data, tun.data, nb-sizeof(tun)+sizeof(tun.data)); 44531195Sbrian VarPacketAliasSaveFragment(frag->data); 44626031Sbrian } 44726031Sbrian } 44828679Sbrian } else { /* no aliasing */ 44931195Sbrian if (PacketCheck(tun.data, nb, FL_IN) < 0) { 45026031Sbrian pfree(bp); 45126031Sbrian return; 45226031Sbrian } 45326031Sbrian ipInOctets += nb; 45431195Sbrian nb += sizeof(tun)-sizeof(tun.data); 45531195Sbrian nw = write(tun_out, &tun, nb); 45626031Sbrian if (nw != nb) 45730092Sbrian if (nw == -1) 45830092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 45930092Sbrian else 46030092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 4616059Samurai } 4626059Samurai pfree(bp); 4636059Samurai 4646059Samurai RestartIdleTimer(); 4656059Samurai} 4666059Samurai 46728679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1]; 4686059Samurai 4696059Samuraivoid 47028679SbrianIpEnqueue(int pri, char *ptr, int count) 4716059Samurai{ 4726059Samurai struct mbuf *bp; 4736059Samurai 4746059Samurai bp = mballoc(count, MB_IPQ); 47530715Sbrian memcpy(MBUF_CTOP(bp), ptr, count); 4766059Samurai Enqueue(&IpOutputQueues[pri], bp); 4776059Samurai} 4786059Samurai 47930715Sbrian#if 0 4808857Srgrimesint 4817001SamuraiIsIpEnqueued() 4827001Samurai{ 4837001Samurai struct mqueue *queue; 48430715Sbrian int exist = 0; 48528679Sbrian 48613733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 48728679Sbrian if (queue->qlen > 0) { 48830715Sbrian exist = 1; 48928679Sbrian break; 49028679Sbrian } 4917001Samurai } 49228679Sbrian return (exist); 4937001Samurai} 49430715Sbrian#endif 4957001Samurai 4966059Samuraivoid 4976059SamuraiIpStartOutput() 4986059Samurai{ 4996059Samurai struct mqueue *queue; 5006059Samurai struct mbuf *bp; 50125630Sbrian int cnt; 5026059Samurai 5036059Samurai if (IpcpFsm.state != ST_OPENED) 5046059Samurai return; 50513733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 5066059Samurai if (queue->top) { 5076059Samurai bp = Dequeue(queue); 5086059Samurai if (bp) { 5096059Samurai cnt = plength(bp); 51013733Sdfr SendPppFrame(bp); 5116059Samurai RestartIdleTimer(); 5126059Samurai ipOutOctets += cnt; 51313733Sdfr break; 51428679Sbrian } 5156059Samurai } 5166059Samurai } 5176059Samurai} 518