xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/pppd/demand.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * demand.c - Support routines for demand-dialling.
3  *
4  * Copyright 2000-2002 Sun Microsystems, Inc.  All rights reserved.
5  * Use is subject to license terms.
6  *
7  * Copyright (c) 1993 The Australian National University.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that the above copyright notice and this paragraph are
12  * duplicated in all such forms and that any documentation,
13  * advertising materials, and other materials related to such
14  * distribution and use acknowledge that the software was developed
15  * by the Australian National University.  The name of the University
16  * may not be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22 
23 #pragma ident	"%Z%%M%	%I%	%E% SMI"
24 #define RCSID	"$Id: demand.c,v 1.13 2000/04/15 01:27:11 masputra Exp $"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <netdb.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <sys/time.h>
36 #include <sys/resource.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #ifdef PPP_FILTER
40 #include <net/if.h>
41 #include <net/bpf.h>
42 #include <pcap.h>
43 #endif
44 
45 #include "pppd.h"
46 #include "fsm.h"
47 #include "lcp.h"
48 
49 #if !defined(lint) && !defined(_lint)
50 static const char rcsid[] = RCSID;
51 #endif
52 
53 static char *frame;
54 static int framelen;
55 static int framemax;
56 static int escape_flag;
57 static int flush_flag;
58 static int fcs;
59 
60 struct packet {
61     int length;
62     struct packet *next;
63     unsigned char data[1];
64 };
65 
66 static struct packet *pend_q;
67 static struct packet *pend_qtail;
68 
69 static int active_packet __P((unsigned char *, int));
70 
71 /*
72  * demand_conf - configure the interface for doing dial-on-demand.
73  */
74 void
75 demand_conf()
76 {
77     int i;
78     struct protent *protp;
79     int mtu;
80 
81     framemax = lcp_wantoptions[0].mru;
82     if (framemax < PPP_MRU)
83 	    framemax = PPP_MRU;
84     framemax += PPP_HDRLEN + PPP_FCSLEN;
85     frame = malloc(framemax);
86     if (frame == NULL)
87 	novm("demand frame");
88     framelen = 0;
89     pend_q = NULL;
90     escape_flag = 0;
91     flush_flag = 0;
92     fcs = PPP_INITFCS;
93 
94     if ((mtu = lcp_allowoptions[0].mru) == 0)
95         mtu = PPP_MTU;
96     ppp_send_config(0, mtu, (u_int32_t) 0, 0, 0);
97     ppp_recv_config(0, framemax, (u_int32_t) 0, 0, 0);
98 
99 #ifdef PPP_FILTER
100     set_filters(&pass_filter, &active_filter);
101 #endif
102 
103     /*
104      * Call the demand_conf procedure for each protocol that's got one.
105      */
106     for (i = 0; (protp = protocols[i]) != NULL; ++i)
107 	if (protp->enabled_flag && protp->demand_conf != NULL)
108 	    if (!((*protp->demand_conf)(0)))
109 		fatal("unable to set demand configuration on %s", protp->name);
110 }
111 
112 
113 /*
114  * demand_block - set each network protocol to block further packets.
115  */
116 void
117 demand_block()
118 {
119     int i;
120     struct protent *protp;
121 
122     for (i = 0; (protp = protocols[i]) != NULL; ++i)
123 	if (protp->enabled_flag && protp->demand_conf != NULL &&
124 	    !sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE))
125 	    fatal("unable to enable queuing for %s", protp->name);
126     /* Intentionally discard return value; we're on our way up now. */
127     (void) get_loop_output();
128 }
129 
130 /*
131  * demand_discard - set each network protocol to discard packets
132  * with an error.
133  */
134 void
135 demand_discard()
136 {
137     struct packet *pkt, *nextpkt;
138     int i;
139     struct protent *protp;
140 
141     for (i = 0; (protp = protocols[i]) != NULL; ++i)
142 	if (protp->enabled_flag && protp->demand_conf != NULL &&
143 	    !sifnpmode(0, protp->protocol & ~0x8000, NPMODE_DROP))
144 	    fatal("unable to disable %s", protp->name);
145 
146     /* Intentionally discard return value; we're on our way down now. */
147     (void) get_loop_output();
148 
149     /* discard all saved packets */
150     for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
151 	nextpkt = pkt->next;
152 	free(pkt);
153     }
154     pend_q = NULL;
155     framelen = 0;
156     flush_flag = 0;
157     escape_flag = 0;
158     fcs = PPP_INITFCS;
159 }
160 
161 /*
162  * demand_unblock - set each enabled network protocol to pass packets.
163  */
164 void
165 demand_unblock()
166 {
167     int i;
168     struct protent *protp;
169 
170     for (i = 0; (protp = protocols[i]) != NULL; ++i)
171 	if (protp->enabled_flag && protp->demand_conf != NULL &&
172 	    !sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS))
173 	    fatal("unable to enable %s", protp->name);
174 }
175 
176 /*
177  * FCS lookup table as calculated by genfcstab.
178  */
179 static u_short fcstab[256] = {
180 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
181 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
182 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
183 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
184 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
185 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
186 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
187 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
188 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
189 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
190 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
191 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
192 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
193 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
194 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
195 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
196 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
197 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
198 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
199 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
200 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
201 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
202 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
203 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
204 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
205 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
206 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
207 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
208 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
209 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
210 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
211 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
212 };
213 
214 /*
215  * loop_chars - process characters received from the loopback.
216  * Calls loop_frame when a complete frame has been accumulated.
217  * Return value is 1 if we need to bring up the link, 0 otherwise.
218  */
219 int
220 loop_chars(p, n)
221     unsigned char *p;
222     int n;
223 {
224     int c, rv;
225 
226     rv = 0;
227     for (; n > 0; --n) {
228 	c = *p++;
229 	if (c == PPP_FLAG) {
230 	    if (!escape_flag && !flush_flag
231 		&& framelen > 2 && fcs == PPP_GOODFCS) {
232 		framelen -= 2;
233 		if (loop_frame((unsigned char *)frame, framelen))
234 		    rv = 1;
235 	    }
236 	    framelen = 0;
237 	    flush_flag = 0;
238 	    escape_flag = 0;
239 	    fcs = PPP_INITFCS;
240 	    continue;
241 	}
242 	if (flush_flag)
243 	    continue;
244 	if (escape_flag) {
245 	    c ^= PPP_TRANS;
246 	    escape_flag = 0;
247 	} else if (c == PPP_ESCAPE) {
248 	    escape_flag = 1;
249 	    continue;
250 	}
251 	if (framelen >= framemax) {
252 	    flush_flag = 1;
253 	    continue;
254 	}
255 	frame[framelen++] = c;
256 	fcs = PPP_FCS(fcs, c);
257     }
258     return rv;
259 }
260 
261 /*
262  * loop_frame - given a frame obtained from the loopback,
263  * decide whether to bring up the link or not, and, if we want
264  * to transmit this frame later, put it on the pending queue.
265  * Return value is 1 if we need to bring up the link, 0 otherwise.
266  * We assume that the kernel driver has already applied the
267  * pass_filter, so we won't get packets it rejected.
268  * We apply the active_filter to see if we want this packet to
269  * bring up the link.
270  */
271 int
272 loop_frame(frame, len)
273     unsigned char *frame;
274     int len;
275 {
276     struct packet *pkt;
277 
278     if (len < PPP_HDRLEN)
279 	return 0;
280     if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
281 	return 0;		/* shouldn't get any of these anyway */
282 
283     /* Note - once we have pending packets, we don't drop any more. */
284     if (pend_q == NULL && !active_packet(frame, len))
285 	return 0;
286 
287     pkt = (struct packet *) malloc(sizeof(struct packet) + len);
288     if (pkt != NULL) {
289 	pkt->length = len;
290 	pkt->next = NULL;
291 	(void) memcpy(pkt->data, frame, len);
292 	if (pend_q == NULL)
293 	    pend_q = pkt;
294 	else
295 	    pend_qtail->next = pkt;
296 	pend_qtail = pkt;
297     }
298     return 1;
299 }
300 
301 /*
302  * demand_rexmit - Resend all those frames that we got via the
303  * loopback, now that the real serial link is up.
304  */
305 void
306 demand_rexmit(proto)
307     int proto;
308 {
309     struct packet *pkt, *prev, *nextpkt;
310 
311     prev = NULL;
312     pkt = pend_q;
313     pend_q = NULL;
314     for (; pkt != NULL; pkt = nextpkt) {
315 	nextpkt = pkt->next;
316 	if (PPP_PROTOCOL(pkt->data) == proto) {
317 	    output(0, pkt->data, pkt->length);
318 	    free(pkt);
319 	} else {
320 	    if (prev == NULL)
321 		pend_q = pkt;
322 	    else
323 		prev->next = pkt;
324 	    prev = pkt;
325 	}
326     }
327     pend_qtail = prev;
328     if (prev != NULL)
329 	prev->next = NULL;
330 }
331 
332 /*
333  * Scan a packet to decide whether it is an "active" packet,
334  * that is, whether it is worth bringing up the link for.
335  */
336 static int
337 active_packet(p, len)
338     unsigned char *p;
339     int len;
340 {
341     int proto, i;
342     struct protent *protp;
343     const char *cp;
344     char pbuf[32];
345 
346     if (len < PPP_HDRLEN)
347 	return 0;
348 #ifdef PPP_FILTER
349     if (active_filter.bf_len != 0
350 	&& bpf_filter(active_filter.bf_insns, frame, len, len) == 0) {
351 	dbglog("BPF identified packet as not worth bringing up the link.");
352 	return 0;
353     }
354 #endif
355     proto = PPP_PROTOCOL(p);
356     for (i = 0; (protp = protocols[i]) != NULL; ++i) {
357 	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
358 	    if (!protp->enabled_flag) {
359 		dbglog("%s: not enabled; not bringing up link", protp->name);
360 		return 0;
361 	    }
362 	    if (protp->active_pkt == NULL) {
363 		dbglog("%s: no active test; bringing up link", protp->name);
364 		return 1;
365 	    }
366 	    i = (*protp->active_pkt)(p, len);
367 	    dbglog("%s: active test; %sbringing up link", protp->name,
368 		i != 0 ? "" : "not ");
369 	    return i;
370 	}
371     }
372     if ((cp = protocol_name(proto)) == NULL) {
373 	(void) slprintf(pbuf, sizeof (pbuf), "0x#X", proto);
374 	cp = (const char *)pbuf;
375     }
376     dbglog("%s: unknown protocol; not bringing up link", cp);
377     return 0;			/* not a supported protocol !!?? */
378 }
379