ip.c revision 49372
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 * 2049372Sbrian * $Id: ip.c,v 1.65 1999/07/27 23:43:59 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; 18249372Sbrian case IPPROTO_OSPFIGP: 18349372Sbrian cproto = P_OSPF; 18449372Sbrian if (datalen < 8) /* IGMP uses 8-octet messages */ 18549372Sbrian return (1); 18649372Sbrian estab = syn = finrst = -1; 18749372Sbrian sport = ntohs(0); 18849372Sbrian break; 18949140Sbrian case IPPROTO_UDP: 19049140Sbrian case IPPROTO_IPIP: 19149140Sbrian cproto = P_UDP; 19249140Sbrian if (datalen < 8) /* UDP header is 8 octets */ 19349140Sbrian return (1); 19449140Sbrian uh = (const struct udphdr *) ptop; 19549140Sbrian sport = ntohs(uh->uh_sport); 19649140Sbrian dport = ntohs(uh->uh_dport); 19749140Sbrian estab = syn = finrst = -1; 19849140Sbrian if (log_IsKept(LogDEBUG)) 19949140Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 20049140Sbrian sport, dport); 20149140Sbrian break; 20249140Sbrian case IPPROTO_TCP: 20349140Sbrian cproto = P_TCP; 20449140Sbrian th = (const struct tcphdr *) ptop; 20549140Sbrian /* TCP headers are variable length. The following code 20649140Sbrian * ensures that the TCP header length isn't de-referenced if 20749140Sbrian * the datagram is too short 20849140Sbrian */ 20949140Sbrian if (datalen < 20 || datalen < (th->th_off << 2)) 21049140Sbrian return (1); 21149140Sbrian sport = ntohs(th->th_sport); 21249140Sbrian dport = ntohs(th->th_dport); 21349140Sbrian estab = (th->th_flags & TH_ACK); 21449140Sbrian syn = (th->th_flags & TH_SYN); 21549140Sbrian finrst = (th->th_flags & (TH_FIN|TH_RST)); 21649140Sbrian if (log_IsKept(LogDEBUG)) { 21749140Sbrian if (!estab) 21849140Sbrian snprintf(dbuff, sizeof dbuff, 21949140Sbrian "flags = %02x, sport = %d, dport = %d", 22049140Sbrian th->th_flags, sport, dport); 22149140Sbrian else 22249140Sbrian *dbuff = '\0'; 2236059Samurai } 22449140Sbrian break; 22549140Sbrian default: 22649140Sbrian return (1); /* We'll block unknown type of packet */ 22749140Sbrian } 22826516Sbrian 22949140Sbrian if (log_IsKept(LogDEBUG)) { 23049140Sbrian if (estab != -1) { 23149140Sbrian len = strlen(dbuff); 23249140Sbrian snprintf(dbuff + len, sizeof dbuff - len, 23349140Sbrian ", estab = %d, syn = %d, finrst = %d", 23449140Sbrian estab, syn, finrst); 2356059Samurai } 23649140Sbrian log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 23749140Sbrian filter_Proto2Nam(cproto), dbuff); 2386059Samurai } 23949140Sbrian gotinfo = 1; 24049140Sbrian } 24149140Sbrian if (log_IsKept(LogDEBUG)) { 24249140Sbrian if (fp->f_srcop != OP_NONE) { 24349140Sbrian snprintf(dbuff, sizeof dbuff, ", src %s %d", 24449140Sbrian filter_Op2Nam(fp->f_srcop), fp->f_srcport); 24549140Sbrian len = strlen(dbuff); 24649140Sbrian } else 24749140Sbrian len = 0; 24849140Sbrian if (fp->f_dstop != OP_NONE) { 24949140Sbrian snprintf(dbuff + len, sizeof dbuff - len, 25049140Sbrian ", dst %s %d", filter_Op2Nam(fp->f_dstop), 25149140Sbrian fp->f_dstport); 25249140Sbrian } else if (!len) 25349140Sbrian *dbuff = '\0'; 25449140Sbrian 25549140Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, " 25649140Sbrian "check against proto %s%s, action = %s\n", 25749140Sbrian n, filter_Proto2Nam(fp->f_proto), 25849140Sbrian dbuff, filter_Action2Nam(fp->f_action)); 25949140Sbrian } 26049140Sbrian 26149140Sbrian if (cproto == fp->f_proto) { 26249140Sbrian if ((fp->f_srcop == OP_NONE || 26349140Sbrian PortMatch(fp->f_srcop, sport, fp->f_srcport)) && 26449140Sbrian (fp->f_dstop == OP_NONE || 26549140Sbrian PortMatch(fp->f_dstop, dport, fp->f_dstport)) && 26649140Sbrian (fp->f_estab == 0 || estab) && 26749140Sbrian (fp->f_syn == 0 || syn) && 26849140Sbrian (fp->f_finrst == 0 || finrst)) { 26949140Sbrian match = 1; 27049140Sbrian } 27149140Sbrian } 27249140Sbrian } else { 27349140Sbrian /* Address is matched and no protocol specified. Make a decision. */ 27449140Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 27549140Sbrian filter_Action2Nam(fp->f_action)); 27649140Sbrian match = 1; 2776059Samurai } 27849140Sbrian } else 27949140Sbrian log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 28049140Sbrian 28149140Sbrian if (match != fp->f_invert) { 28249140Sbrian /* Take specified action */ 28349140Sbrian if (fp->f_action < A_NONE) 28449140Sbrian fp = &filter->rule[n = fp->f_action]; 28549140Sbrian else 28649140Sbrian return (fp->f_action != A_PERMIT); 28749140Sbrian } else { 28849140Sbrian n++; 2896059Samurai fp++; 2906059Samurai } 2916059Samurai } 29249140Sbrian return (1); /* No rule is mached. Deny this packet */ 2936059Samurai} 2946059Samurai 29536285Sbrian#ifdef notdef 2966059Samuraistatic void 29746828SbrianIcmpError(struct ip *pip, int code) 2986059Samurai{ 2996059Samurai struct mbuf *bp; 3006059Samurai 3016059Samurai if (pip->ip_p != IPPROTO_ICMP) { 30236285Sbrian bp = mbuf_Alloc(cnt, MB_IPIN); 30330715Sbrian memcpy(MBUF_CTOP(bp), ptr, cnt); 30436285Sbrian vj_SendFrame(bp); 30536285Sbrian ipcp_AddOutOctets(cnt); 3066059Samurai } 30736285Sbrian} 3086059Samurai#endif 3096059Samurai 3106059Samurai/* 3116059Samurai * For debugging aid. 3126059Samurai */ 3136059Samuraiint 31436285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 3156059Samurai{ 3166059Samurai struct ip *pip; 3176059Samurai struct tcphdr *th; 3186059Samurai struct udphdr *uh; 3196059Samurai struct icmp *icmph; 3206059Samurai char *ptop; 3216059Samurai int mask, len, n; 3226059Samurai int pri = PRI_NORMAL; 32326692Sbrian int logit, loglen; 32437010Sbrian char logbuf[200]; 3256059Samurai 32636285Sbrian logit = log_IsKept(LogTCPIP) && filter->logok; 32726692Sbrian loglen = 0; 3286059Samurai 32928679Sbrian pip = (struct ip *) cp; 3308857Srgrimes 33126692Sbrian if (logit && loglen < sizeof logbuf) { 33236285Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 33328679Sbrian loglen += strlen(logbuf + loglen); 33426692Sbrian } 3356059Samurai ptop = (cp + (pip->ip_hl << 2)); 3366059Samurai 3376059Samurai switch (pip->ip_p) { 3386059Samurai case IPPROTO_ICMP: 33926692Sbrian if (logit && loglen < sizeof logbuf) { 34028679Sbrian icmph = (struct icmp *) ptop; 34128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 34228679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 34328679Sbrian loglen += strlen(logbuf + loglen); 34428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 34528679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 34628679Sbrian loglen += strlen(logbuf + loglen); 3476059Samurai } 3486059Samurai break; 3496059Samurai case IPPROTO_UDP: 35026692Sbrian if (logit && loglen < sizeof logbuf) { 35128679Sbrian uh = (struct udphdr *) ptop; 35228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 35328679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 35428679Sbrian loglen += strlen(logbuf + loglen); 35528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 35628679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 35728679Sbrian loglen += strlen(logbuf + loglen); 3586059Samurai } 3596059Samurai break; 36049372Sbrian case IPPROTO_OSPFIGP: 36149372Sbrian if (logit && loglen < sizeof logbuf) { 36249372Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 36349372Sbrian "OSPF: %s ---> ", inet_ntoa(pip->ip_src)); 36449372Sbrian loglen += strlen(logbuf + loglen); 36549372Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 36649372Sbrian "%s", inet_ntoa(pip->ip_dst)); 36749372Sbrian loglen += strlen(logbuf + loglen); 36849372Sbrian } 36949372Sbrian break; 37036961Sbrian case IPPROTO_IPIP: 37136961Sbrian if (logit && loglen < sizeof logbuf) { 37236961Sbrian uh = (struct udphdr *) ptop; 37336961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 37436961Sbrian "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 37536961Sbrian loglen += strlen(logbuf + loglen); 37636961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 37736961Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 37836961Sbrian loglen += strlen(logbuf + loglen); 37936961Sbrian } 38036961Sbrian break; 38136961Sbrian case IPPROTO_IGMP: 38236961Sbrian if (logit && loglen < sizeof logbuf) { 38336961Sbrian uh = (struct udphdr *) ptop; 38436961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 38536961Sbrian "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 38636961Sbrian loglen += strlen(logbuf + loglen); 38736961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 38836961Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 38936961Sbrian loglen += strlen(logbuf + loglen); 39036961Sbrian } 39136961Sbrian break; 3926059Samurai case IPPROTO_TCP: 39328679Sbrian th = (struct tcphdr *) ptop; 3946059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 3956059Samurai pri = PRI_FAST; 39613733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 3976059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 39828679Sbrian pri = PRI_FAST; 3996059Samurai } 40026692Sbrian if (logit && loglen < sizeof logbuf) { 4016059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 40228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 40328679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 40428679Sbrian loglen += strlen(logbuf + loglen); 40528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 40628679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 40728679Sbrian loglen += strlen(logbuf + loglen); 4086059Samurai n = 0; 4096059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 41026692Sbrian if (th->th_flags & mask) { 41128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 41228679Sbrian loglen += strlen(logbuf + loglen); 41328679Sbrian } 4146059Samurai n++; 4156059Samurai } 41628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 41737210Sbrian " seq:%lx ack:%lx (%d/%d)", 41837210Sbrian (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 41928679Sbrian loglen += strlen(logbuf + loglen); 4206059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 42128679Sbrian u_short *sp; 4226059Samurai 4236059Samurai ptop += 20; 42428679Sbrian sp = (u_short *) ptop; 42526692Sbrian if (ntohs(sp[0]) == 0x0204) { 42628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 42728679Sbrian " MSS = %d", ntohs(sp[1])); 42828679Sbrian loglen += strlen(logbuf + loglen); 42928679Sbrian } 4306059Samurai } 4316059Samurai } 4326059Samurai break; 4336059Samurai } 43426692Sbrian 43549140Sbrian if (FilterCheck(pip, filter)) { 43631142Sbrian if (logit) 43736285Sbrian log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 43836285Sbrian#ifdef notdef 43928679Sbrian if (direction == 0) 44028679Sbrian IcmpError(pip, pri); 44136285Sbrian#endif 44228679Sbrian return (-1); 4436059Samurai } else { 44436285Sbrian /* Check Keep Alive filter */ 44536285Sbrian if (logit) { 44649140Sbrian if (FilterCheck(pip, &bundle->filter.alive)) 44736285Sbrian log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 44836285Sbrian else 44936285Sbrian log_Printf(LogTCPIP, "%s\n", logbuf); 4506735Samurai } 45128679Sbrian return (pri); 4526059Samurai } 4536059Samurai} 4546059Samurai 45546686Sbrianstruct mbuf * 45646686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 45736285Sbrian{ 4586059Samurai int nb, nw; 45931343Sbrian struct tun_data tun; 46046686Sbrian struct ip *pip; 4616059Samurai 46246686Sbrian if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 46346686Sbrian log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n"); 46446686Sbrian mbuf_Free(bp); 46546686Sbrian return NULL; 4666059Samurai } 4676059Samurai 46847695Sbrian mbuf_SetType(bp, MB_IPIN); 46946686Sbrian tun_fill_header(tun, AF_INET); 47046686Sbrian nb = mbuf_Length(bp); 47147168Sbrian if (nb > sizeof tun.data) { 47247168Sbrian log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n", 47347168Sbrian l->name, nb, (int)(sizeof tun.data)); 47447168Sbrian mbuf_Free(bp); 47547168Sbrian return NULL; 47647168Sbrian } 47746686Sbrian mbuf_Read(bp, tun.data, nb); 47826031Sbrian 47946686Sbrian if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) 48046686Sbrian return NULL; 48126031Sbrian 48246686Sbrian pip = (struct ip *)tun.data; 48349140Sbrian if (!FilterCheck(pip, &bundle->filter.alive)) 48446686Sbrian bundle_StartIdleTimer(bundle); 48526031Sbrian 48646686Sbrian ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 48736285Sbrian 48846686Sbrian nb += sizeof tun - sizeof tun.data; 48946686Sbrian nw = write(bundle->dev.fd, &tun, nb); 49046686Sbrian if (nw != nb) { 49146686Sbrian if (nw == -1) 49247168Sbrian log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n", 49347168Sbrian l->name, nb, strerror(errno)); 49446686Sbrian else 49547168Sbrian log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw); 49646686Sbrian } 49736285Sbrian 49846686Sbrian return NULL; 4996059Samurai} 5006059Samurai 5016059Samuraivoid 50238557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) 5036059Samurai{ 5046059Samurai struct mbuf *bp; 5056059Samurai 50638557Sbrian if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0]) 50738557Sbrian log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); 50838557Sbrian else { 50946686Sbrian /* 51046686Sbrian * We allocate an extra 6 bytes, four at the front and two at the end. 51146686Sbrian * This is an optimisation so that we need to do less work in 51246686Sbrian * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and 51346686Sbrian * appending in hdlc_LayerPush(). 51446686Sbrian */ 51547695Sbrian bp = mbuf_Alloc(count + 6, MB_IPOUT); 51646686Sbrian bp->offset += 4; 51746686Sbrian bp->cnt -= 6; 51838557Sbrian memcpy(MBUF_CTOP(bp), ptr, count); 51938557Sbrian mbuf_Enqueue(&ipcp->Queue[pri], bp); 52038557Sbrian } 5216059Samurai} 5226059Samurai 52338544Sbrianvoid 52438557Sbrianip_DeleteQueue(struct ipcp *ipcp) 52538544Sbrian{ 52638544Sbrian struct mqueue *queue; 52738544Sbrian 52838557Sbrian for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 52938544Sbrian while (queue->top) 53038544Sbrian mbuf_Free(mbuf_Dequeue(queue)); 53138544Sbrian} 53238544Sbrian 5338857Srgrimesint 53438557Sbrianip_QueueLen(struct ipcp *ipcp) 5357001Samurai{ 5367001Samurai struct mqueue *queue; 53736285Sbrian int result = 0; 53828679Sbrian 53938557Sbrian for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++) 54036285Sbrian result += queue->qlen; 54136285Sbrian 54236285Sbrian return result; 5437001Samurai} 5447001Samurai 54536285Sbrianint 54646686Sbrianip_PushPacket(struct link *l, struct bundle *bundle) 5476059Samurai{ 54838557Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 5496059Samurai struct mqueue *queue; 5506059Samurai struct mbuf *bp; 55146686Sbrian struct ip *pip; 55225630Sbrian int cnt; 5536059Samurai 55438557Sbrian if (ipcp->fsm.state != ST_OPENED) 55536285Sbrian return 0; 55636285Sbrian 55738557Sbrian for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--) 5586059Samurai if (queue->top) { 55945103Sbrian bp = mbuf_Contiguous(mbuf_Dequeue(queue)); 56046686Sbrian cnt = mbuf_Length(bp); 56146686Sbrian pip = (struct ip *)MBUF_CTOP(bp); 56249140Sbrian if (!FilterCheck(pip, &bundle->filter.alive)) 56346686Sbrian bundle_StartIdleTimer(bundle); 56446686Sbrian link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP); 56546686Sbrian ipcp_AddOutOctets(ipcp, cnt); 56646686Sbrian return 1; 5676059Samurai } 56836285Sbrian 56936285Sbrian return 0; 5706059Samurai} 571