ip.c revision 49374
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 * 2049374Sbrian * $Id: ip.c,v 1.66 1999/08/02 11:53:16 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Return ICMP message for filterd packet 246059Samurai * and optionaly record it into log. 256059Samurai */ 2643313Sbrian#include <sys/param.h> 2746086Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__) 2831195Sbrian#include <sys/socket.h> 2938174Sbrian#endif 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> 3736285Sbrian#include <sys/un.h> 3830715Sbrian 3930092Sbrian#include <errno.h> 4030715Sbrian#include <stdio.h> 4130715Sbrian#include <stdlib.h> 4230715Sbrian#include <string.h> 4346686Sbrian#include <termios.h> 4430715Sbrian#include <unistd.h> 4530715Sbrian 4646686Sbrian#include "layer.h" 4746686Sbrian#include "proto.h" 4830715Sbrian#include "mbuf.h" 4930715Sbrian#include "log.h" 5030715Sbrian#include "defs.h" 5130715Sbrian#include "timer.h" 5230715Sbrian#include "fsm.h" 5336285Sbrian#include "lqr.h" 5430715Sbrian#include "hdlc.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" 6543313Sbrian#ifndef NORADIUS 6643313Sbrian#include "radius.h" 6743313Sbrian#endif 6836285Sbrian#include "bundle.h" 6930715Sbrian#include "vjcomp.h" 7031195Sbrian#include "tun.h" 7130715Sbrian#include "ip.h" 726059Samurai 7331343Sbrianstatic const u_short interactive_ports[32] = { 7428679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7546223Sbrian 80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 766059Samurai}; 776059Samurai 7813733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 796059Samurai 8031343Sbrianstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 816059Samurai 8249140Sbrianstatic __inline int 8328679SbrianPortMatch(int op, u_short pport, u_short rport) 846059Samurai{ 856059Samurai switch (op) { 8649140Sbrian case OP_EQ: 8728679Sbrian return (pport == rport); 886059Samurai case OP_GT: 8928679Sbrian return (pport > rport); 906059Samurai case OP_LT: 9128679Sbrian return (pport < rport); 926059Samurai default: 9328679Sbrian return (0); 946059Samurai } 956059Samurai} 966059Samurai 976059Samurai/* 9846686Sbrian * Check a packet against a defined filter 9949140Sbrian * Returns 0 to accept the packet, non-zero to drop the packet 10049140Sbrian * 10149140Sbrian * If filtering is enabled, the initial fragment of a datagram must 10249140Sbrian * contain the complete protocol header, and subsequent fragments 10349140Sbrian * must not attempt to over-write it. 1046059Samurai */ 1056059Samuraistatic int 10649140SbrianFilterCheck(const struct ip *pip, const struct filter *filter) 1076059Samurai{ 10849140Sbrian int gotinfo; /* true if IP payload decoded */ 10949140Sbrian int cproto; /* P_* protocol type if (gotinfo) */ 11049140Sbrian int estab, syn, finrst; /* TCP state flags if (gotinfo) */ 11149140Sbrian u_short sport, dport; /* src, dest port from packet if (gotinfo) */ 11249140Sbrian int n; /* filter rule to process */ 11349140Sbrian int len; /* bytes used in dbuff */ 11449140Sbrian int didname; /* true if filter header printed */ 11549140Sbrian int match; /* true if condition matched */ 11649140Sbrian const struct filterent *fp = filter->rule; 11736285Sbrian char dbuff[100]; 1186059Samurai 11949140Sbrian if (fp->f_action == A_NONE) 12049140Sbrian return (0); /* No rule is given. Permit this packet */ 12136285Sbrian 12249140Sbrian /* Deny any packet fragment that tries to over-write the header. 12349140Sbrian * Since we no longer have the real header available, punt on the 12449140Sbrian * largest normal header - 20 bytes for TCP without options, rounded 12549140Sbrian * up to the next possible fragment boundary. Since the smallest 12649140Sbrian * `legal' MTU is 576, and the smallest recommended MTU is 296, any 12749140Sbrian * fragmentation within this range is dubious at best */ 12849140Sbrian len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */ 12949140Sbrian if (len > 0) { /* Not first fragment within datagram */ 13049140Sbrian if (len < (24 >> 3)) /* don't allow fragment to over-write header */ 13149140Sbrian return (1); 13249140Sbrian /* permit fragments on in and out filter */ 13349140Sbrian return (filter->fragok); 13449140Sbrian } 13549140Sbrian 13649140Sbrian cproto = gotinfo = estab = syn = finrst = didname = 0; 13749140Sbrian sport = dport = 0; 13849140Sbrian for (n = 0; n < MAXFILTERS; ) { 13949140Sbrian if (fp->f_action == A_NONE) { 14049140Sbrian n++; 14149140Sbrian fp++; 14249140Sbrian continue; 14349140Sbrian } 14436285Sbrian 14549140Sbrian if (!didname) { 14649140Sbrian log_Printf(LogDEBUG, "%s filter:\n", filter->name); 14749140Sbrian didname = 1; 14849140Sbrian } 1496059Samurai 15049140Sbrian match = 0; 15149140Sbrian if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) & 15249140Sbrian fp->f_src.mask.s_addr) && 15349140Sbrian !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) & 15449140Sbrian fp->f_dst.mask.s_addr)) { 15549140Sbrian if (fp->f_proto != P_NONE) { 15649140Sbrian if (!gotinfo) { 15749140Sbrian const char *ptop = (const char *) pip + (pip->ip_hl << 2); 15849140Sbrian const struct tcphdr *th; 15949140Sbrian const struct udphdr *uh; 16049140Sbrian const struct icmp *ih; 16149140Sbrian int datalen; /* IP datagram length */ 16249140Sbrian 16349140Sbrian datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 16449140Sbrian switch (pip->ip_p) { 16549140Sbrian case IPPROTO_ICMP: 16649140Sbrian cproto = P_ICMP; 16749140Sbrian if (datalen < 8) /* ICMP must be at least 8 octets */ 16849140Sbrian return (1); 16949140Sbrian ih = (const struct icmp *) ptop; 17049140Sbrian sport = ih->icmp_type; 17149140Sbrian estab = syn = finrst = -1; 17249140Sbrian if (log_IsKept(LogDEBUG)) 17349140Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 17449140Sbrian break; 17549140Sbrian case IPPROTO_IGMP: 17649140Sbrian cproto = P_IGMP; 17749140Sbrian if (datalen < 8) /* IGMP uses 8-octet messages */ 17849140Sbrian return (1); 17949140Sbrian estab = syn = finrst = -1; 18049140Sbrian sport = ntohs(0); 18149140Sbrian break; 18249374Sbrian#ifdef IPPROTO_OSPFIGP 18349372Sbrian case IPPROTO_OSPFIGP: 18449372Sbrian cproto = P_OSPF; 18549372Sbrian if (datalen < 8) /* IGMP uses 8-octet messages */ 18649372Sbrian return (1); 18749372Sbrian estab = syn = finrst = -1; 18849372Sbrian sport = ntohs(0); 18949372Sbrian break; 19049374Sbrian#endif 19149140Sbrian case IPPROTO_UDP: 19249140Sbrian case IPPROTO_IPIP: 19349140Sbrian cproto = P_UDP; 19449140Sbrian if (datalen < 8) /* UDP header is 8 octets */ 19549140Sbrian return (1); 19649140Sbrian uh = (const struct udphdr *) ptop; 19749140Sbrian sport = ntohs(uh->uh_sport); 19849140Sbrian dport = ntohs(uh->uh_dport); 19949140Sbrian estab = syn = finrst = -1; 20049140Sbrian if (log_IsKept(LogDEBUG)) 20149140Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 20249140Sbrian sport, dport); 20349140Sbrian break; 20449140Sbrian case IPPROTO_TCP: 20549140Sbrian cproto = P_TCP; 20649140Sbrian th = (const struct tcphdr *) ptop; 20749140Sbrian /* TCP headers are variable length. The following code 20849140Sbrian * ensures that the TCP header length isn't de-referenced if 20949140Sbrian * the datagram is too short 21049140Sbrian */ 21149140Sbrian if (datalen < 20 || datalen < (th->th_off << 2)) 21249140Sbrian return (1); 21349140Sbrian sport = ntohs(th->th_sport); 21449140Sbrian dport = ntohs(th->th_dport); 21549140Sbrian estab = (th->th_flags & TH_ACK); 21649140Sbrian syn = (th->th_flags & TH_SYN); 21749140Sbrian finrst = (th->th_flags & (TH_FIN|TH_RST)); 21849140Sbrian if (log_IsKept(LogDEBUG)) { 21949140Sbrian if (!estab) 22049140Sbrian snprintf(dbuff, sizeof dbuff, 22149140Sbrian "flags = %02x, sport = %d, dport = %d", 22249140Sbrian th->th_flags, sport, dport); 22349140Sbrian else 22449140Sbrian *dbuff = '\0'; 2256059Samurai } 22649140Sbrian break; 22749140Sbrian default: 22849140Sbrian return (1); /* We'll block unknown type of packet */ 22949140Sbrian } 23026516Sbrian 23149140Sbrian if (log_IsKept(LogDEBUG)) { 23249140Sbrian if (estab != -1) { 23349140Sbrian len = strlen(dbuff); 23449140Sbrian snprintf(dbuff + len, sizeof dbuff - len, 23549140Sbrian ", estab = %d, syn = %d, finrst = %d", 23649140Sbrian estab, syn, finrst); 2376059Samurai } 23849140Sbrian log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 23949140Sbrian filter_Proto2Nam(cproto), dbuff); 2406059Samurai } 24149140Sbrian gotinfo = 1; 24249140Sbrian } 24349140Sbrian if (log_IsKept(LogDEBUG)) { 24449140Sbrian if (fp->f_srcop != OP_NONE) { 24549140Sbrian snprintf(dbuff, sizeof dbuff, ", src %s %d", 24649140Sbrian filter_Op2Nam(fp->f_srcop), fp->f_srcport); 24749140Sbrian len = strlen(dbuff); 24849140Sbrian } else 24949140Sbrian len = 0; 25049140Sbrian if (fp->f_dstop != OP_NONE) { 25149140Sbrian snprintf(dbuff + len, sizeof dbuff - len, 25249140Sbrian ", dst %s %d", filter_Op2Nam(fp->f_dstop), 25349140Sbrian fp->f_dstport); 25449140Sbrian } else if (!len) 25549140Sbrian *dbuff = '\0'; 25649140Sbrian 25749140Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, " 25849140Sbrian "check against proto %s%s, action = %s\n", 25949140Sbrian n, filter_Proto2Nam(fp->f_proto), 26049140Sbrian dbuff, filter_Action2Nam(fp->f_action)); 26149140Sbrian } 26249140Sbrian 26349140Sbrian if (cproto == fp->f_proto) { 26449140Sbrian if ((fp->f_srcop == OP_NONE || 26549140Sbrian PortMatch(fp->f_srcop, sport, fp->f_srcport)) && 26649140Sbrian (fp->f_dstop == OP_NONE || 26749140Sbrian PortMatch(fp->f_dstop, dport, fp->f_dstport)) && 26849140Sbrian (fp->f_estab == 0 || estab) && 26949140Sbrian (fp->f_syn == 0 || syn) && 27049140Sbrian (fp->f_finrst == 0 || finrst)) { 27149140Sbrian match = 1; 27249140Sbrian } 27349140Sbrian } 27449140Sbrian } else { 27549140Sbrian /* Address is matched and no protocol specified. Make a decision. */ 27649140Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 27749140Sbrian filter_Action2Nam(fp->f_action)); 27849140Sbrian match = 1; 2796059Samurai } 28049140Sbrian } else 28149140Sbrian log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 28249140Sbrian 28349140Sbrian if (match != fp->f_invert) { 28449140Sbrian /* Take specified action */ 28549140Sbrian if (fp->f_action < A_NONE) 28649140Sbrian fp = &filter->rule[n = fp->f_action]; 28749140Sbrian else 28849140Sbrian return (fp->f_action != A_PERMIT); 28949140Sbrian } else { 29049140Sbrian n++; 2916059Samurai fp++; 2926059Samurai } 2936059Samurai } 29449140Sbrian return (1); /* No rule is mached. Deny this packet */ 2956059Samurai} 2966059Samurai 29736285Sbrian#ifdef notdef 2986059Samuraistatic void 29946828SbrianIcmpError(struct ip *pip, int code) 3006059Samurai{ 3016059Samurai struct mbuf *bp; 3026059Samurai 3036059Samurai if (pip->ip_p != IPPROTO_ICMP) { 30436285Sbrian bp = mbuf_Alloc(cnt, MB_IPIN); 30530715Sbrian memcpy(MBUF_CTOP(bp), ptr, cnt); 30636285Sbrian vj_SendFrame(bp); 30736285Sbrian ipcp_AddOutOctets(cnt); 3086059Samurai } 30936285Sbrian} 3106059Samurai#endif 3116059Samurai 3126059Samurai/* 3136059Samurai * For debugging aid. 3146059Samurai */ 3156059Samuraiint 31636285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 3176059Samurai{ 3186059Samurai struct ip *pip; 3196059Samurai struct tcphdr *th; 3206059Samurai struct udphdr *uh; 3216059Samurai struct icmp *icmph; 3226059Samurai char *ptop; 3236059Samurai int mask, len, n; 3246059Samurai int pri = PRI_NORMAL; 32526692Sbrian int logit, loglen; 32637010Sbrian char logbuf[200]; 3276059Samurai 32836285Sbrian logit = log_IsKept(LogTCPIP) && filter->logok; 32926692Sbrian loglen = 0; 3306059Samurai 33128679Sbrian pip = (struct ip *) cp; 3328857Srgrimes 33326692Sbrian if (logit && loglen < sizeof logbuf) { 33436285Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 33528679Sbrian loglen += strlen(logbuf + loglen); 33626692Sbrian } 3376059Samurai ptop = (cp + (pip->ip_hl << 2)); 3386059Samurai 3396059Samurai switch (pip->ip_p) { 3406059Samurai case IPPROTO_ICMP: 34126692Sbrian if (logit && loglen < sizeof logbuf) { 34228679Sbrian icmph = (struct icmp *) ptop; 34328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 34428679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 34528679Sbrian loglen += strlen(logbuf + loglen); 34628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 34728679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 34828679Sbrian loglen += strlen(logbuf + loglen); 3496059Samurai } 3506059Samurai break; 3516059Samurai case IPPROTO_UDP: 35226692Sbrian if (logit && loglen < sizeof logbuf) { 35328679Sbrian uh = (struct udphdr *) ptop; 35428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 35528679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 35628679Sbrian loglen += strlen(logbuf + loglen); 35728679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 35828679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 35928679Sbrian loglen += strlen(logbuf + loglen); 3606059Samurai } 3616059Samurai break; 36249374Sbrian#ifdef IPPROTO_OSPFIGP 36349372Sbrian case IPPROTO_OSPFIGP: 36449372Sbrian if (logit && loglen < sizeof logbuf) { 36549372Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 36649372Sbrian "OSPF: %s ---> ", inet_ntoa(pip->ip_src)); 36749372Sbrian loglen += strlen(logbuf + loglen); 36849372Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 36949372Sbrian "%s", inet_ntoa(pip->ip_dst)); 37049372Sbrian loglen += strlen(logbuf + loglen); 37149372Sbrian } 37249372Sbrian break; 37349374Sbrian#endif 37436961Sbrian case IPPROTO_IPIP: 37536961Sbrian if (logit && loglen < sizeof logbuf) { 37636961Sbrian uh = (struct udphdr *) ptop; 37736961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 37836961Sbrian "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 37936961Sbrian loglen += strlen(logbuf + loglen); 38036961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 38136961Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 38236961Sbrian loglen += strlen(logbuf + loglen); 38336961Sbrian } 38436961Sbrian break; 38536961Sbrian case IPPROTO_IGMP: 38636961Sbrian if (logit && loglen < sizeof logbuf) { 38736961Sbrian uh = (struct udphdr *) ptop; 38836961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 38936961Sbrian "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 39036961Sbrian loglen += strlen(logbuf + loglen); 39136961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 39236961Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 39336961Sbrian loglen += strlen(logbuf + loglen); 39436961Sbrian } 39536961Sbrian break; 3966059Samurai case IPPROTO_TCP: 39728679Sbrian th = (struct tcphdr *) ptop; 3986059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 3996059Samurai pri = PRI_FAST; 40013733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 4016059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 40228679Sbrian pri = PRI_FAST; 4036059Samurai } 40426692Sbrian if (logit && loglen < sizeof logbuf) { 4056059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 40628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 40728679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 40828679Sbrian loglen += strlen(logbuf + loglen); 40928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 41028679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 41128679Sbrian loglen += strlen(logbuf + loglen); 4126059Samurai n = 0; 4136059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 41426692Sbrian if (th->th_flags & mask) { 41528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 41628679Sbrian loglen += strlen(logbuf + loglen); 41728679Sbrian } 4186059Samurai n++; 4196059Samurai } 42028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 42137210Sbrian " seq:%lx ack:%lx (%d/%d)", 42237210Sbrian (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 42328679Sbrian loglen += strlen(logbuf + loglen); 4246059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 42528679Sbrian u_short *sp; 4266059Samurai 4276059Samurai ptop += 20; 42828679Sbrian sp = (u_short *) ptop; 42926692Sbrian if (ntohs(sp[0]) == 0x0204) { 43028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 43128679Sbrian " MSS = %d", ntohs(sp[1])); 43228679Sbrian loglen += strlen(logbuf + loglen); 43328679Sbrian } 4346059Samurai } 4356059Samurai } 4366059Samurai break; 4376059Samurai } 43826692Sbrian 43949140Sbrian if (FilterCheck(pip, filter)) { 44031142Sbrian if (logit) 44136285Sbrian log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 44236285Sbrian#ifdef notdef 44328679Sbrian if (direction == 0) 44428679Sbrian IcmpError(pip, pri); 44536285Sbrian#endif 44628679Sbrian return (-1); 4476059Samurai } else { 44836285Sbrian /* Check Keep Alive filter */ 44936285Sbrian if (logit) { 45049140Sbrian if (FilterCheck(pip, &bundle->filter.alive)) 45136285Sbrian log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 45236285Sbrian else 45336285Sbrian log_Printf(LogTCPIP, "%s\n", logbuf); 4546735Samurai } 45528679Sbrian return (pri); 4566059Samurai } 4576059Samurai} 4586059Samurai 45946686Sbrianstruct mbuf * 46046686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 46136285Sbrian{ 4626059Samurai int nb, nw; 46331343Sbrian struct tun_data tun; 46446686Sbrian struct ip *pip; 4656059Samurai 46646686Sbrian if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 46746686Sbrian log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n"); 46846686Sbrian mbuf_Free(bp); 46946686Sbrian return NULL; 4706059Samurai } 4716059Samurai 47247695Sbrian mbuf_SetType(bp, MB_IPIN); 47346686Sbrian tun_fill_header(tun, AF_INET); 47446686Sbrian nb = mbuf_Length(bp); 47547168Sbrian if (nb > sizeof tun.data) { 47647168Sbrian log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n", 47747168Sbrian l->name, nb, (int)(sizeof tun.data)); 47847168Sbrian mbuf_Free(bp); 47947168Sbrian return NULL; 48047168Sbrian } 48146686Sbrian mbuf_Read(bp, tun.data, nb); 48226031Sbrian 48346686Sbrian if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) 48446686Sbrian return NULL; 48526031Sbrian 48646686Sbrian pip = (struct ip *)tun.data; 48749140Sbrian if (!FilterCheck(pip, &bundle->filter.alive)) 48846686Sbrian bundle_StartIdleTimer(bundle); 48926031Sbrian 49046686Sbrian ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 49136285Sbrian 49246686Sbrian nb += sizeof tun - sizeof tun.data; 49346686Sbrian nw = write(bundle->dev.fd, &tun, nb); 49446686Sbrian if (nw != nb) { 49546686Sbrian if (nw == -1) 49647168Sbrian log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n", 49747168Sbrian l->name, nb, strerror(errno)); 49846686Sbrian else 49947168Sbrian log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw); 50046686Sbrian } 50136285Sbrian 50246686Sbrian return NULL; 5036059Samurai} 5046059Samurai 5056059Samuraivoid 50638557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) 5076059Samurai{ 5086059Samurai struct mbuf *bp; 5096059Samurai 51038557Sbrian if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0]) 51138557Sbrian log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); 51238557Sbrian else { 51346686Sbrian /* 51446686Sbrian * We allocate an extra 6 bytes, four at the front and two at the end. 51546686Sbrian * This is an optimisation so that we need to do less work in 51646686Sbrian * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and 51746686Sbrian * appending in hdlc_LayerPush(). 51846686Sbrian */ 51947695Sbrian bp = mbuf_Alloc(count + 6, MB_IPOUT); 52046686Sbrian bp->offset += 4; 52146686Sbrian bp->cnt -= 6; 52238557Sbrian memcpy(MBUF_CTOP(bp), ptr, count); 52338557Sbrian mbuf_Enqueue(&ipcp->Queue[pri], bp); 52438557Sbrian } 5256059Samurai} 5266059Samurai 52738544Sbrianvoid 52838557Sbrianip_DeleteQueue(struct ipcp *ipcp) 52938544Sbrian{ 53038544Sbrian struct mqueue *queue; 53138544Sbrian 53238557Sbrian for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 53338544Sbrian while (queue->top) 53438544Sbrian mbuf_Free(mbuf_Dequeue(queue)); 53538544Sbrian} 53638544Sbrian 5378857Srgrimesint 53838557Sbrianip_QueueLen(struct ipcp *ipcp) 5397001Samurai{ 5407001Samurai struct mqueue *queue; 54136285Sbrian int result = 0; 54228679Sbrian 54338557Sbrian for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 54436285Sbrian result += queue->qlen; 54536285Sbrian 54636285Sbrian return result; 5477001Samurai} 5487001Samurai 54936285Sbrianint 55046686Sbrianip_PushPacket(struct link *l, struct bundle *bundle) 5516059Samurai{ 55238557Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 5536059Samurai struct mqueue *queue; 5546059Samurai struct mbuf *bp; 55546686Sbrian struct ip *pip; 55625630Sbrian int cnt; 5576059Samurai 55838557Sbrian if (ipcp->fsm.state != ST_OPENED) 55936285Sbrian return 0; 56036285Sbrian 56138557Sbrian for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--) 5626059Samurai if (queue->top) { 56345103Sbrian bp = mbuf_Contiguous(mbuf_Dequeue(queue)); 56446686Sbrian cnt = mbuf_Length(bp); 56546686Sbrian pip = (struct ip *)MBUF_CTOP(bp); 56649140Sbrian if (!FilterCheck(pip, &bundle->filter.alive)) 56746686Sbrian bundle_StartIdleTimer(bundle); 56846686Sbrian link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP); 56946686Sbrian ipcp_AddOutOctets(ipcp, cnt); 57046686Sbrian return 1; 5716059Samurai } 57236285Sbrian 57336285Sbrian return 0; 5746059Samurai} 575