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