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