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