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