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