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