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