ip.c revision 36285
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 * 2036285Sbrian * $Id: ip.c,v 1.38.2.26 1998/05/06 23:50:11 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Return ICMP message for filterd packet 246059Samurai * and optionaly record it into log. 256059Samurai */ 2636285Sbrian#include <sys/types.h> 2731195Sbrian#include <sys/socket.h> 2830715Sbrian#include <netinet/in.h> 296059Samurai#include <netinet/in_systm.h> 306059Samurai#include <netinet/ip.h> 316059Samurai#include <netinet/ip_icmp.h> 326059Samurai#include <netinet/udp.h> 336059Samurai#include <netinet/tcp.h> 3413389Sphk#include <arpa/inet.h> 3536285Sbrian#include <net/if_tun.h> 3636285Sbrian#include <sys/un.h> 3730715Sbrian 3831343Sbrian#ifndef NOALIAS 3926031Sbrian#include <alias.h> 4031343Sbrian#endif 4130092Sbrian#include <errno.h> 4230715Sbrian#include <stdio.h> 4330715Sbrian#include <stdlib.h> 4430715Sbrian#include <string.h> 4530715Sbrian#include <unistd.h> 4630715Sbrian 4730715Sbrian#include "mbuf.h" 4830715Sbrian#include "log.h" 4930715Sbrian#include "defs.h" 5030715Sbrian#include "timer.h" 5130715Sbrian#include "fsm.h" 5236285Sbrian#include "lqr.h" 5330715Sbrian#include "hdlc.h" 5426142Sbrian#include "loadalias.h" 5536285Sbrian#include "throughput.h" 5636285Sbrian#include "iplist.h" 5736285Sbrian#include "slcompress.h" 5836285Sbrian#include "ipcp.h" 596059Samurai#include "filter.h" 6036285Sbrian#include "descriptor.h" 6136285Sbrian#include "lcp.h" 6236285Sbrian#include "ccp.h" 6336285Sbrian#include "link.h" 6436285Sbrian#include "mp.h" 6536285Sbrian#include "bundle.h" 6630715Sbrian#include "vjcomp.h" 6731195Sbrian#include "tun.h" 6830715Sbrian#include "ip.h" 696059Samurai 7031343Sbrianstatic const u_short interactive_ports[32] = { 7128679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7228679Sbrian 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 736059Samurai}; 746059Samurai 7513733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 766059Samurai 7731343Sbrianstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 786059Samurai 796059Samuraistatic int 8028679SbrianPortMatch(int op, u_short pport, u_short rport) 816059Samurai{ 826059Samurai switch (op) { 8328679Sbrian case OP_EQ: 8428679Sbrian return (pport == rport); 856059Samurai case OP_GT: 8628679Sbrian return (pport > rport); 876059Samurai case OP_LT: 8828679Sbrian return (pport < rport); 896059Samurai default: 9028679Sbrian return (0); 916059Samurai } 926059Samurai} 936059Samurai 946059Samurai/* 956059Samurai * Check a packet against with defined filters 966059Samurai */ 976059Samuraistatic int 9836285SbrianFilterCheck(struct ip *pip, struct filter *filter) 996059Samurai{ 10036285Sbrian int gotinfo, cproto, estab, syn, finrst, n, len, didname; 1016059Samurai struct tcphdr *th; 1026059Samurai struct udphdr *uh; 1036059Samurai struct icmp *ih; 1046059Samurai char *ptop; 1056059Samurai u_short sport, dport; 10636285Sbrian struct filterent *fp = filter->rule; 10736285Sbrian char dbuff[100]; 1086059Samurai 1096059Samurai if (fp->action) { 11036285Sbrian cproto = gotinfo = estab = syn = finrst = didname = 0; 1116059Samurai sport = dport = 0; 1126059Samurai for (n = 0; n < MAXFILTERS; n++) { 1136059Samurai if (fp->action) { 11428679Sbrian /* permit fragments on in and out filter */ 11536285Sbrian if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0) 11628679Sbrian return (A_PERMIT); 11736285Sbrian 11836285Sbrian if (!didname) 11936285Sbrian log_Printf(LogDEBUG, "%s filter:\n", filter->name); 12036285Sbrian didname = 1; 12136285Sbrian 12231143Sbrian if ((pip->ip_src.s_addr & fp->smask.s_addr) == 12331143Sbrian (fp->saddr.s_addr & fp->smask.s_addr) && 12431143Sbrian (pip->ip_dst.s_addr & fp->dmask.s_addr) == 12531143Sbrian (fp->daddr.s_addr & fp->dmask.s_addr)) { 1266059Samurai if (fp->proto) { 1276059Samurai if (!gotinfo) { 12828679Sbrian ptop = (char *) pip + (pip->ip_hl << 2); 1296059Samurai 1306059Samurai switch (pip->ip_p) { 1316059Samurai case IPPROTO_ICMP: 13228679Sbrian cproto = P_ICMP; 13328679Sbrian ih = (struct icmp *) ptop; 13428679Sbrian sport = ih->icmp_type; 13536285Sbrian estab = syn = finrst = -1; 13636285Sbrian if (log_IsKept(LogDEBUG)) 13736285Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 1386059Samurai break; 1396059Samurai case IPPROTO_UDP: 14028679Sbrian cproto = P_UDP; 14128679Sbrian uh = (struct udphdr *) ptop; 14228679Sbrian sport = ntohs(uh->uh_sport); 14328679Sbrian dport = ntohs(uh->uh_dport); 14436285Sbrian estab = syn = finrst = -1; 14536285Sbrian if (log_IsKept(LogDEBUG)) 14636285Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 14736285Sbrian sport, dport); 1486059Samurai break; 1496059Samurai case IPPROTO_TCP: 15028679Sbrian cproto = P_TCP; 15128679Sbrian th = (struct tcphdr *) ptop; 15228679Sbrian sport = ntohs(th->th_sport); 15328679Sbrian dport = ntohs(th->th_dport); 1546059Samurai estab = (th->th_flags & TH_ACK); 15536285Sbrian syn = (th->th_flags & TH_SYN); 15636285Sbrian finrst = (th->th_flags & (TH_FIN|TH_RST)); 15736285Sbrian if (log_IsKept(LogDEBUG) && !estab) 15836285Sbrian snprintf(dbuff, sizeof dbuff, 15936285Sbrian "flags = %02x, sport = %d, dport = %d", 16036285Sbrian th->th_flags, sport, dport); 1616059Samurai break; 1626059Samurai default: 16336285Sbrian return (A_DENY); /* We'll block unknown type of packet */ 1646059Samurai } 16536285Sbrian if (log_IsKept(LogDEBUG)) { 16636285Sbrian if (estab != -1) { 16736285Sbrian len = strlen(dbuff); 16836285Sbrian snprintf(dbuff + len, sizeof dbuff - len, 16936285Sbrian ", estab = %d, syn = %d, finrst = %d", 17036285Sbrian estab, syn, finrst); 17136285Sbrian } 17236285Sbrian log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 17336285Sbrian filter_Proto2Nam(cproto), dbuff); 17436285Sbrian } 1756059Samurai gotinfo = 1; 1766059Samurai } 17736285Sbrian if (log_IsKept(LogDEBUG)) { 17836285Sbrian if (fp->opt.srcop != OP_NONE) { 17936285Sbrian snprintf(dbuff, sizeof dbuff, ", src %s %d", 18036285Sbrian filter_Op2Nam(fp->opt.srcop), fp->opt.srcport); 18136285Sbrian len = strlen(dbuff); 18236285Sbrian } else 18336285Sbrian len = 0; 18436285Sbrian if (fp->opt.dstop != OP_NONE) { 18536285Sbrian snprintf(dbuff + len, sizeof dbuff - len, 18636285Sbrian ", dst %s %d", filter_Op2Nam(fp->opt.dstop), 18736285Sbrian fp->opt.dstport); 18836285Sbrian } else if (!len) 18936285Sbrian *dbuff = '\0'; 19026516Sbrian 19136285Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, " 19236285Sbrian "check against proto %s%s, action = %s\n", 19336285Sbrian n, filter_Proto2Nam(fp->proto), 19436285Sbrian dbuff, filter_Action2Nam(fp->action)); 19536285Sbrian } 19636285Sbrian 1976059Samurai if (cproto == fp->proto) { 1986059Samurai if ((fp->opt.srcop == OP_NONE || 19936285Sbrian PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) && 2006059Samurai (fp->opt.dstop == OP_NONE || 20136285Sbrian PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) && 20236285Sbrian (fp->opt.estab == 0 || estab) && 20336285Sbrian (fp->opt.syn == 0 || syn) && 20436285Sbrian (fp->opt.finrst == 0 || finrst)) { 20528679Sbrian return (fp->action); 2066059Samurai } 2076059Samurai } 2086059Samurai } else { 2096059Samurai /* Address is mached. Make a decision. */ 21036285Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 21136285Sbrian filter_Action2Nam(fp->action)); 21228679Sbrian return (fp->action); 2136059Samurai } 21436285Sbrian } else 21536285Sbrian log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 2166059Samurai } 2176059Samurai fp++; 2186059Samurai } 21928679Sbrian return (A_DENY); /* No rule is mached. Deny this packet */ 2206059Samurai } 22128679Sbrian return (A_PERMIT); /* No rule is given. Permit this packet */ 2226059Samurai} 2236059Samurai 22436285Sbrian#ifdef notdef 2256059Samuraistatic void 22628679SbrianIcmpError(struct ip * pip, int code) 2276059Samurai{ 2286059Samurai struct mbuf *bp; 2296059Samurai 2306059Samurai if (pip->ip_p != IPPROTO_ICMP) { 23136285Sbrian bp = mbuf_Alloc(cnt, MB_IPIN); 23230715Sbrian memcpy(MBUF_CTOP(bp), ptr, cnt); 23336285Sbrian vj_SendFrame(bp); 23436285Sbrian ipcp_AddOutOctets(cnt); 2356059Samurai } 23636285Sbrian} 2376059Samurai#endif 2386059Samurai 2396059Samurai/* 2406059Samurai * For debugging aid. 2416059Samurai */ 2426059Samuraiint 24336285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 2446059Samurai{ 2456059Samurai struct ip *pip; 2466059Samurai struct tcphdr *th; 2476059Samurai struct udphdr *uh; 2486059Samurai struct icmp *icmph; 2496059Samurai char *ptop; 2506059Samurai int mask, len, n; 2516059Samurai int pri = PRI_NORMAL; 25226692Sbrian int logit, loglen; 25326692Sbrian static char logbuf[200]; 2546059Samurai 25536285Sbrian logit = log_IsKept(LogTCPIP) && filter->logok; 25626692Sbrian loglen = 0; 2576059Samurai 25828679Sbrian pip = (struct ip *) cp; 2598857Srgrimes 26026692Sbrian if (logit && loglen < sizeof logbuf) { 26136285Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 26228679Sbrian loglen += strlen(logbuf + loglen); 26326692Sbrian } 2646059Samurai ptop = (cp + (pip->ip_hl << 2)); 2656059Samurai 2666059Samurai switch (pip->ip_p) { 2676059Samurai case IPPROTO_ICMP: 26826692Sbrian if (logit && loglen < sizeof logbuf) { 26928679Sbrian icmph = (struct icmp *) ptop; 27028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 27128679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 27228679Sbrian loglen += strlen(logbuf + loglen); 27328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 27428679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 27528679Sbrian loglen += strlen(logbuf + loglen); 2766059Samurai } 2776059Samurai break; 2786059Samurai case IPPROTO_UDP: 27926692Sbrian if (logit && loglen < sizeof logbuf) { 28028679Sbrian uh = (struct udphdr *) ptop; 28128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 28228679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 28328679Sbrian loglen += strlen(logbuf + loglen); 28428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 28528679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 28628679Sbrian loglen += strlen(logbuf + loglen); 2876059Samurai } 2886059Samurai break; 2896059Samurai case IPPROTO_TCP: 29028679Sbrian th = (struct tcphdr *) ptop; 2916059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 2926059Samurai pri = PRI_FAST; 29313733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 2946059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 29528679Sbrian pri = PRI_FAST; 2966059Samurai } 29726692Sbrian if (logit && loglen < sizeof logbuf) { 2986059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 29928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30028679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 30128679Sbrian loglen += strlen(logbuf + loglen); 30228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30328679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 30428679Sbrian loglen += strlen(logbuf + loglen); 3056059Samurai n = 0; 3066059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 30726692Sbrian if (th->th_flags & mask) { 30828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 30928679Sbrian loglen += strlen(logbuf + loglen); 31028679Sbrian } 3116059Samurai n++; 3126059Samurai } 31328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 31428679Sbrian " seq:%x ack:%x (%d/%d)", 31528679Sbrian ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 31628679Sbrian loglen += strlen(logbuf + loglen); 3176059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 31828679Sbrian u_short *sp; 3196059Samurai 3206059Samurai ptop += 20; 32128679Sbrian sp = (u_short *) ptop; 32226692Sbrian if (ntohs(sp[0]) == 0x0204) { 32328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32428679Sbrian " MSS = %d", ntohs(sp[1])); 32528679Sbrian loglen += strlen(logbuf + loglen); 32628679Sbrian } 3276059Samurai } 3286059Samurai } 3296059Samurai break; 3306059Samurai } 33126692Sbrian 33236285Sbrian if ((FilterCheck(pip, filter) & A_DENY)) { 33331142Sbrian if (logit) 33436285Sbrian log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 33536285Sbrian#ifdef notdef 33628679Sbrian if (direction == 0) 33728679Sbrian IcmpError(pip, pri); 33836285Sbrian#endif 33928679Sbrian return (-1); 3406059Samurai } else { 34136285Sbrian /* Check Keep Alive filter */ 34236285Sbrian if (logit) { 34336285Sbrian if (FilterCheck(pip, &bundle->filter.alive) & A_DENY) 34436285Sbrian log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 34536285Sbrian else 34636285Sbrian log_Printf(LogTCPIP, "%s\n", logbuf); 3476735Samurai } 34828679Sbrian return (pri); 3496059Samurai } 3506059Samurai} 3516059Samurai 3526059Samuraivoid 35336285Sbrianip_Input(struct bundle *bundle, struct mbuf * bp) 35436285Sbrian{ 3556059Samurai u_char *cp; 3566059Samurai struct mbuf *wp; 3576059Samurai int nb, nw; 35831343Sbrian struct tun_data tun; 35936285Sbrian struct ip *pip = (struct ip *)tun.data; 3606059Samurai 36131195Sbrian tun_fill_header(tun, AF_INET); 36231195Sbrian cp = tun.data; 3636059Samurai nb = 0; 36428679Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 36532247Sbrian if (sizeof tun.data - (cp - tun.data) < wp->cnt) { 36636285Sbrian log_Printf(LogERROR, "ip_Input: Packet too large (%d) - dropped\n", 36736285Sbrian mbuf_Length(bp)); 36836285Sbrian mbuf_Free(bp); 36932247Sbrian return; 37032247Sbrian } 37130715Sbrian memcpy(cp, MBUF_CTOP(wp), wp->cnt); 3726059Samurai cp += wp->cnt; 3736059Samurai nb += wp->cnt; 3746059Samurai } 3756059Samurai 37631343Sbrian#ifndef NOALIAS 37736285Sbrian if (alias_IsEnabled()) { 37831343Sbrian struct tun_data *frag; 37926031Sbrian int iresult; 38026031Sbrian char *fptr; 38126031Sbrian 38236285Sbrian iresult = (*PacketAlias.In)(tun.data, sizeof tun.data); 38331195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 38426031Sbrian 38526031Sbrian if (nb > MAX_MRU) { 38636285Sbrian log_Printf(LogERROR, "ip_Input: Problem with IP header length\n"); 38736285Sbrian mbuf_Free(bp); 38826031Sbrian return; 38926031Sbrian } 39026031Sbrian if (iresult == PKT_ALIAS_OK 39128679Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 39236285Sbrian if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) { 39336285Sbrian mbuf_Free(bp); 39428679Sbrian return; 39526031Sbrian } 39626031Sbrian 39736285Sbrian if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 39836285Sbrian bundle_StartIdleTimer(bundle); 39936285Sbrian 40036285Sbrian ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 40136285Sbrian 40231195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 40331962Sbrian nb += sizeof tun - sizeof tun.data; 40436285Sbrian nw = write(bundle->dev.fd, &tun, nb); 40535449Sbrian if (nw != nb) { 40630092Sbrian if (nw == -1) 40736285Sbrian log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, 40830092Sbrian strerror(errno)); 40930092Sbrian else 41036285Sbrian log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 41135449Sbrian } 41226031Sbrian 41326031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 41436285Sbrian while ((fptr = (*PacketAlias.GetFragment)(tun.data)) != NULL) { 41536285Sbrian (*PacketAlias.FragmentIn)(tun.data, fptr); 41628679Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 41731962Sbrian frag = (struct tun_data *) 41831962Sbrian ((char *)fptr - sizeof tun + sizeof tun.data); 41931962Sbrian nb += sizeof tun - sizeof tun.data; 42036285Sbrian nw = write(bundle->dev.fd, frag, nb); 42135449Sbrian if (nw != nb) { 42230092Sbrian if (nw == -1) 42336285Sbrian log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, 42430092Sbrian strerror(errno)); 42530092Sbrian else 42636285Sbrian log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 42735449Sbrian } 42831195Sbrian free(frag); 42928679Sbrian } 43026031Sbrian } 43128679Sbrian } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 43231195Sbrian nb = ntohs(((struct ip *) tun.data)->ip_len); 43331962Sbrian nb += sizeof tun - sizeof tun.data; 43431195Sbrian frag = (struct tun_data *)malloc(nb); 43531195Sbrian if (frag == NULL) 43636285Sbrian log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n"); 43726031Sbrian else { 43831195Sbrian tun_fill_header(*frag, AF_INET); 43931962Sbrian memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data); 44036285Sbrian (*PacketAlias.SaveFragment)(frag->data); 44126031Sbrian } 44226031Sbrian } 44331343Sbrian } else 44431343Sbrian#endif /* #ifndef NOALIAS */ 44531343Sbrian { /* no aliasing */ 44636285Sbrian if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) { 44736285Sbrian mbuf_Free(bp); 44826031Sbrian return; 44926031Sbrian } 45036285Sbrian 45136285Sbrian if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 45236285Sbrian bundle_StartIdleTimer(bundle); 45336285Sbrian 45436285Sbrian ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 45536285Sbrian 45631962Sbrian nb += sizeof tun - sizeof tun.data; 45736285Sbrian nw = write(bundle->dev.fd, &tun, nb); 45834536Sbrian if (nw != nb) { 45930092Sbrian if (nw == -1) 46036285Sbrian log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno)); 46130092Sbrian else 46236285Sbrian log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw); 46334536Sbrian } 4646059Samurai } 46536285Sbrian mbuf_Free(bp); 4666059Samurai} 4676059Samurai 46828679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1]; 4696059Samurai 4706059Samuraivoid 47136285Sbrianip_Enqueue(int pri, char *ptr, int count) 4726059Samurai{ 4736059Samurai struct mbuf *bp; 4746059Samurai 47536285Sbrian bp = mbuf_Alloc(count, MB_IPQ); 47630715Sbrian memcpy(MBUF_CTOP(bp), ptr, count); 47736285Sbrian mbuf_Enqueue(&IpOutputQueues[pri], bp); 4786059Samurai} 4796059Samurai 4808857Srgrimesint 48136285Sbrianip_QueueLen() 4827001Samurai{ 4837001Samurai struct mqueue *queue; 48436285Sbrian int result = 0; 48528679Sbrian 48636285Sbrian for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--) 48736285Sbrian result += queue->qlen; 48836285Sbrian 48936285Sbrian return result; 4907001Samurai} 4917001Samurai 49236285Sbrianint 49336285Sbrianip_FlushPacket(struct link *l, struct bundle *bundle) 4946059Samurai{ 4956059Samurai struct mqueue *queue; 4966059Samurai struct mbuf *bp; 49725630Sbrian int cnt; 4986059Samurai 49936285Sbrian if (bundle->ncp.ipcp.fsm.state != ST_OPENED) 50036285Sbrian return 0; 50136285Sbrian 50236285Sbrian for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) 5036059Samurai if (queue->top) { 50436285Sbrian bp = mbuf_Dequeue(queue); 5056059Samurai if (bp) { 50636285Sbrian struct ip *pip = (struct ip *)MBUF_CTOP(bp); 50736285Sbrian 50836285Sbrian cnt = mbuf_Length(bp); 50936285Sbrian vj_SendFrame(l, bp, bundle); 51036285Sbrian if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY)) 51136285Sbrian bundle_StartIdleTimer(bundle); 51236285Sbrian ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt); 51336285Sbrian return 1; 51428679Sbrian } 5156059Samurai } 51636285Sbrian 51736285Sbrian return 0; 5186059Samurai} 519