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