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
demand_conf()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
demand_block()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
demand_discard()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
demand_unblock()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
loop_chars(p,n)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
loop_frame(frame,len)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
demand_rexmit(proto)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
active_packet(p,len)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