ip.c revision 31962
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 * 2031962Sbrian * $Id: ip.c,v 1.32 1997/11/22 03:37:33 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> 3831343Sbrian#ifdef __FreeBSD__ 3931195Sbrian#include <net/if_var.h> 4031343Sbrian#endif 4131195Sbrian#include <net/if_tun.h> 4230715Sbrian 4331343Sbrian#ifndef NOALIAS 4426031Sbrian#include <alias.h> 4531343Sbrian#endif 4630092Sbrian#include <errno.h> 4730715Sbrian#include <stdio.h> 4830715Sbrian#include <stdlib.h> 4930715Sbrian#include <string.h> 5030733Sbrian#include <termios.h> 5130715Sbrian#include <unistd.h> 5230715Sbrian 5331343Sbrian#include "command.h" 5430715Sbrian#include "mbuf.h" 5530715Sbrian#include "log.h" 5630715Sbrian#include "defs.h" 5730715Sbrian#include "timer.h" 5830715Sbrian#include "fsm.h" 5930715Sbrian#include "lcpproto.h" 6030715Sbrian#include "hdlc.h" 6126142Sbrian#include "loadalias.h" 626059Samurai#include "vars.h" 636059Samurai#include "filter.h" 6429043Sbrian#include "os.h" 6530715Sbrian#include "ipcp.h" 6630715Sbrian#include "vjcomp.h" 6730715Sbrian#include "lcp.h" 6830733Sbrian#include "modem.h" 6931195Sbrian#include "tun.h" 7030715Sbrian#include "ip.h" 716059Samurai 726059Samuraistatic struct pppTimer IdleTimer; 736059Samurai 7428679Sbrianstatic void 7531343SbrianIdleTimeout(void *v) 766059Samurai{ 7726516Sbrian LogPrintf(LogPHASE, "Idle timer expired.\n"); 7826098Sbrian reconnect(RECON_FALSE); 796059Samurai LcpClose(); 806059Samurai} 816059Samurai 826059Samurai/* 836059Samurai * Start Idle timer. If timeout is reached, we call LcpClose() to 846059Samurai * close LCP and link. 856059Samurai */ 866059Samuraivoid 876059SamuraiStartIdleTimer() 886059Samurai{ 8928679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 906059Samurai StopTimer(&IdleTimer); 916059Samurai IdleTimer.func = IdleTimeout; 926059Samurai IdleTimer.load = VarIdleTimeout * SECTICKS; 936059Samurai IdleTimer.state = TIMER_STOPPED; 946059Samurai StartTimer(&IdleTimer); 956059Samurai } 966059Samurai} 976059Samurai 986059Samuraivoid 9926516SbrianUpdateIdleTimer() 10026516Sbrian{ 10129043Sbrian if (OsLinkIsUp()) 10226516Sbrian StartIdleTimer(); 10326516Sbrian} 10426516Sbrian 10526516Sbrianvoid 1066059SamuraiStopIdleTimer() 1076059Samurai{ 1086059Samurai StopTimer(&IdleTimer); 1096059Samurai} 1106059Samurai 1116059Samurai/* 1126059Samurai * If any IP layer traffic is detected, refresh IdleTimer. 1136059Samurai */ 1146059Samuraistatic void 11531343SbrianRestartIdleTimer(void) 1166059Samurai{ 11728679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 1186059Samurai StartTimer(&IdleTimer); 1196059Samurai ipIdleSecs = 0; 1206059Samurai } 1216059Samurai} 1226059Samurai 12331343Sbrianstatic const u_short interactive_ports[32] = { 12428679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12528679Sbrian 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 1266059Samurai}; 1276059Samurai 12813733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1296059Samurai 13031343Sbrianstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 1316059Samurai 13231343Sbrianstatic const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 13328679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 1346059Samurai 1356059Samuraistatic int 13628679SbrianPortMatch(int op, u_short pport, u_short rport) 1376059Samurai{ 1386059Samurai switch (op) { 13928679Sbrian case OP_EQ: 14028679Sbrian return (pport == rport); 1416059Samurai case OP_GT: 14228679Sbrian return (pport > rport); 1436059Samurai case OP_LT: 14428679Sbrian return (pport < rport); 1456059Samurai default: 14628679Sbrian return (0); 1476059Samurai } 1486059Samurai} 1496059Samurai 1506059Samurai/* 1516059Samurai * Check a packet against with defined filters 1526059Samurai */ 1536059Samuraistatic int 15428679SbrianFilterCheck(struct ip * pip, int direction) 1556059Samurai{ 1566059Samurai struct filterent *fp = Filters[direction]; 1576059Samurai int gotinfo, cproto, estab, n; 1586059Samurai struct tcphdr *th; 1596059Samurai struct udphdr *uh; 1606059Samurai struct icmp *ih; 1616059Samurai char *ptop; 1626059Samurai u_short sport, dport; 1636059Samurai 1646059Samurai if (fp->action) { 1656059Samurai cproto = gotinfo = estab = 0; 1666059Samurai sport = dport = 0; 1676059Samurai for (n = 0; n < MAXFILTERS; n++) { 1686059Samurai if (fp->action) { 16928679Sbrian /* permit fragments on in and out filter */ 17028679Sbrian if ((direction == FL_IN || direction == FL_OUT) && 17128679Sbrian (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 17228679Sbrian return (A_PERMIT); 17328679Sbrian } 17428679Sbrian LogPrintf(LogDEBUG, "rule = %d\n", n); 17531143Sbrian if ((pip->ip_src.s_addr & fp->smask.s_addr) == 17631143Sbrian (fp->saddr.s_addr & fp->smask.s_addr) && 17731143Sbrian (pip->ip_dst.s_addr & fp->dmask.s_addr) == 17831143Sbrian (fp->daddr.s_addr & fp->dmask.s_addr)) { 1796059Samurai if (fp->proto) { 1806059Samurai if (!gotinfo) { 18128679Sbrian ptop = (char *) pip + (pip->ip_hl << 2); 1826059Samurai 1836059Samurai switch (pip->ip_p) { 1846059Samurai case IPPROTO_ICMP: 18528679Sbrian cproto = P_ICMP; 18628679Sbrian ih = (struct icmp *) ptop; 18728679Sbrian sport = ih->icmp_type; 18828679Sbrian estab = 1; 1896059Samurai break; 1906059Samurai case IPPROTO_UDP: 19128679Sbrian cproto = P_UDP; 19228679Sbrian uh = (struct udphdr *) ptop; 19328679Sbrian sport = ntohs(uh->uh_sport); 19428679Sbrian dport = ntohs(uh->uh_dport); 1956059Samurai estab = 1; 1966059Samurai break; 1976059Samurai case IPPROTO_TCP: 19828679Sbrian cproto = P_TCP; 19928679Sbrian th = (struct tcphdr *) ptop; 20028679Sbrian sport = ntohs(th->th_sport); 20128679Sbrian dport = ntohs(th->th_dport); 2026059Samurai estab = (th->th_flags & TH_ACK); 20328679Sbrian if (estab == 0) 20428679Sbrian LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 20528679Sbrian th->th_flags, sport, dport); 2066059Samurai break; 2076059Samurai default: 20828679Sbrian return (A_DENY);/* We'll block unknown type of packet */ 2096059Samurai } 2106059Samurai gotinfo = 1; 21128679Sbrian LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 21228679Sbrian " dstop = %d, estab = %d\n", direction, cproto, 21328679Sbrian fp->opt.srcop, fp->opt.dstop, estab); 2146059Samurai } 21526516Sbrian LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 21628679Sbrian " dport = %d\n", n, cproto, sport, dport); 21726516Sbrian LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 21826516Sbrian 2196059Samurai if (cproto == fp->proto) { 2206059Samurai if ((fp->opt.srcop == OP_NONE || 22128679Sbrian PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 22228679Sbrian && 2236059Samurai (fp->opt.dstop == OP_NONE || 22428679Sbrian PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 22528679Sbrian && 2266059Samurai (fp->opt.estab == 0 || estab)) { 22728679Sbrian return (fp->action); 2286059Samurai } 2296059Samurai } 2306059Samurai } else { 2316059Samurai /* Address is mached. Make a decision. */ 23226516Sbrian LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 23328679Sbrian return (fp->action); 2346059Samurai } 2356059Samurai } 2366059Samurai } 2376059Samurai fp++; 2386059Samurai } 23928679Sbrian return (A_DENY); /* No rule is mached. Deny this packet */ 2406059Samurai } 24128679Sbrian return (A_PERMIT); /* No rule is given. Permit this packet */ 2426059Samurai} 2436059Samurai 2446059Samuraistatic void 24528679SbrianIcmpError(struct ip * pip, int code) 2466059Samurai{ 2476059Samurai#ifdef notdef 2486059Samurai struct mbuf *bp; 2496059Samurai 2506059Samurai if (pip->ip_p != IPPROTO_ICMP) { 2516059Samurai bp = mballoc(cnt, MB_IPIN); 25230715Sbrian memcpy(MBUF_CTOP(bp), ptr, cnt); 25313733Sdfr SendPppFrame(bp); 2546059Samurai RestartIdleTimer(); 25531272Sbrian IpcpAddOutOctets(cnt); 2566059Samurai } 2576059Samurai#endif 2586059Samurai} 2596059Samurai 2606059Samurai/* 2616059Samurai * For debugging aid. 2626059Samurai */ 2636059Samuraiint 26428679SbrianPacketCheck(char *cp, int nb, int direction) 2656059Samurai{ 2666059Samurai struct ip *pip; 2676059Samurai struct tcphdr *th; 2686059Samurai struct udphdr *uh; 2696059Samurai struct icmp *icmph; 2706059Samurai char *ptop; 2716059Samurai int mask, len, n; 2726059Samurai int pri = PRI_NORMAL; 27326692Sbrian int logit, loglen; 27426692Sbrian static char logbuf[200]; 2756059Samurai 27626516Sbrian logit = LogIsKept(LogTCPIP); 27726692Sbrian loglen = 0; 2786059Samurai 27928679Sbrian pip = (struct ip *) cp; 2808857Srgrimes 28126692Sbrian if (logit && loglen < sizeof logbuf) { 28228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 28328679Sbrian Direction[direction]); 28428679Sbrian loglen += strlen(logbuf + loglen); 28526692Sbrian } 2866059Samurai ptop = (cp + (pip->ip_hl << 2)); 2876059Samurai 2886059Samurai switch (pip->ip_p) { 2896059Samurai case IPPROTO_ICMP: 29026692Sbrian if (logit && loglen < sizeof logbuf) { 29128679Sbrian icmph = (struct icmp *) ptop; 29228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29328679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 29428679Sbrian loglen += strlen(logbuf + loglen); 29528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29628679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 29728679Sbrian loglen += strlen(logbuf + loglen); 2986059Samurai } 2996059Samurai break; 3006059Samurai case IPPROTO_UDP: 30126692Sbrian if (logit && loglen < sizeof logbuf) { 30228679Sbrian uh = (struct udphdr *) ptop; 30328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30428679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 30528679Sbrian loglen += strlen(logbuf + loglen); 30628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30728679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 30828679Sbrian loglen += strlen(logbuf + loglen); 3096059Samurai } 3106059Samurai break; 3116059Samurai case IPPROTO_TCP: 31228679Sbrian th = (struct tcphdr *) ptop; 3136059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 3146059Samurai pri = PRI_FAST; 31513733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 3166059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 31728679Sbrian pri = PRI_FAST; 3186059Samurai } 31926692Sbrian if (logit && loglen < sizeof logbuf) { 3206059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 32128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32228679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 32328679Sbrian loglen += strlen(logbuf + loglen); 32428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32528679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 32628679Sbrian loglen += strlen(logbuf + loglen); 3276059Samurai n = 0; 3286059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 32926692Sbrian if (th->th_flags & mask) { 33028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 33128679Sbrian loglen += strlen(logbuf + loglen); 33228679Sbrian } 3336059Samurai n++; 3346059Samurai } 33528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 33628679Sbrian " seq:%x ack:%x (%d/%d)", 33728679Sbrian ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 33828679Sbrian loglen += strlen(logbuf + loglen); 3396059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 34028679Sbrian u_short *sp; 3416059Samurai 3426059Samurai ptop += 20; 34328679Sbrian sp = (u_short *) ptop; 34426692Sbrian if (ntohs(sp[0]) == 0x0204) { 34528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 34628679Sbrian " MSS = %d", ntohs(sp[1])); 34728679Sbrian loglen += strlen(logbuf + loglen); 34828679Sbrian } 3496059Samurai } 3506059Samurai } 3516059Samurai break; 3526059Samurai } 35326692Sbrian 35413733Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 35531142Sbrian if (logit) 35631142Sbrian LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); 35728679Sbrian if (direction == 0) 35828679Sbrian IcmpError(pip, pri); 35928679Sbrian return (-1); 3606059Samurai } else { 36128679Sbrian if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 36231142Sbrian if (logit) 36331142Sbrian LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 36430715Sbrian ipKeepAlive = 0; 3656735Samurai } else { 36631142Sbrian if (logit) 36731142Sbrian LogPrintf(LogTCPIP, "%s\n", logbuf); 36830715Sbrian ipKeepAlive = 1; 3696735Samurai } 37028679Sbrian return (pri); 3716059Samurai } 3726059Samurai} 3736059Samurai 3746059Samuraivoid 37528679SbrianIpInput(struct mbuf * bp) 37628679Sbrian{ /* IN: Pointer to IP pakcet */ 3776059Samurai u_char *cp; 3786059Samurai struct mbuf *wp; 3796059Samurai int nb, nw; 38031343Sbrian struct tun_data tun; 3816059Samurai 38231195Sbrian tun_fill_header(tun, AF_INET); 38331195Sbrian cp = tun.data; 3846059Samurai nb = 0; 38528679Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 38630715Sbrian memcpy(cp, MBUF_CTOP(wp), wp->cnt); 3876059Samurai cp += wp->cnt; 3886059Samurai nb += wp->cnt; 3896059Samurai } 3906059Samurai 39131343Sbrian#ifndef NOALIAS 39220365Sjkh if (mode & MODE_ALIAS) { 39331343Sbrian struct tun_data *frag; 39426031Sbrian int iresult; 39526031Sbrian char *fptr; 39626031Sbrian 39731195Sbrian iresult = VarPacketAliasIn(tun.data, sizeof tun.data); 39831195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 39926031Sbrian 40026031Sbrian if (nb > MAX_MRU) { 40126516Sbrian LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 40226031Sbrian pfree(bp); 40326031Sbrian return; 40426031Sbrian } 40526031Sbrian if (iresult == PKT_ALIAS_OK 40628679Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 40731195Sbrian if (PacketCheck(tun.data, nb, FL_IN) < 0) { 40828679Sbrian pfree(bp); 40928679Sbrian return; 41026031Sbrian } 41131272Sbrian IpcpAddInOctets(nb); 41226031Sbrian 41331195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 41431962Sbrian nb += sizeof tun - sizeof tun.data; 41531195Sbrian nw = write(tun_out, &tun, nb); 41626031Sbrian if (nw != nb) 41730092Sbrian if (nw == -1) 41830092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 41930092Sbrian strerror(errno)); 42030092Sbrian else 42130092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 42226031Sbrian 42326031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 42431195Sbrian while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) { 42531195Sbrian VarPacketAliasFragmentIn(tun.data, fptr); 42628679Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 42731962Sbrian frag = (struct tun_data *) 42831962Sbrian ((char *)fptr - sizeof tun + sizeof tun.data); 42931962Sbrian nb += sizeof tun - sizeof tun.data; 43031195Sbrian nw = write(tun_out, frag, nb); 43128679Sbrian if (nw != nb) 43230092Sbrian if (nw == -1) 43330092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 43430092Sbrian strerror(errno)); 43530092Sbrian else 43630092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 43731195Sbrian free(frag); 43828679Sbrian } 43926031Sbrian } 44028679Sbrian } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 44131195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 44231962Sbrian nb += sizeof tun - sizeof tun.data; 44331195Sbrian frag = (struct tun_data *)malloc(nb); 44431195Sbrian if (frag == NULL) 44528679Sbrian LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 44626031Sbrian else { 44731195Sbrian tun_fill_header(*frag, AF_INET); 44831962Sbrian memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data); 44931195Sbrian VarPacketAliasSaveFragment(frag->data); 45026031Sbrian } 45126031Sbrian } 45231343Sbrian } else 45331343Sbrian#endif /* #ifndef NOALIAS */ 45431343Sbrian { /* no aliasing */ 45531195Sbrian if (PacketCheck(tun.data, nb, FL_IN) < 0) { 45626031Sbrian pfree(bp); 45726031Sbrian return; 45826031Sbrian } 45931272Sbrian IpcpAddInOctets(nb); 46031962Sbrian nb += sizeof tun - sizeof tun.data; 46131195Sbrian nw = write(tun_out, &tun, nb); 46226031Sbrian if (nw != nb) 46330092Sbrian if (nw == -1) 46430092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 46530092Sbrian else 46630092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 4676059Samurai } 4686059Samurai pfree(bp); 4696059Samurai 4706059Samurai RestartIdleTimer(); 4716059Samurai} 4726059Samurai 47328679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1]; 4746059Samurai 4756059Samuraivoid 47628679SbrianIpEnqueue(int pri, char *ptr, int count) 4776059Samurai{ 4786059Samurai struct mbuf *bp; 4796059Samurai 4806059Samurai bp = mballoc(count, MB_IPQ); 48130715Sbrian memcpy(MBUF_CTOP(bp), ptr, count); 4826059Samurai Enqueue(&IpOutputQueues[pri], bp); 4836059Samurai} 4846059Samurai 48530715Sbrian#if 0 4868857Srgrimesint 4877001SamuraiIsIpEnqueued() 4887001Samurai{ 4897001Samurai struct mqueue *queue; 49030715Sbrian int exist = 0; 49128679Sbrian 49213733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 49328679Sbrian if (queue->qlen > 0) { 49430715Sbrian exist = 1; 49528679Sbrian break; 49628679Sbrian } 4977001Samurai } 49828679Sbrian return (exist); 4997001Samurai} 50030715Sbrian#endif 5017001Samurai 5026059Samuraivoid 5036059SamuraiIpStartOutput() 5046059Samurai{ 5056059Samurai struct mqueue *queue; 5066059Samurai struct mbuf *bp; 50725630Sbrian int cnt; 5086059Samurai 5096059Samurai if (IpcpFsm.state != ST_OPENED) 5106059Samurai return; 51113733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 5126059Samurai if (queue->top) { 5136059Samurai bp = Dequeue(queue); 5146059Samurai if (bp) { 5156059Samurai cnt = plength(bp); 51613733Sdfr SendPppFrame(bp); 5176059Samurai RestartIdleTimer(); 51831272Sbrian IpcpAddOutOctets(cnt); 51913733Sdfr break; 52028679Sbrian } 5216059Samurai } 5226059Samurai } 5236059Samurai} 524