xref: /freebsd/usr.sbin/ppp/ip.c (revision 53c9f6c0c48df668bb8fa282cd0b12cb8690bcce)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *		PPP IP Protocol Interface
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
20af57ed9fSAtsushi Murai  * $Id:$
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Return ICMP message for filterd packet
24af57ed9fSAtsushi Murai  *		  and optionaly record it into log.
25af57ed9fSAtsushi Murai  */
26af57ed9fSAtsushi Murai #include "fsm.h"
27af57ed9fSAtsushi Murai #include "lcpproto.h"
28af57ed9fSAtsushi Murai #include "hdlc.h"
29af57ed9fSAtsushi Murai #include <netinet/in_systm.h>
30af57ed9fSAtsushi Murai #include <netinet/ip.h>
31af57ed9fSAtsushi Murai #include <netinet/ip_icmp.h>
32af57ed9fSAtsushi Murai #include <netinet/udp.h>
33af57ed9fSAtsushi Murai #include <netinet/tcp.h>
34af57ed9fSAtsushi Murai #include "vars.h"
35af57ed9fSAtsushi Murai #include "filter.h"
36af57ed9fSAtsushi Murai 
3753c9f6c0SAtsushi Murai extern void SendPppFrame();
38af57ed9fSAtsushi Murai extern int PacketCheck();
39af57ed9fSAtsushi Murai extern void LcpClose();
40af57ed9fSAtsushi Murai 
41af57ed9fSAtsushi Murai static struct pppTimer IdleTimer;
42af57ed9fSAtsushi Murai 
43af57ed9fSAtsushi Murai static void IdleTimeout()
44af57ed9fSAtsushi Murai {
45af57ed9fSAtsushi Murai   LogPrintf(LOG_PHASE, "Idle timer expired.\n");
46af57ed9fSAtsushi Murai   LcpClose();
47af57ed9fSAtsushi Murai }
48af57ed9fSAtsushi Murai 
49af57ed9fSAtsushi Murai /*
50af57ed9fSAtsushi Murai  *  Start Idle timer. If timeout is reached, we call LcpClose() to
51af57ed9fSAtsushi Murai  *  close LCP and link.
52af57ed9fSAtsushi Murai  */
53af57ed9fSAtsushi Murai void
54af57ed9fSAtsushi Murai StartIdleTimer()
55af57ed9fSAtsushi Murai {
56af57ed9fSAtsushi Murai   if (!(mode & MODE_DEDICATED)) {
57af57ed9fSAtsushi Murai     StopTimer(&IdleTimer);
58af57ed9fSAtsushi Murai     IdleTimer.func = IdleTimeout;
59af57ed9fSAtsushi Murai     IdleTimer.load = VarIdleTimeout * SECTICKS;
60af57ed9fSAtsushi Murai     IdleTimer.state = TIMER_STOPPED;
61af57ed9fSAtsushi Murai     StartTimer(&IdleTimer);
62af57ed9fSAtsushi Murai   }
63af57ed9fSAtsushi Murai }
64af57ed9fSAtsushi Murai 
65af57ed9fSAtsushi Murai void
66af57ed9fSAtsushi Murai StopIdleTimer()
67af57ed9fSAtsushi Murai {
68af57ed9fSAtsushi Murai   StopTimer(&IdleTimer);
69af57ed9fSAtsushi Murai }
70af57ed9fSAtsushi Murai 
71af57ed9fSAtsushi Murai /*
72af57ed9fSAtsushi Murai  *  If any IP layer traffic is detected, refresh IdleTimer.
73af57ed9fSAtsushi Murai  */
74af57ed9fSAtsushi Murai static void
75af57ed9fSAtsushi Murai RestartIdleTimer()
76af57ed9fSAtsushi Murai {
7753c9f6c0SAtsushi Murai   if (!(mode & MODE_DEDICATED) && ipKeepAlive ) {
7853c9f6c0SAtsushi Murai /*  StopTimer(&IdleTimer); */
79af57ed9fSAtsushi Murai     StartTimer(&IdleTimer);
80af57ed9fSAtsushi Murai     ipIdleSecs = 0;
81af57ed9fSAtsushi Murai   }
82af57ed9fSAtsushi Murai }
83af57ed9fSAtsushi Murai 
84af57ed9fSAtsushi Murai static u_short interactive_ports[8] = {
85af57ed9fSAtsushi Murai   0, 513, 0, 0, 0, 21, 0, 23,
86af57ed9fSAtsushi Murai };
87af57ed9fSAtsushi Murai 
88af57ed9fSAtsushi Murai #define	INTERACTIVE(p)	(interactive_ports[(p) & 7] == (p))
89af57ed9fSAtsushi Murai 
90af57ed9fSAtsushi Murai static char *TcpFlags[] = {
91af57ed9fSAtsushi Murai   "FIN", "SYN", "RST", "PSH", "ACK", "URG",
92af57ed9fSAtsushi Murai };
93af57ed9fSAtsushi Murai 
9453c9f6c0SAtsushi Murai static char *Direction[] = { "INP", "OUT", "OUT", "IN/OUT" };
9553c9f6c0SAtsushi Murai static struct filterent *Filters[] = { ifilters, ofilters, dfilters, afilters };
96af57ed9fSAtsushi Murai 
97af57ed9fSAtsushi Murai static int
98af57ed9fSAtsushi Murai PortMatch(op, pport, rport)
99af57ed9fSAtsushi Murai int op;
100af57ed9fSAtsushi Murai u_short pport, rport;
101af57ed9fSAtsushi Murai {
102af57ed9fSAtsushi Murai   switch (op) {
103af57ed9fSAtsushi Murai   case OP_EQ:
104af57ed9fSAtsushi Murai     return(pport == rport);
105af57ed9fSAtsushi Murai   case OP_GT:
106af57ed9fSAtsushi Murai     return(pport > rport);
107af57ed9fSAtsushi Murai   case OP_LT:
108af57ed9fSAtsushi Murai     return(pport < rport);
109af57ed9fSAtsushi Murai   default:
110af57ed9fSAtsushi Murai     return(0);
111af57ed9fSAtsushi Murai   }
112af57ed9fSAtsushi Murai }
113af57ed9fSAtsushi Murai 
114af57ed9fSAtsushi Murai /*
115af57ed9fSAtsushi Murai  *  Check a packet against with defined filters
116af57ed9fSAtsushi Murai  */
117af57ed9fSAtsushi Murai static int
118af57ed9fSAtsushi Murai FilterCheck(pip, direction)
119af57ed9fSAtsushi Murai struct ip *pip;
120af57ed9fSAtsushi Murai int direction;
121af57ed9fSAtsushi Murai {
122af57ed9fSAtsushi Murai   struct filterent *fp = Filters[direction];
123af57ed9fSAtsushi Murai   int gotinfo, cproto, estab, n;
124af57ed9fSAtsushi Murai   struct tcphdr *th;
125af57ed9fSAtsushi Murai   struct udphdr *uh;
126af57ed9fSAtsushi Murai   struct icmp *ih;
127af57ed9fSAtsushi Murai   char *ptop;
128af57ed9fSAtsushi Murai   u_short sport, dport;
129af57ed9fSAtsushi Murai 
130af57ed9fSAtsushi Murai   if (fp->action) {
131af57ed9fSAtsushi Murai     cproto = gotinfo = estab = 0;
132af57ed9fSAtsushi Murai     sport = dport = 0;
133af57ed9fSAtsushi Murai     for (n = 0; n < MAXFILTERS; n++) {
134af57ed9fSAtsushi Murai       if (fp->action) {
135af57ed9fSAtsushi Murai #ifdef DEBUG
136af57ed9fSAtsushi Murai logprintf("rule = %d\n", n);
137af57ed9fSAtsushi Murai #endif
138af57ed9fSAtsushi Murai 	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
139af57ed9fSAtsushi Murai 	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
140af57ed9fSAtsushi Murai 	  if (fp->proto) {
141af57ed9fSAtsushi Murai 	    if (!gotinfo) {
142af57ed9fSAtsushi Murai 	      ptop = (char *)pip + (pip->ip_hl << 2);
143af57ed9fSAtsushi Murai 
144af57ed9fSAtsushi Murai 	      switch (pip->ip_p) {
145af57ed9fSAtsushi Murai 	      case IPPROTO_ICMP:
146af57ed9fSAtsushi Murai 		cproto = P_ICMP; ih = (struct icmp *)ptop;
147af57ed9fSAtsushi Murai 		sport = ih->icmp_type; estab = 1;
148af57ed9fSAtsushi Murai 		break;
149af57ed9fSAtsushi Murai 	      case IPPROTO_UDP:
150af57ed9fSAtsushi Murai 		cproto = P_UDP; uh = (struct udphdr *)ptop;
151af57ed9fSAtsushi Murai 		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
152af57ed9fSAtsushi Murai 		estab = 1;
153af57ed9fSAtsushi Murai 		break;
154af57ed9fSAtsushi Murai 	      case IPPROTO_TCP:
155af57ed9fSAtsushi Murai 		cproto = P_TCP; th = (struct tcphdr *)ptop;
156af57ed9fSAtsushi Murai 		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
157af57ed9fSAtsushi Murai 		estab = (th->th_flags & TH_ACK);
15853c9f6c0SAtsushi Murai #ifdef DEBUG
15953c9f6c0SAtsushi Murai if (estab == 0)
16053c9f6c0SAtsushi Murai logprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
16153c9f6c0SAtsushi Murai #endif
162af57ed9fSAtsushi Murai 		break;
163af57ed9fSAtsushi Murai 	      default:
164af57ed9fSAtsushi Murai 		return(A_DENY);	/* We'll block unknown type of packet */
165af57ed9fSAtsushi Murai 	      }
166af57ed9fSAtsushi Murai 	      gotinfo = 1;
167af57ed9fSAtsushi Murai #ifdef DEBUG
168af57ed9fSAtsushi Murai logprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
169af57ed9fSAtsushi Murai direction, cproto, fp->opt.srcop, fp->opt.dstop, estab);
170af57ed9fSAtsushi Murai #endif
171af57ed9fSAtsushi Murai 	    }
172af57ed9fSAtsushi Murai #ifdef DEBUG
173af57ed9fSAtsushi Murai 	    logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
174af57ed9fSAtsushi Murai 		      n, cproto, sport, dport);
175af57ed9fSAtsushi Murai 	    logprintf("check0: action = %d\n", fp->action);
176af57ed9fSAtsushi Murai #endif
177af57ed9fSAtsushi Murai 	    if (cproto == fp->proto) {
178af57ed9fSAtsushi Murai 	      if ((fp->opt.srcop == OP_NONE ||
179af57ed9fSAtsushi Murai 		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
180af57ed9fSAtsushi Murai 	       &&
181af57ed9fSAtsushi Murai 		  (fp->opt.dstop == OP_NONE ||
182af57ed9fSAtsushi Murai 		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
183af57ed9fSAtsushi Murai 	       &&
184af57ed9fSAtsushi Murai 		  (fp->opt.estab == 0 || estab)) {
185af57ed9fSAtsushi Murai 		return(fp->action);
186af57ed9fSAtsushi Murai 	      }
187af57ed9fSAtsushi Murai 	    }
188af57ed9fSAtsushi Murai 	  } else {
189af57ed9fSAtsushi Murai 	    /* Address is mached. Make a decision. */
190af57ed9fSAtsushi Murai #ifdef DEBUG
191af57ed9fSAtsushi Murai 	    logprintf("check1: action = %d\n", fp->action);
192af57ed9fSAtsushi Murai #endif
193af57ed9fSAtsushi Murai 	    return(fp->action);
194af57ed9fSAtsushi Murai 	  }
195af57ed9fSAtsushi Murai 	}
196af57ed9fSAtsushi Murai       }
197af57ed9fSAtsushi Murai       fp++;
198af57ed9fSAtsushi Murai     }
199af57ed9fSAtsushi Murai drop:
200af57ed9fSAtsushi Murai     return(A_DENY);	/* No rule is mached. Deny this packet */
201af57ed9fSAtsushi Murai   }
202af57ed9fSAtsushi Murai   return(A_PERMIT);	/* No rule is given. Permit this packet */
203af57ed9fSAtsushi Murai }
204af57ed9fSAtsushi Murai 
205af57ed9fSAtsushi Murai static void
206af57ed9fSAtsushi Murai IcmpError(pip, code)
207af57ed9fSAtsushi Murai struct ip *pip;
208af57ed9fSAtsushi Murai int code;
209af57ed9fSAtsushi Murai {
210af57ed9fSAtsushi Murai #ifdef notdef
211af57ed9fSAtsushi Murai   struct mbuf *bp;
212af57ed9fSAtsushi Murai 
213af57ed9fSAtsushi Murai   if (pip->ip_p != IPPROTO_ICMP) {
214af57ed9fSAtsushi Murai     bp = mballoc(cnt, MB_IPIN);
215af57ed9fSAtsushi Murai     bcopy(ptr, MBUF_CTOP(bp), cnt);
21653c9f6c0SAtsushi Murai     SendPppFrame(PRI_URGENT, bp);
217af57ed9fSAtsushi Murai     RestartIdleTimer();
218af57ed9fSAtsushi Murai     ipOutOctets += cnt;
219af57ed9fSAtsushi Murai   }
220af57ed9fSAtsushi Murai #endif
221af57ed9fSAtsushi Murai }
222af57ed9fSAtsushi Murai 
223af57ed9fSAtsushi Murai /*
224af57ed9fSAtsushi Murai  *  For debugging aid.
225af57ed9fSAtsushi Murai  */
226af57ed9fSAtsushi Murai int
227af57ed9fSAtsushi Murai PacketCheck(cp, nb, direction)
228af57ed9fSAtsushi Murai char *cp;
229af57ed9fSAtsushi Murai int nb;
230af57ed9fSAtsushi Murai int direction;
231af57ed9fSAtsushi Murai {
232af57ed9fSAtsushi Murai   struct ip *pip;
233af57ed9fSAtsushi Murai   struct tcphdr *th;
234af57ed9fSAtsushi Murai   struct udphdr *uh;
235af57ed9fSAtsushi Murai   struct icmp *icmph;
236af57ed9fSAtsushi Murai   char *ptop;
237af57ed9fSAtsushi Murai   int mask, len, n;
238af57ed9fSAtsushi Murai   int logit;
239af57ed9fSAtsushi Murai   int pri = PRI_NORMAL;
240af57ed9fSAtsushi Murai 
241af57ed9fSAtsushi Murai   logit = (loglevel & (1 << LOG_TCPIP));
242af57ed9fSAtsushi Murai 
243af57ed9fSAtsushi Murai   pip = (struct ip *)cp;
244af57ed9fSAtsushi Murai 
245af57ed9fSAtsushi Murai   if (logit) logprintf("%s  ", Direction[direction]);
246af57ed9fSAtsushi Murai 
247af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
248af57ed9fSAtsushi Murai 
249af57ed9fSAtsushi Murai   switch (pip->ip_p) {
250af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
251af57ed9fSAtsushi Murai     if (logit) {
252af57ed9fSAtsushi Murai       icmph = (struct icmp *)ptop;
253af57ed9fSAtsushi Murai       logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
254af57ed9fSAtsushi Murai       logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
255af57ed9fSAtsushi Murai     }
256af57ed9fSAtsushi Murai     break;
257af57ed9fSAtsushi Murai   case IPPROTO_UDP:
258af57ed9fSAtsushi Murai     if (logit) {
259af57ed9fSAtsushi Murai       uh = (struct udphdr *)ptop;
260af57ed9fSAtsushi Murai       logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
261af57ed9fSAtsushi Murai       logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
262af57ed9fSAtsushi Murai     }
263af57ed9fSAtsushi Murai     break;
264af57ed9fSAtsushi Murai   case IPPROTO_TCP:
265af57ed9fSAtsushi Murai     th = (struct tcphdr *)ptop;
266af57ed9fSAtsushi Murai     if (pip->ip_tos == IPTOS_LOWDELAY)
267af57ed9fSAtsushi Murai       pri = PRI_FAST;
268af57ed9fSAtsushi Murai     else if (pip->ip_off == 0) {
269af57ed9fSAtsushi Murai       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
270af57ed9fSAtsushi Murai 	 pri = PRI_FAST;
271af57ed9fSAtsushi Murai     }
272af57ed9fSAtsushi Murai 
273af57ed9fSAtsushi Murai     if (logit) {
274af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
275af57ed9fSAtsushi Murai       logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
276af57ed9fSAtsushi Murai       logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
277af57ed9fSAtsushi Murai       n = 0;
278af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
279af57ed9fSAtsushi Murai 	if (th->th_flags & mask)
280af57ed9fSAtsushi Murai 	  logprintf(" %s", TcpFlags[n]);
281af57ed9fSAtsushi Murai 	n++;
282af57ed9fSAtsushi Murai       }
283af57ed9fSAtsushi Murai       logprintf("  seq:%x  ack:%x (%d/%d)\n",
284af57ed9fSAtsushi Murai 	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
285af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
286af57ed9fSAtsushi Murai         u_short *sp;
287af57ed9fSAtsushi Murai 
288af57ed9fSAtsushi Murai 	ptop += 20;
289af57ed9fSAtsushi Murai 	sp = (u_short *)ptop;
290af57ed9fSAtsushi Murai 	if (ntohs(sp[0]) == 0x0204)
291af57ed9fSAtsushi Murai 	  logprintf(" MSS = %d\n", ntohs(sp[1]));
292af57ed9fSAtsushi Murai       }
293af57ed9fSAtsushi Murai     }
294af57ed9fSAtsushi Murai     break;
295af57ed9fSAtsushi Murai   }
296af57ed9fSAtsushi Murai   pri = FilterCheck(pip, direction);
297af57ed9fSAtsushi Murai   if (pri & A_DENY) {
298af57ed9fSAtsushi Murai #ifdef DEBUG
299af57ed9fSAtsushi Murai     logprintf("blocked.\n");
300af57ed9fSAtsushi Murai #endif
301af57ed9fSAtsushi Murai     if (direction == 0) IcmpError(pip, pri);
302af57ed9fSAtsushi Murai     return(-1);
303af57ed9fSAtsushi Murai   } else {
30453c9f6c0SAtsushi Murai     if ( FilterCheck(pip, 3) & A_DENY ) {  /* Check Keep Alive filter */
30553c9f6c0SAtsushi Murai 	ipKeepAlive = FALSE;
30653c9f6c0SAtsushi Murai     } else {
30753c9f6c0SAtsushi Murai 	ipKeepAlive = TRUE;
30853c9f6c0SAtsushi Murai     }
309af57ed9fSAtsushi Murai     return(pri);
310af57ed9fSAtsushi Murai   }
311af57ed9fSAtsushi Murai }
312af57ed9fSAtsushi Murai 
313af57ed9fSAtsushi Murai void
314af57ed9fSAtsushi Murai IpInput(bp)
315af57ed9fSAtsushi Murai struct mbuf *bp;		/* IN: Pointer to IP pakcet */
316af57ed9fSAtsushi Murai {
317af57ed9fSAtsushi Murai   u_char *cp;
318af57ed9fSAtsushi Murai   struct mbuf *wp;
319af57ed9fSAtsushi Murai   int nb, nw;
320af57ed9fSAtsushi Murai   u_char tunbuff[MAX_MRU];
321af57ed9fSAtsushi Murai 
322af57ed9fSAtsushi Murai   cp = tunbuff;
323af57ed9fSAtsushi Murai   nb = 0;
324af57ed9fSAtsushi Murai   for (wp = bp; wp; wp = wp->next) {		/* Copy to continuois region */
325af57ed9fSAtsushi Murai     bcopy(MBUF_CTOP(wp), cp, wp->cnt);
326af57ed9fSAtsushi Murai     cp += wp->cnt;
327af57ed9fSAtsushi Murai     nb += wp->cnt;
328af57ed9fSAtsushi Murai   }
329af57ed9fSAtsushi Murai 
330af57ed9fSAtsushi Murai   if (PacketCheck(tunbuff, nb, 0) < 0) {
331af57ed9fSAtsushi Murai     pfree(bp);
332af57ed9fSAtsushi Murai     return;
333af57ed9fSAtsushi Murai   }
334af57ed9fSAtsushi Murai 
335af57ed9fSAtsushi Murai   ipInOctets += nb;
336af57ed9fSAtsushi Murai   /*
337af57ed9fSAtsushi Murai    *  Pass it to tunnel device
338af57ed9fSAtsushi Murai    */
339af57ed9fSAtsushi Murai   nw = write(tun_out, tunbuff, nb);
340af57ed9fSAtsushi Murai   if (nw != nb)
341af57ed9fSAtsushi Murai     fprintf(stderr, "wrote %d, got %d\r\n");
342af57ed9fSAtsushi Murai   pfree(bp);
343af57ed9fSAtsushi Murai 
344af57ed9fSAtsushi Murai   RestartIdleTimer();
345af57ed9fSAtsushi Murai }
346af57ed9fSAtsushi Murai 
347af57ed9fSAtsushi Murai void
348af57ed9fSAtsushi Murai IpOutput(ptr, cnt)
349af57ed9fSAtsushi Murai u_char *ptr;			/* IN: Pointer to IP packet */
350af57ed9fSAtsushi Murai int cnt;			/* IN: Length of packet */
351af57ed9fSAtsushi Murai {
352af57ed9fSAtsushi Murai   struct mbuf *bp;
353af57ed9fSAtsushi Murai   int pri;
354af57ed9fSAtsushi Murai 
355af57ed9fSAtsushi Murai   if (IpcpFsm.state != ST_OPENED)
356af57ed9fSAtsushi Murai     return;
357af57ed9fSAtsushi Murai 
358af57ed9fSAtsushi Murai   pri = PacketCheck(ptr, cnt, 1);
359af57ed9fSAtsushi Murai   if (pri >= 0) {
360af57ed9fSAtsushi Murai     bp = mballoc(cnt, MB_IPIN);
361af57ed9fSAtsushi Murai     bcopy(ptr, MBUF_CTOP(bp), cnt);
36253c9f6c0SAtsushi Murai     SendPppFrame(pri, bp);
363af57ed9fSAtsushi Murai     RestartIdleTimer();
364af57ed9fSAtsushi Murai     ipOutOctets += cnt;
365af57ed9fSAtsushi Murai   }
366af57ed9fSAtsushi Murai }
367af57ed9fSAtsushi Murai 
368af57ed9fSAtsushi Murai static struct mqueue IpOutputQueues[PRI_URGENT+1];
369af57ed9fSAtsushi Murai 
370af57ed9fSAtsushi Murai void
371af57ed9fSAtsushi Murai IpEnqueue(pri, ptr, count)
372af57ed9fSAtsushi Murai int pri;
373af57ed9fSAtsushi Murai char *ptr;
374af57ed9fSAtsushi Murai int count;
375af57ed9fSAtsushi Murai {
376af57ed9fSAtsushi Murai   struct mbuf *bp;
377af57ed9fSAtsushi Murai 
378af57ed9fSAtsushi Murai   bp = mballoc(count, MB_IPQ);
379af57ed9fSAtsushi Murai   bcopy(ptr, MBUF_CTOP(bp), count);
380af57ed9fSAtsushi Murai   Enqueue(&IpOutputQueues[pri], bp);
381af57ed9fSAtsushi Murai }
382af57ed9fSAtsushi Murai 
383af57ed9fSAtsushi Murai void
384af57ed9fSAtsushi Murai IpStartOutput()
385af57ed9fSAtsushi Murai {
386af57ed9fSAtsushi Murai   struct mqueue *queue;
387af57ed9fSAtsushi Murai   struct mbuf *bp;
388af57ed9fSAtsushi Murai   int pri, cnt;
389af57ed9fSAtsushi Murai 
390af57ed9fSAtsushi Murai   if (IpcpFsm.state != ST_OPENED)
391af57ed9fSAtsushi Murai     return;
392af57ed9fSAtsushi Murai   pri = PRI_URGENT;
393af57ed9fSAtsushi Murai   for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
394af57ed9fSAtsushi Murai     if (queue->top) {
395af57ed9fSAtsushi Murai       bp = Dequeue(queue);
396af57ed9fSAtsushi Murai       if (bp) {
397af57ed9fSAtsushi Murai 	cnt = plength(bp);
39853c9f6c0SAtsushi Murai 	SendPppFrame(pri, bp);
399af57ed9fSAtsushi Murai 	RestartIdleTimer();
400af57ed9fSAtsushi Murai 	ipOutOctets += cnt;
401af57ed9fSAtsushi Murai        }
402af57ed9fSAtsushi Murai     }
403af57ed9fSAtsushi Murai     pri--;
404af57ed9fSAtsushi Murai   }
405af57ed9fSAtsushi Murai }
406