ip.c revision 51048
197403Sobrien/* 297403Sobrien * PPP IP Protocol Interface 3132720Skan * 4132720Skan * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 597403Sobrien * 697403Sobrien * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 797403Sobrien * 897403Sobrien * Redistribution and use in source and binary forms are permitted 997403Sobrien * provided that the above copyright notice and this paragraph are 1097403Sobrien * duplicated in all such forms and that any documentation, 1197403Sobrien * advertising materials, and other materials related to such 1297403Sobrien * distribution and use acknowledge that the software was developed 1397403Sobrien * by the Internet Initiative Japan. The name of the 1497403Sobrien * IIJ may not be used to endorse or promote products derived 1597403Sobrien * from this software without specific prior written permission. 1697403Sobrien * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1797403Sobrien * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1897403Sobrien * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1997403Sobrien * 2097403Sobrien * $FreeBSD: head/usr.sbin/ppp/ip.c 51048 1999-09-07 07:51:11Z brian $ 2197403Sobrien * 2297403Sobrien * TODO: 2397403Sobrien * o Return ICMP message for filterd packet 2497403Sobrien * and optionaly record it into log. 2597403Sobrien */ 2697403Sobrien#include <sys/param.h> 2797403Sobrien#if defined(__OpenBSD__) || defined(__NetBSD__) 2897403Sobrien#include <sys/socket.h> 2997403Sobrien#endif 3097403Sobrien#include <netinet/in.h> 3197403Sobrien#include <netinet/in_systm.h> 3297403Sobrien#include <netinet/ip.h> 3397403Sobrien#include <netinet/ip_icmp.h> 3497403Sobrien#include <netinet/udp.h> 3597403Sobrien#include <netinet/tcp.h> 3697403Sobrien#include <arpa/inet.h> 3797403Sobrien#include <sys/un.h> 3897403Sobrien 3997403Sobrien#include <errno.h> 40132720Skan#include <stdio.h> 41132720Skan#include <string.h> 4297403Sobrien#include <termios.h> 4397403Sobrien#include <unistd.h> 4497403Sobrien 4597403Sobrien#include "layer.h" 4697403Sobrien#include "proto.h" 4797403Sobrien#include "mbuf.h" 4897403Sobrien#include "log.h" 4997403Sobrien#include "defs.h" 50117397Skan#include "timer.h" 51117397Skan#include "fsm.h" 52117397Skan#include "lqr.h" 53117397Skan#include "hdlc.h" 54117397Skan#include "throughput.h" 55117397Skan#include "iplist.h" 56117397Skan#include "slcompress.h" 57117397Skan#include "ipcp.h" 5897403Sobrien#include "filter.h" 5997403Sobrien#include "descriptor.h" 6097403Sobrien#include "lcp.h" 6197403Sobrien#include "ccp.h" 6297403Sobrien#include "link.h" 6397403Sobrien#include "mp.h" 6497403Sobrien#ifndef NORADIUS 6597403Sobrien#include "radius.h" 6697403Sobrien#endif 6797403Sobrien#include "bundle.h" 6897403Sobrien#include "tun.h" 6997403Sobrien#include "ip.h" 7097403Sobrien 7197403Sobrienstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 7297403Sobrien 73132720Skanstatic __inline int 74132720SkanPortMatch(int op, u_short pport, u_short rport) 7597403Sobrien{ 7697403Sobrien switch (op) { 77117397Skan case OP_EQ: 78117397Skan return (pport == rport); 79117397Skan case OP_GT: 80117397Skan return (pport > rport); 81117397Skan case OP_LT: 82117397Skan return (pport < rport); 83117397Skan default: 84117397Skan return (0); 8597403Sobrien } 8697403Sobrien} 87117397Skan 88117397Skan/* 89117397Skan * Check a packet against a defined filter 90117397Skan * Returns 0 to accept the packet, non-zero to drop the packet 91117397Skan * 92117397Skan * If filtering is enabled, the initial fragment of a datagram must 9397403Sobrien * contain the complete protocol header, and subsequent fragments 9497403Sobrien * must not attempt to over-write it. 9597403Sobrien */ 96117397Skanstatic int 97117397SkanFilterCheck(const struct ip *pip, const struct filter *filter) 98117397Skan{ 99117397Skan int gotinfo; /* true if IP payload decoded */ 100117397Skan int cproto; /* P_* protocol type if (gotinfo) */ 101117397Skan int estab, syn, finrst; /* TCP state flags if (gotinfo) */ 102117397Skan u_short sport, dport; /* src, dest port from packet if (gotinfo) */ 103117397Skan int n; /* filter rule to process */ 10497403Sobrien int len; /* bytes used in dbuff */ 105132720Skan int didname; /* true if filter header printed */ 106132720Skan int match; /* true if condition matched */ 10797403Sobrien const struct filterent *fp = filter->rule; 108117397Skan char dbuff[100]; 109117397Skan 110117397Skan if (fp->f_action == A_NONE) 111117397Skan return (0); /* No rule is given. Permit this packet */ 112117397Skan 11397403Sobrien /* Deny any packet fragment that tries to over-write the header. 11497403Sobrien * Since we no longer have the real header available, punt on the 11597403Sobrien * largest normal header - 20 bytes for TCP without options, rounded 11697403Sobrien * up to the next possible fragment boundary. Since the smallest 117117397Skan * `legal' MTU is 576, and the smallest recommended MTU is 296, any 11897403Sobrien * fragmentation within this range is dubious at best */ 11997403Sobrien len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */ 12097403Sobrien if (len > 0) { /* Not first fragment within datagram */ 121117397Skan if (len < (24 >> 3)) /* don't allow fragment to over-write header */ 122117397Skan return (1); 123117397Skan /* permit fragments on in and out filter */ 124117397Skan return (filter->fragok); 125117397Skan } 126117397Skan 127117397Skan cproto = gotinfo = estab = syn = finrst = didname = 0; 128117397Skan sport = dport = 0; 129117397Skan for (n = 0; n < MAXFILTERS; ) { 130117397Skan if (fp->f_action == A_NONE) { 131132720Skan n++; 13297403Sobrien fp++; 13397403Sobrien continue; 134132720Skan } 13597403Sobrien 13697403Sobrien if (!didname) { 137132720Skan log_Printf(LogDEBUG, "%s filter:\n", filter->name); 13897403Sobrien didname = 1; 139117397Skan } 14097403Sobrien 141117397Skan match = 0; 142117397Skan if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) & 143117397Skan fp->f_src.mask.s_addr) && 144117397Skan !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) & 145117397Skan fp->f_dst.mask.s_addr)) { 146117397Skan if (fp->f_proto != P_NONE) { 147117397Skan if (!gotinfo) { 148117397Skan const char *ptop = (const char *) pip + (pip->ip_hl << 2); 149117397Skan const struct tcphdr *th; 150117397Skan const struct udphdr *uh; 151117397Skan const struct icmp *ih; 152117397Skan int datalen; /* IP datagram length */ 153117397Skan 154117397Skan datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 155117397Skan switch (pip->ip_p) { 156117397Skan case IPPROTO_ICMP: 157117397Skan cproto = P_ICMP; 158117397Skan if (datalen < 8) /* ICMP must be at least 8 octets */ 159117397Skan return (1); 160117397Skan ih = (const struct icmp *) ptop; 161117397Skan sport = ih->icmp_type; 162117397Skan estab = syn = finrst = -1; 163117397Skan if (log_IsKept(LogDEBUG)) 164117397Skan snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 165117397Skan break; 166117397Skan case IPPROTO_IGMP: 167117397Skan cproto = P_IGMP; 168117397Skan if (datalen < 8) /* IGMP uses 8-octet messages */ 16997403Sobrien return (1); 17097403Sobrien estab = syn = finrst = -1; 17197403Sobrien sport = ntohs(0); 17297403Sobrien break; 17397403Sobrien#ifdef IPPROTO_OSPFIGP 17497403Sobrien case IPPROTO_OSPFIGP: 17597403Sobrien cproto = P_OSPF; 17697403Sobrien if (datalen < 8) /* IGMP uses 8-octet messages */ 17797403Sobrien return (1); 17897403Sobrien estab = syn = finrst = -1; 17997403Sobrien sport = ntohs(0); 18097403Sobrien break; 18197403Sobrien#endif 18297403Sobrien case IPPROTO_UDP: 18397403Sobrien case IPPROTO_IPIP: 18497403Sobrien cproto = P_UDP; 18597403Sobrien if (datalen < 8) /* UDP header is 8 octets */ 18697403Sobrien return (1); 18797403Sobrien uh = (const struct udphdr *) ptop; 18897403Sobrien sport = ntohs(uh->uh_sport); 18997403Sobrien dport = ntohs(uh->uh_dport); 190132720Skan estab = syn = finrst = -1; 19197403Sobrien if (log_IsKept(LogDEBUG)) 19297403Sobrien snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 19397403Sobrien sport, dport); 19497403Sobrien break; 19597403Sobrien case IPPROTO_TCP: 19697403Sobrien cproto = P_TCP; 19797403Sobrien th = (const struct tcphdr *) ptop; 19897403Sobrien /* TCP headers are variable length. The following code 19997403Sobrien * ensures that the TCP header length isn't de-referenced if 20097403Sobrien * the datagram is too short 20197403Sobrien */ 20297403Sobrien if (datalen < 20 || datalen < (th->th_off << 2)) 20397403Sobrien return (1); 20497403Sobrien sport = ntohs(th->th_sport); 20597403Sobrien dport = ntohs(th->th_dport); 20697403Sobrien estab = (th->th_flags & TH_ACK); 20797403Sobrien syn = (th->th_flags & TH_SYN); 20897403Sobrien finrst = (th->th_flags & (TH_FIN|TH_RST)); 20997403Sobrien if (log_IsKept(LogDEBUG)) { 210117397Skan if (!estab) 211117397Skan snprintf(dbuff, sizeof dbuff, 212117397Skan "flags = %02x, sport = %d, dport = %d", 213117397Skan th->th_flags, sport, dport); 214117397Skan else 215132720Skan *dbuff = '\0'; 216117397Skan } 217117397Skan break; 218117397Skan default: 219117397Skan return (1); /* We'll block unknown type of packet */ 220117397Skan } 221117397Skan 222117397Skan if (log_IsKept(LogDEBUG)) { 223117397Skan if (estab != -1) { 224117397Skan len = strlen(dbuff); 225117397Skan snprintf(dbuff + len, sizeof dbuff - len, 226117397Skan ", estab = %d, syn = %d, finrst = %d", 227117397Skan estab, syn, finrst); 228117397Skan } 229117397Skan log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 23097403Sobrien filter_Proto2Nam(cproto), dbuff); 23197403Sobrien } 232117397Skan gotinfo = 1; 23397403Sobrien } 234117397Skan if (log_IsKept(LogDEBUG)) { 235117397Skan if (fp->f_srcop != OP_NONE) { 236117397Skan snprintf(dbuff, sizeof dbuff, ", src %s %d", 237117397Skan filter_Op2Nam(fp->f_srcop), fp->f_srcport); 238117397Skan len = strlen(dbuff); 239117397Skan } else 24097403Sobrien len = 0; 241117397Skan if (fp->f_dstop != OP_NONE) { 24297403Sobrien snprintf(dbuff + len, sizeof dbuff - len, 24397403Sobrien ", dst %s %d", filter_Op2Nam(fp->f_dstop), 244117397Skan fp->f_dstport); 245117397Skan } else if (!len) 246117397Skan *dbuff = '\0'; 247117397Skan 248117397Skan log_Printf(LogDEBUG, " rule = %d: Address match, " 249117397Skan "check against proto %s%s, action = %s\n", 250117397Skan n, filter_Proto2Nam(fp->f_proto), 251117397Skan dbuff, filter_Action2Nam(fp->f_action)); 252117397Skan } 253117397Skan 254117397Skan if (cproto == fp->f_proto) { 255117397Skan if ((fp->f_srcop == OP_NONE || 256117397Skan PortMatch(fp->f_srcop, sport, fp->f_srcport)) && 257117397Skan (fp->f_dstop == OP_NONE || 258117397Skan PortMatch(fp->f_dstop, dport, fp->f_dstport)) && 259117397Skan (fp->f_estab == 0 || estab) && 260117397Skan (fp->f_syn == 0 || syn) && 261117397Skan (fp->f_finrst == 0 || finrst)) { 262117397Skan match = 1; 263117397Skan } 264117397Skan } 265117397Skan } else { 266117397Skan /* Address is matched and no protocol specified. Make a decision. */ 267117397Skan log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 268117397Skan filter_Action2Nam(fp->f_action)); 269117397Skan match = 1; 270117397Skan } 271117397Skan } else 27297403Sobrien log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 273117397Skan 27497403Sobrien if (match != fp->f_invert) { 275117397Skan /* Take specified action */ 276117397Skan if (fp->f_action < A_NONE) 277117397Skan fp = &filter->rule[n = fp->f_action]; 278117397Skan else 279117397Skan return (fp->f_action != A_PERMIT); 280117397Skan } else { 281117397Skan n++; 282117397Skan fp++; 283117397Skan } 284117397Skan } 285117397Skan return (1); /* No rule is mached. Deny this packet */ 28697403Sobrien} 28797403Sobrien 28897403Sobrien#ifdef notdef 289117397Skanstatic void 290117397SkanIcmpError(struct ip *pip, int code) 291117397Skan{ 292117397Skan struct mbuf *bp; 293117397Skan 294117397Skan if (pip->ip_p != IPPROTO_ICMP) { 295117397Skan bp = mbuf_Alloc(cnt, MB_IPIN); 296117397Skan memcpy(MBUF_CTOP(bp), ptr, cnt); 297117397Skan vj_SendFrame(bp); 298117397Skan ipcp_AddOutOctets(cnt); 299117397Skan } 300117397Skan} 301117397Skan#endif 302117397Skan 303117397Skan/* 304117397Skan * For debugging aid. 305117397Skan */ 306117397Skanint 307117397SkanPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 308117397Skan{ 309117397Skan struct ip *pip; 310117397Skan struct tcphdr *th; 311117397Skan struct udphdr *uh; 312117397Skan struct icmp *icmph; 31397403Sobrien char *ptop; 31497403Sobrien int mask, len, n; 31597403Sobrien int pri = 0; 316117397Skan int logit, loglen; 317117397Skan char logbuf[200]; 318117397Skan 319117397Skan logit = log_IsKept(LogTCPIP) && filter->logok; 320117397Skan loglen = 0; 321117397Skan 322117397Skan pip = (struct ip *) cp; 323117397Skan 32497403Sobrien if (logit && loglen < sizeof logbuf) { 32597403Sobrien snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 32697403Sobrien loglen += strlen(logbuf + loglen); 32797403Sobrien } 328117397Skan ptop = (cp + (pip->ip_hl << 2)); 329117397Skan 330117397Skan switch (pip->ip_p) { 331117397Skan case IPPROTO_ICMP: 332117397Skan if (logit && loglen < sizeof logbuf) { 333117397Skan icmph = (struct icmp *) ptop; 334117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 335117397Skan "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 336117397Skan loglen += strlen(logbuf + loglen); 337117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 338117397Skan "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 339117397Skan loglen += strlen(logbuf + loglen); 340117397Skan } 341117397Skan break; 342117397Skan 343117397Skan case IPPROTO_UDP: 344117397Skan uh = (struct udphdr *) ptop; 345117397Skan if (pip->ip_tos == IPTOS_LOWDELAY) 346117397Skan pri++; 34797403Sobrien 34897403Sobrien if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 && 34997403Sobrien ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport), 350117397Skan ntohs(uh->uh_dport))) 351117397Skan pri++; 352117397Skan 353117397Skan if (logit && loglen < sizeof logbuf) { 354117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 355117397Skan "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 356117397Skan loglen += strlen(logbuf + loglen); 35797403Sobrien snprintf(logbuf + loglen, sizeof logbuf - loglen, 35897403Sobrien "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 35997403Sobrien loglen += strlen(logbuf + loglen); 36097403Sobrien } 361117397Skan break; 362117397Skan 363117397Skan#ifdef IPPROTO_OSPFIGP 364117397Skan case IPPROTO_OSPFIGP: 365117397Skan if (logit && loglen < sizeof logbuf) { 366117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 367117397Skan "OSPF: %s ---> ", inet_ntoa(pip->ip_src)); 368117397Skan loglen += strlen(logbuf + loglen); 369117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 370117397Skan "%s", inet_ntoa(pip->ip_dst)); 371117397Skan loglen += strlen(logbuf + loglen); 372117397Skan } 373117397Skan break; 374117397Skan#endif 375117397Skan 376117397Skan case IPPROTO_IPIP: 377117397Skan if (logit && loglen < sizeof logbuf) { 378117397Skan uh = (struct udphdr *) ptop; 379117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 380117397Skan "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 381117397Skan loglen += strlen(logbuf + loglen); 382117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 383117397Skan "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 384117397Skan loglen += strlen(logbuf + loglen); 385117397Skan } 38697403Sobrien break; 38797403Sobrien 38897403Sobrien case IPPROTO_IGMP: 389117397Skan if (logit && loglen < sizeof logbuf) { 390117397Skan uh = (struct udphdr *) ptop; 391117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 392117397Skan "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 393117397Skan loglen += strlen(logbuf + loglen); 394117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 395117397Skan "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 396117397Skan loglen += strlen(logbuf + loglen); 39797403Sobrien } 39897403Sobrien break; 39997403Sobrien 40097403Sobrien case IPPROTO_TCP: 401117397Skan th = (struct tcphdr *) ptop; 402117397Skan if (pip->ip_tos == IPTOS_LOWDELAY) 403117397Skan pri++; 404117397Skan 405117397Skan if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 && 406117397Skan ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport), 407117397Skan ntohs(th->th_dport))) 408117397Skan pri++; 409117397Skan 410117397Skan if (logit && loglen < sizeof logbuf) { 411117397Skan len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 412117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 413117397Skan "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 414117397Skan loglen += strlen(logbuf + loglen); 415117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 41697403Sobrien "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 41797403Sobrien loglen += strlen(logbuf + loglen); 41897403Sobrien n = 0; 419117397Skan for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 420117397Skan if (th->th_flags & mask) { 421117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 422117397Skan loglen += strlen(logbuf + loglen); 423117397Skan } 424117397Skan n++; 425117397Skan } 426117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 42797403Sobrien " seq:%lx ack:%lx (%d/%d)", 428117397Skan (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 42997403Sobrien loglen += strlen(logbuf + loglen); 430117397Skan if ((th->th_flags & TH_SYN) && nb > 40) { 431117397Skan u_short *sp; 432117397Skan 433117397Skan ptop += 20; 434117397Skan sp = (u_short *) ptop; 435117397Skan if (ntohs(sp[0]) == 0x0204) { 436117397Skan snprintf(logbuf + loglen, sizeof logbuf - loglen, 437117397Skan " MSS = %d", ntohs(sp[1])); 438117397Skan loglen += strlen(logbuf + loglen); 439117397Skan } 440117397Skan } 441117397Skan } 442117397Skan break; 443117397Skan } 444117397Skan 44597403Sobrien if (FilterCheck(pip, filter)) { 44697403Sobrien if (logit) 44797403Sobrien log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 448117397Skan#ifdef notdef 449117397Skan if (direction == 0) 450117397Skan IcmpError(pip, pri); 451117397Skan#endif 452117397Skan return (-1); 453117397Skan } else { 454117397Skan /* Check Keep Alive filter */ 455117397Skan if (logit) { 456117397Skan if (FilterCheck(pip, &bundle->filter.alive)) 457117397Skan log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 458117397Skan else 459117397Skan log_Printf(LogTCPIP, "%s\n", logbuf); 460117397Skan } 461117397Skan return (pri); 462117397Skan } 463117397Skan} 46497403Sobrien 46597403Sobrienstruct mbuf * 46697403Sobrienip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 467117397Skan{ 468117397Skan int nb, nw; 469117397Skan struct tun_data tun; 470117397Skan struct ip *pip; 471117397Skan 472117397Skan if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 473117397Skan log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n"); 474117397Skan mbuf_Free(bp); 475117397Skan return NULL; 476117397Skan } 477117397Skan 478117397Skan mbuf_SetType(bp, MB_IPIN); 479117397Skan tun_fill_header(tun, AF_INET); 48097403Sobrien nb = mbuf_Length(bp); 48197403Sobrien if (nb > sizeof tun.data) { 48297403Sobrien log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n", 483117397Skan l->name, nb, (int)(sizeof tun.data)); 484117397Skan mbuf_Free(bp); 485117397Skan return NULL; 486117397Skan } 487117397Skan mbuf_Read(bp, tun.data, nb); 488117397Skan 489117397Skan if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) 490117397Skan return NULL; 491117397Skan 492117397Skan pip = (struct ip *)tun.data; 493117397Skan if (!FilterCheck(pip, &bundle->filter.alive)) 494117397Skan bundle_StartIdleTimer(bundle); 49597403Sobrien 496117397Skan ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 49797403Sobrien 498117397Skan nb += sizeof tun - sizeof tun.data; 499117397Skan nw = write(bundle->dev.fd, &tun, nb); 500117397Skan if (nw != nb) { 501117397Skan if (nw == -1) 502117397Skan log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n", 503117397Skan l->name, nb, strerror(errno)); 504117397Skan else 505117397Skan log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw); 506117397Skan } 507117397Skan 508117397Skan return NULL; 509117397Skan} 510117397Skan 511117397Skanvoid 512117397Skanip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) 51397403Sobrien{ 514117397Skan struct mbuf *bp; 51597403Sobrien 516117397Skan if (pri < 0 || pri >= IPCP_QUEUES(ipcp)) 517117397Skan log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); 518117397Skan else { 519117397Skan /* 520117397Skan * We allocate an extra 6 bytes, four at the front and two at the end. 521117397Skan * This is an optimisation so that we need to do less work in 522117397Skan * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and 523117397Skan * appending in hdlc_LayerPush(). 524117397Skan */ 525117397Skan bp = mbuf_Alloc(count + 6, MB_IPOUT); 526117397Skan bp->offset += 4; 52797403Sobrien bp->cnt -= 6; 528117397Skan memcpy(MBUF_CTOP(bp), ptr, count); 52997403Sobrien mbuf_Enqueue(ipcp->Queue + pri, bp); 530117397Skan } 531117397Skan} 532117397Skan 533117397Skanvoid 534117397Skanip_DeleteQueue(struct ipcp *ipcp) 535117397Skan{ 536117397Skan struct mqueue *queue; 537117397Skan 538117397Skan for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++) 539117397Skan while (queue->top) 540117397Skan mbuf_Free(mbuf_Dequeue(queue)); 541117397Skan} 54297403Sobrien 54397403Sobrienint 54497403Sobrienip_QueueLen(struct ipcp *ipcp) 545117397Skan{ 546117397Skan struct mqueue *queue; 547117397Skan int result = 0; 548117397Skan 549117397Skan for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++) 550117397Skan result += queue->qlen; 551117397Skan 552117397Skan return result; 553117397Skan} 554117397Skan 555117397Skanint 556117397Skanip_PushPacket(struct link *l, struct bundle *bundle) 557117397Skan{ 55897403Sobrien struct ipcp *ipcp = &bundle->ncp.ipcp; 55997403Sobrien struct mqueue *queue; 560117397Skan struct mbuf *bp; 561132720Skan struct ip *pip; 562132720Skan int cnt; 563132720Skan 564132720Skan if (ipcp->fsm.state != ST_OPENED) 56597403Sobrien return 0; 56697403Sobrien 567117397Skan queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1; 568117397Skan do { 569117397Skan if (queue->top) { 570117397Skan bp = mbuf_Contiguous(mbuf_Dequeue(queue)); 571117397Skan cnt = mbuf_Length(bp); 572117397Skan pip = (struct ip *)MBUF_CTOP(bp); 573117397Skan if (!FilterCheck(pip, &bundle->filter.alive)) 574117397Skan bundle_StartIdleTimer(bundle); 575117397Skan link_PushPacket(l, bp, bundle, 0, PROTO_IP); 576117397Skan ipcp_AddOutOctets(ipcp, cnt); 577117397Skan return 1; 57897403Sobrien } 57997403Sobrien } while (queue-- != ipcp->Queue); 58097403Sobrien 58197403Sobrien return 0; 582117397Skan} 58397403Sobrien