allow chars 0x20 - 0x3f to be escaped
[ppp.git] / pppd / cbcp.c
1 /*
2  * cbcp - Call Back Configuration Protocol.
3  *
4  * Copyright (c) 1995 Pedro Roque Marques
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 Pedro Roque Marques.  The name of the author may not be used to
13  * endorse or promote products derived from this software without
14  * specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20
21 #ifndef lint
22 static char rcsid[] = "$Id: cbcp.c,v 1.3 1998/11/07 06:59:25 paulus Exp $";
23 #endif
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <syslog.h>
30
31 #include "pppd.h"
32 #include "cbcp.h"
33 #include "fsm.h"
34 #include "lcp.h"
35 #include "ipcp.h"
36
37 /*
38  * Options.
39  */
40 static int setcbcp __P((char **));
41
42 static option_t cbcp_option_list[] = {
43     { "callback", o_special, setcbcp,
44       "Ask for callback" },
45     { NULL }
46 };
47
48 /*
49  * Protocol entry points.
50  */
51 static void cbcp_init      __P((int unit));
52 static void cbcp_open      __P((int unit));
53 static void cbcp_lowerup   __P((int unit));
54 static void cbcp_input     __P((int unit, u_char *pkt, int len));
55 static void cbcp_protrej   __P((int unit));
56 static int  cbcp_printpkt  __P((u_char *pkt, int len,
57                                 void (*printer) __P((void *, char *, ...)),
58                                 void *arg));
59
60 struct protent cbcp_protent = {
61     PPP_CBCP,
62     cbcp_init,
63     cbcp_input,
64     cbcp_protrej,
65     cbcp_lowerup,
66     NULL,
67     cbcp_open,
68     NULL,
69     cbcp_printpkt,
70     NULL,
71     0,
72     "CBCP",
73     cbcp_option_list,
74     NULL,
75     NULL,
76     NULL,
77     NULL
78 };
79
80 cbcp_state cbcp[NUM_PPP];       
81
82 /* internal prototypes */
83
84 static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
85 static void cbcp_resp __P((cbcp_state *us));
86 static void cbcp_up __P((cbcp_state *us));
87 static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
88 static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
89
90 /* option processing */
91 static int
92 setcbcp(argv)
93     char **argv;
94 {
95     lcp_wantoptions[0].neg_cbcp = 1;
96     cbcp_protent.enabled_flag = 1;
97     cbcp[0].us_number = strdup(*argv);
98     if (cbcp[0].us_number == 0)
99         novm("callback number");
100     cbcp[0].us_type |= (1 << CB_CONF_USER);
101     cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
102     return (1);
103 }
104
105 /* init state */
106 static void
107 cbcp_init(iface)
108     int iface;
109 {
110     cbcp_state *us;
111
112     us = &cbcp[iface];
113     memset(us, 0, sizeof(cbcp_state));
114     us->us_unit = iface;
115     us->us_type |= (1 << CB_CONF_NO);
116 }
117
118 /* lower layer is up */
119 static void
120 cbcp_lowerup(iface)
121     int iface;
122 {
123     cbcp_state *us = &cbcp[iface];
124
125     syslog(LOG_DEBUG, "cbcp_lowerup");
126     syslog(LOG_DEBUG, "want: %d", us->us_type);
127
128     if (us->us_type == CB_CONF_USER)
129         syslog(LOG_DEBUG, "phone no: %s", us->us_number);
130 }
131
132 static void
133 cbcp_open(unit)
134     int unit;
135 {
136     syslog(LOG_DEBUG, "cbcp_open");
137 }
138
139 /* process an incomming packet */
140 static void
141 cbcp_input(unit, inpacket, pktlen)
142     int unit;
143     u_char *inpacket;
144     int pktlen;
145 {
146     u_char *inp;
147     u_char code, id;
148     u_short len;
149
150     cbcp_state *us = &cbcp[unit];
151
152     inp = inpacket;
153
154     if (pktlen < CBCP_MINLEN) {
155         syslog(LOG_ERR, "CBCP packet is too small");
156         return;
157     }
158
159     GETCHAR(code, inp);
160     GETCHAR(id, inp);
161     GETSHORT(len, inp);
162
163 #if 0
164     if (len > pktlen) {
165         syslog(LOG_ERR, "CBCP packet: invalid length");
166         return;
167     }
168 #endif
169
170     len -= CBCP_MINLEN;
171  
172     switch(code) {
173     case CBCP_REQ:
174         us->us_id = id;
175         cbcp_recvreq(us, inp, len);
176         break;
177
178     case CBCP_RESP:
179         syslog(LOG_DEBUG, "CBCP_RESP received");
180         break;
181
182     case CBCP_ACK:
183         if (id != us->us_id)
184             syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
185                    us->us_id, id);
186
187         cbcp_recvack(us, inp, len);
188         break;
189
190     default:
191         break;
192     }
193 }
194
195 /* protocol was rejected by foe */
196 void cbcp_protrej(int iface)
197 {
198 }
199
200 char *cbcp_codenames[] = {
201     "Request", "Response", "Ack"
202 };
203
204 char *cbcp_optionnames[] = {
205     "NoCallback",
206     "UserDefined",
207     "AdminDefined",
208     "List"
209 };
210
211 /* pretty print a packet */
212 static int
213 cbcp_printpkt(p, plen, printer, arg)
214     u_char *p;
215     int plen;
216     void (*printer) __P((void *, char *, ...));
217     void *arg;
218 {
219     int code, opt, id, len, olen, delay;
220     u_char *pstart;
221
222     if (plen < HEADERLEN)
223         return 0;
224     pstart = p;
225     GETCHAR(code, p);
226     GETCHAR(id, p);
227     GETSHORT(len, p);
228     if (len < HEADERLEN || len > plen)
229         return 0;
230
231     if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
232         printer(arg, " %s", cbcp_codenames[code-1]);
233     else
234         printer(arg, " code=0x%x", code); 
235
236     printer(arg, " id=0x%x", id);
237     len -= HEADERLEN;
238
239     switch (code) {
240     case CBCP_REQ:
241     case CBCP_RESP:
242     case CBCP_ACK:
243         while(len >= 2) {
244             GETCHAR(opt, p);
245             GETCHAR(olen, p);
246
247             if (olen < 2 || olen > len) {
248                 break;
249             }
250
251             printer(arg, " <");
252             len -= olen;
253
254             if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
255                 printer(arg, " %s", cbcp_optionnames[opt-1]);
256             else
257                 printer(arg, " option=0x%x", opt); 
258
259             if (olen > 2) {
260                 GETCHAR(delay, p);
261                 printer(arg, " delay = %d", delay);
262             }
263
264             if (olen > 3) {
265                 int addrt;
266                 char str[256];
267
268                 GETCHAR(addrt, p);
269                 memcpy(str, p, olen - 4);
270                 str[olen - 4] = 0;
271                 printer(arg, " number = %s", str);
272             }
273             printer(arg, ">");
274             break;
275         }
276
277     default:
278         break;
279     }
280
281     for (; len > 0; --len) {
282         GETCHAR(code, p);
283         printer(arg, " %.2x", code);
284     }
285
286     return p - pstart;
287 }
288
289 /* received CBCP request */
290 static void
291 cbcp_recvreq(us, pckt, pcktlen)
292     cbcp_state *us;
293     char *pckt;
294     int pcktlen;
295 {
296     u_char type, opt_len, delay, addr_type;
297     char address[256];
298     int len = pcktlen;
299
300     address[0] = 0;
301
302     while (len) {
303         syslog(LOG_DEBUG, "length: %d", len);
304
305         GETCHAR(type, pckt);
306         GETCHAR(opt_len, pckt);
307
308         if (opt_len > 2)
309             GETCHAR(delay, pckt);
310
311         us->us_allowed |= (1 << type);
312
313         switch(type) {
314         case CB_CONF_NO:
315             syslog(LOG_DEBUG, "no callback allowed");
316             break;
317
318         case CB_CONF_USER:
319             syslog(LOG_DEBUG, "user callback allowed");
320             if (opt_len > 4) {
321                 GETCHAR(addr_type, pckt);
322                 memcpy(address, pckt, opt_len - 4);
323                 address[opt_len - 4] = 0;
324                 if (address[0])
325                     syslog(LOG_DEBUG, "address: %s", address);
326             }
327             break;
328
329         case CB_CONF_ADMIN:
330             syslog(LOG_DEBUG, "user admin defined allowed");
331             break;
332
333         case CB_CONF_LIST:
334             break;
335         }
336         len -= opt_len;
337     }
338
339     cbcp_resp(us);
340 }
341
342 static void
343 cbcp_resp(us)
344     cbcp_state *us;
345 {
346     u_char cb_type;
347     u_char buf[256];
348     u_char *bufp = buf;
349     int len = 0;
350
351     cb_type = us->us_allowed & us->us_type;
352     syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
353
354 #if 0
355     if (!cb_type)
356         lcp_down(us->us_unit);
357 #endif
358
359     if (cb_type & ( 1 << CB_CONF_USER ) ) {
360         syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
361         PUTCHAR(CB_CONF_USER, bufp);
362         len = 3 + 1 + strlen(us->us_number) + 1;
363         PUTCHAR(len , bufp);
364         PUTCHAR(5, bufp); /* delay */
365         PUTCHAR(1, bufp);
366         BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
367         cbcp_send(us, CBCP_RESP, buf, len);
368         return;
369     }
370
371     if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
372         syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
373         PUTCHAR(CB_CONF_ADMIN, bufp);
374         len = 3 + 1;
375         PUTCHAR(len , bufp);
376         PUTCHAR(5, bufp); /* delay */
377         PUTCHAR(0, bufp);
378         cbcp_send(us, CBCP_RESP, buf, len);
379         return;
380     }
381
382     if (cb_type & ( 1 << CB_CONF_NO ) ) {
383         syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
384         PUTCHAR(CB_CONF_NO, bufp);
385         len = 3;
386         PUTCHAR(len , bufp);
387         PUTCHAR(0, bufp);
388         cbcp_send(us, CBCP_RESP, buf, len);
389         (*ipcp_protent.open)(us->us_unit);
390         return;
391     }
392 }
393
394 static void
395 cbcp_send(us, code, buf, len)
396     cbcp_state *us;
397     u_char code;
398     u_char *buf;
399     int len;
400 {
401     u_char *outp;
402     int outlen;
403
404     outp = outpacket_buf;
405
406     outlen = 4 + len;
407     
408     MAKEHEADER(outp, PPP_CBCP);
409
410     PUTCHAR(code, outp);
411     PUTCHAR(us->us_id, outp);
412     PUTSHORT(outlen, outp);
413     
414     if (len)
415         BCOPY(buf, outp, len);
416
417     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
418 }
419
420 static void
421 cbcp_recvack(us, pckt, len)
422     cbcp_state *us;
423     char *pckt;
424     int len;
425 {
426     u_char type, delay, addr_type;
427     int opt_len;
428     char address[256];
429
430     if (len) {
431         GETCHAR(type, pckt);
432         GETCHAR(opt_len, pckt);
433      
434         if (opt_len > 2)
435             GETCHAR(delay, pckt);
436
437         if (opt_len > 4) {
438             GETCHAR(addr_type, pckt);
439             memcpy(address, pckt, opt_len - 4);
440             address[opt_len - 4] = 0;
441             if (address[0])
442                 syslog(LOG_DEBUG, "peer will call: %s", address);
443         }
444     }
445
446     cbcp_up(us);
447 }
448
449 extern int persist;
450
451 /* ok peer will do callback */
452 static void
453 cbcp_up(us)
454     cbcp_state *us;
455 {
456     persist = 0;
457     lcp_close(0, "Call me back, please");
458 }