Merge from vendor branch GDB:
[dragonfly.git] / usr.sbin / 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  * $FreeBSD: src/usr.sbin/pppd/cbcp.c,v 1.4 1999/08/28 01:19:00 peter Exp $
21  * $DragonFly: src/usr.sbin/pppd/cbcp.c,v 1.4 2004/11/05 07:27:20 dillon Exp $
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <syslog.h>
29
30 #include "pppd.h"
31 #include "cbcp.h"
32 #include "fsm.h"
33 #include "lcp.h"
34 #include "ipcp.h"
35
36 /*
37  * Protocol entry points.
38  */
39 static void cbcp_init     (int unit);
40 static void cbcp_open     (int unit);
41 static void cbcp_lowerup  (int unit);
42 static void cbcp_input    (int unit, u_char *pkt, int len);
43 static void cbcp_protrej  (int unit);
44 static int  cbcp_printpkt (u_char *pkt, int len,
45                                 void (*printer)(void *, char *, ...),
46                                 void *arg);
47
48 struct protent cbcp_protent = {
49     PPP_CBCP,
50     cbcp_init,
51     cbcp_input,
52     cbcp_protrej,
53     cbcp_lowerup,
54     NULL,
55     cbcp_open,
56     NULL,
57     cbcp_printpkt,
58     NULL,
59     0,
60     "CBCP",
61     NULL,
62     NULL,
63     NULL
64 };
65
66 cbcp_state cbcp[NUM_PPP];       
67
68 /* internal prototypes */
69
70 static void cbcp_recvreq(cbcp_state *us, char *pckt, int len);
71 static void cbcp_resp(cbcp_state *us);
72 static void cbcp_up(cbcp_state *us);
73 static void cbcp_recvack(cbcp_state *us, char *pckt, int len);
74 static void cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len);
75
76 /* init state */
77 static void
78 cbcp_init(iface)
79     int iface;
80 {
81     cbcp_state *us;
82
83     us = &cbcp[iface];
84     memset(us, 0, sizeof(cbcp_state));
85     us->us_unit = iface;
86     us->us_type |= (1 << CB_CONF_NO);
87 }
88
89 /* lower layer is up */
90 static void
91 cbcp_lowerup(iface)
92     int iface;
93 {
94     cbcp_state *us = &cbcp[iface];
95
96     syslog(LOG_DEBUG, "cbcp_lowerup");
97     syslog(LOG_DEBUG, "want: %d", us->us_type);
98
99     if (us->us_type == CB_CONF_USER)
100         syslog(LOG_DEBUG, "phone no: %s", us->us_number);
101 }
102
103 static void
104 cbcp_open(unit)
105     int unit;
106 {
107     syslog(LOG_DEBUG, "cbcp_open");
108 }
109
110 /* process an incomming packet */
111 static void
112 cbcp_input(unit, inpacket, pktlen)
113     int unit;
114     u_char *inpacket;
115     int pktlen;
116 {
117     u_char *inp;
118     u_char code, id;
119     u_short len;
120
121     cbcp_state *us = &cbcp[unit];
122
123     inp = inpacket;
124
125     if (pktlen < CBCP_MINLEN) {
126         syslog(LOG_ERR, "CBCP packet is too small");
127         return;
128     }
129
130     GETCHAR(code, inp);
131     GETCHAR(id, inp);
132     GETSHORT(len, inp);
133
134     if (len < CBCP_MINLEN || len > pktlen) {
135         syslog(LOG_ERR, "CBCP packet: invalid length");
136         return;
137     }
138
139     len -= CBCP_MINLEN;
140  
141     switch(code) {
142     case CBCP_REQ:
143         us->us_id = id;
144         cbcp_recvreq(us, inp, len);
145         break;
146
147     case CBCP_RESP:
148         syslog(LOG_DEBUG, "CBCP_RESP received");
149         break;
150
151     case CBCP_ACK:
152         if (id != us->us_id)
153             syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
154                    us->us_id, id);
155
156         cbcp_recvack(us, inp, len);
157         break;
158
159     default:
160         break;
161     }
162 }
163
164 /* protocol was rejected by foe */
165 void cbcp_protrej(int iface)
166 {
167 }
168
169 char *cbcp_codenames[] = {
170     "Request", "Response", "Ack"
171 };
172
173 char *cbcp_optionnames[] = {
174     "NoCallback",
175     "UserDefined",
176     "AdminDefined",
177     "List"
178 };
179
180 /* pretty print a packet */
181 static int
182 cbcp_printpkt(p, plen, printer, arg)
183     u_char *p;
184     int plen;
185     void (*printer)(void *, char *, ...);
186     void *arg;
187 {
188     int code, opt, id, len, olen, delay;
189     u_char *pstart;
190
191     if (plen < HEADERLEN)
192         return 0;
193     pstart = p;
194     GETCHAR(code, p);
195     GETCHAR(id, p);
196     GETSHORT(len, p);
197     if (len < HEADERLEN || len > plen)
198         return 0;
199
200     if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
201         printer(arg, " %s", cbcp_codenames[code-1]);
202     else
203         printer(arg, " code=0x%x", code); 
204
205     printer(arg, " id=0x%x", id);
206     len -= HEADERLEN;
207
208     switch (code) {
209     case CBCP_REQ:
210     case CBCP_RESP:
211     case CBCP_ACK:
212         while(len >= 2) {
213             GETCHAR(opt, p);
214             GETCHAR(olen, p);
215
216             if (olen < 2 || olen > len) {
217                 break;
218             }
219
220             printer(arg, " <");
221             len -= olen;
222
223             if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
224                 printer(arg, " %s", cbcp_optionnames[opt-1]);
225             else
226                 printer(arg, " option=0x%x", opt); 
227
228             if (olen > 2) {
229                 GETCHAR(delay, p);
230                 printer(arg, " delay = %d", delay);
231             }
232
233             if (olen > 3) {
234                 int addrt;
235                 char str[256];
236
237                 GETCHAR(addrt, p);
238                 memcpy(str, p, olen - 4);
239                 str[olen - 4] = 0;
240                 printer(arg, " number = %s", str);
241             }
242             printer(arg, ">");
243             break;
244         }
245
246     default:
247         break;
248     }
249
250     for (; len > 0; --len) {
251         GETCHAR(code, p);
252         printer(arg, " %.2x", code);
253     }
254
255     return p - pstart;
256 }
257
258 /* received CBCP request */
259 static void
260 cbcp_recvreq(us, pckt, pcktlen)
261     cbcp_state *us;
262     char *pckt;
263     int pcktlen;
264 {
265     u_char type, opt_len, delay, addr_type;
266     char address[256];
267     int len = pcktlen;
268
269     address[0] = 0;
270
271     while (len > 1) {
272         syslog(LOG_DEBUG, "length: %d", len);
273
274         GETCHAR(type, pckt);
275         GETCHAR(opt_len, pckt);
276
277         if (len < opt_len)
278                 break;
279         len -= opt_len;
280
281         if (opt_len > 2)
282             GETCHAR(delay, pckt);
283
284         us->us_allowed |= (1 << type);
285
286         switch(type) {
287         case CB_CONF_NO:
288             syslog(LOG_DEBUG, "no callback allowed");
289             break;
290
291         case CB_CONF_USER:
292             syslog(LOG_DEBUG, "user callback allowed");
293             if (opt_len > 4) {
294                 GETCHAR(addr_type, pckt);
295                 memcpy(address, pckt, opt_len - 4);
296                 address[opt_len - 4] = 0;
297                 if (address[0])
298                     syslog(LOG_DEBUG, "address: %s", address);
299             }
300             break;
301
302         case CB_CONF_ADMIN:
303             syslog(LOG_DEBUG, "user admin defined allowed");
304             break;
305
306         case CB_CONF_LIST:
307             break;
308         }
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 > 1) {
403         GETCHAR(type, pckt);
404         GETCHAR(opt_len, pckt);
405      
406         if (opt_len > len)
407                 return;
408
409         if (opt_len > 2)
410             GETCHAR(delay, pckt);
411
412         if (opt_len > 4) {
413             GETCHAR(addr_type, pckt);
414             memcpy(address, pckt, opt_len - 4);
415             address[opt_len - 4] = 0;
416             if (address[0])
417                 syslog(LOG_DEBUG, "peer will call: %s", address);
418         }
419     }
420
421     cbcp_up(us);
422 }
423
424 extern int persist;
425
426 /* ok peer will do callback */
427 static void
428 cbcp_up(us)
429     cbcp_state *us;
430 {
431     persist = 0;
432     lcp_close(0, "Call me back, please");
433 }