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