fix up MD4 stuff - interface is better now
[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.2 1997/04/30 05:50:26 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 static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
72 static void cbcp_resp __P((cbcp_state *us));
73 static void cbcp_up __P((cbcp_state *us));
74 static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
75 static void cbcp_send __P((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;
193
194     if (plen < HEADERLEN)
195         return 0;
196     pstart = p;
197     GETCHAR(code, p);
198     GETCHAR(id, p);
199     GETSHORT(len, p);
200     if (len < HEADERLEN || len > plen)
201         return 0;
202
203     if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
204         printer(arg, " %s", cbcp_codenames[code-1]);
205     else
206         printer(arg, " code=0x%x", code); 
207
208     printer(arg, " id=0x%x", id);
209     len -= HEADERLEN;
210
211     switch (code) {
212     case CBCP_REQ:
213     case CBCP_RESP:
214     case CBCP_ACK:
215         while(len >= 2) {
216             GETCHAR(opt, p);
217             GETCHAR(olen, p);
218
219             if (olen < 2 || olen > len) {
220                 break;
221             }
222
223             printer(arg, " <");
224             len -= olen;
225
226             if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
227                 printer(arg, " %s", cbcp_optionnames[opt-1]);
228             else
229                 printer(arg, " option=0x%x", opt); 
230
231             if (olen > 2) {
232                 GETCHAR(delay, p);
233                 printer(arg, " delay = %d", delay);
234             }
235
236             if (olen > 3) {
237                 int addrt;
238                 char str[256];
239
240                 GETCHAR(addrt, p);
241                 memcpy(str, p, olen - 4);
242                 str[olen - 4] = 0;
243                 printer(arg, " number = %s", str);
244             }
245             printer(arg, ">");
246             break;
247         }
248
249     default:
250         break;
251     }
252
253     for (; len > 0; --len) {
254         GETCHAR(code, p);
255         printer(arg, " %.2x", code);
256     }
257
258     return p - pstart;
259 }
260
261 /* received CBCP request */
262 static void
263 cbcp_recvreq(us, pckt, pcktlen)
264     cbcp_state *us;
265     char *pckt;
266     int pcktlen;
267 {
268     u_char type, opt_len, delay, addr_type;
269     char address[256];
270     int len = pcktlen;
271
272     address[0] = 0;
273
274     while (len) {
275         syslog(LOG_DEBUG, "length: %d", len);
276
277         GETCHAR(type, pckt);
278         GETCHAR(opt_len, pckt);
279
280         if (opt_len > 2)
281             GETCHAR(delay, pckt);
282
283         us->us_allowed |= (1 << type);
284
285         switch(type) {
286         case CB_CONF_NO:
287             syslog(LOG_DEBUG, "no callback allowed");
288             break;
289
290         case CB_CONF_USER:
291             syslog(LOG_DEBUG, "user callback allowed");
292             if (opt_len > 4) {
293                 GETCHAR(addr_type, pckt);
294                 memcpy(address, pckt, opt_len - 4);
295                 address[opt_len - 4] = 0;
296                 if (address[0])
297                     syslog(LOG_DEBUG, "address: %s", address);
298             }
299             break;
300
301         case CB_CONF_ADMIN:
302             syslog(LOG_DEBUG, "user admin defined allowed");
303             break;
304
305         case CB_CONF_LIST:
306             break;
307         }
308         len -= opt_len;
309     }
310
311     cbcp_resp(us);
312 }
313
314 static void
315 cbcp_resp(us)
316     cbcp_state *us;
317 {
318     u_char cb_type;
319     u_char buf[256];
320     u_char *bufp = buf;
321     int len = 0;
322
323     cb_type = us->us_allowed & us->us_type;
324     syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
325
326 #if 0
327     if (!cb_type)
328         lcp_down(us->us_unit);
329 #endif
330
331     if (cb_type & ( 1 << CB_CONF_USER ) ) {
332         syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
333         PUTCHAR(CB_CONF_USER, bufp);
334         len = 3 + 1 + strlen(us->us_number) + 1;
335         PUTCHAR(len , bufp);
336         PUTCHAR(5, bufp); /* delay */
337         PUTCHAR(1, bufp);
338         BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
339         cbcp_send(us, CBCP_RESP, buf, len);
340         return;
341     }
342
343     if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
344         syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
345         PUTCHAR(CB_CONF_ADMIN, bufp);
346         len = 3 + 1;
347         PUTCHAR(len , bufp);
348         PUTCHAR(5, bufp); /* delay */
349         PUTCHAR(0, bufp);
350         cbcp_send(us, CBCP_RESP, buf, len);
351         return;
352     }
353
354     if (cb_type & ( 1 << CB_CONF_NO ) ) {
355         syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
356         PUTCHAR(CB_CONF_NO, bufp);
357         len = 3;
358         PUTCHAR(len , bufp);
359         PUTCHAR(0, bufp);
360         cbcp_send(us, CBCP_RESP, buf, len);
361         (*ipcp_protent.open)(us->us_unit);
362         return;
363     }
364 }
365
366 static void
367 cbcp_send(us, code, buf, len)
368     cbcp_state *us;
369     u_char code;
370     u_char *buf;
371     int len;
372 {
373     u_char *outp;
374     int outlen;
375
376     outp = outpacket_buf;
377
378     outlen = 4 + len;
379     
380     MAKEHEADER(outp, PPP_CBCP);
381
382     PUTCHAR(code, outp);
383     PUTCHAR(us->us_id, outp);
384     PUTSHORT(outlen, outp);
385     
386     if (len)
387         BCOPY(buf, outp, len);
388
389     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
390 }
391
392 static void
393 cbcp_recvack(us, pckt, len)
394     cbcp_state *us;
395     char *pckt;
396     int len;
397 {
398     u_char type, delay, addr_type;
399     int opt_len;
400     char address[256];
401
402     if (len) {
403         GETCHAR(type, pckt);
404         GETCHAR(opt_len, pckt);
405      
406         if (opt_len > 2)
407             GETCHAR(delay, pckt);
408
409         if (opt_len > 4) {
410             GETCHAR(addr_type, pckt);
411             memcpy(address, pckt, opt_len - 4);
412             address[opt_len - 4] = 0;
413             if (address[0])
414                 syslog(LOG_DEBUG, "peer will call: %s", address);
415         }
416     }
417
418     cbcp_up(us);
419 }
420
421 extern int persist;
422
423 /* ok peer will do callback */
424 static void
425 cbcp_up(us)
426     cbcp_state *us;
427 {
428     persist = 0;
429     lcp_close(0, "Call me back, please");
430 }