]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/pppd/cbcp.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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
21 #ifndef lint
22 static char rcsid[] = "$FreeBSD$";
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 (len < CBCP_MINLEN || len > pktlen) {
136         syslog(LOG_ERR, "CBCP packet: invalid length");
137         return;
138     }
139
140     len -= CBCP_MINLEN;
141  
142     switch(code) {
143     case CBCP_REQ:
144         us->us_id = id;
145         cbcp_recvreq(us, inp, len);
146         break;
147
148     case CBCP_RESP:
149         syslog(LOG_DEBUG, "CBCP_RESP received");
150         break;
151
152     case CBCP_ACK:
153         if (id != us->us_id)
154             syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
155                    us->us_id, id);
156
157         cbcp_recvack(us, inp, len);
158         break;
159
160     default:
161         break;
162     }
163 }
164
165 /* protocol was rejected by foe */
166 void cbcp_protrej(int iface)
167 {
168 }
169
170 char *cbcp_codenames[] = {
171     "Request", "Response", "Ack"
172 };
173
174 char *cbcp_optionnames[] = {
175     "NoCallback",
176     "UserDefined",
177     "AdminDefined",
178     "List"
179 };
180
181 /* pretty print a packet */
182 static int
183 cbcp_printpkt(p, plen, printer, arg)
184     u_char *p;
185     int plen;
186     void (*printer) __P((void *, char *, ...));
187     void *arg;
188 {
189     int code, opt, id, len, olen, delay;
190     u_char *pstart;
191
192     if (plen < HEADERLEN)
193         return 0;
194     pstart = p;
195     GETCHAR(code, p);
196     GETCHAR(id, p);
197     GETSHORT(len, p);
198     if (len < HEADERLEN || len > plen)
199         return 0;
200
201     if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
202         printer(arg, " %s", cbcp_codenames[code-1]);
203     else
204         printer(arg, " code=0x%x", code); 
205
206     printer(arg, " id=0x%x", id);
207     len -= HEADERLEN;
208
209     switch (code) {
210     case CBCP_REQ:
211     case CBCP_RESP:
212     case CBCP_ACK:
213         while(len >= 2) {
214             GETCHAR(opt, p);
215             GETCHAR(olen, p);
216
217             if (olen < 2 || olen > len) {
218                 break;
219             }
220
221             printer(arg, " <");
222             len -= olen;
223
224             if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
225                 printer(arg, " %s", cbcp_optionnames[opt-1]);
226             else
227                 printer(arg, " option=0x%x", opt); 
228
229             if (olen > 2) {
230                 GETCHAR(delay, p);
231                 printer(arg, " delay = %d", delay);
232             }
233
234             if (olen > 3) {
235                 int addrt;
236                 char str[256];
237
238                 GETCHAR(addrt, p);
239                 memcpy(str, p, olen - 4);
240                 str[olen - 4] = 0;
241                 printer(arg, " number = %s", str);
242             }
243             printer(arg, ">");
244             break;
245         }
246
247     default:
248         break;
249     }
250
251     for (; len > 0; --len) {
252         GETCHAR(code, p);
253         printer(arg, " %.2x", code);
254     }
255
256     return p - pstart;
257 }
258
259 /* received CBCP request */
260 static void
261 cbcp_recvreq(us, pckt, pcktlen)
262     cbcp_state *us;
263     char *pckt;
264     int pcktlen;
265 {
266     u_char type, opt_len, delay, addr_type;
267     char address[256];
268     int len = pcktlen;
269
270     address[0] = 0;
271
272     while (len > 1) {
273         syslog(LOG_DEBUG, "length: %d", len);
274
275         GETCHAR(type, pckt);
276         GETCHAR(opt_len, pckt);
277
278         if (len < opt_len)
279                 break;
280         len -= opt_len;
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     }
311
312     cbcp_resp(us);
313 }
314
315 static void
316 cbcp_resp(us)
317     cbcp_state *us;
318 {
319     u_char cb_type;
320     u_char buf[256];
321     u_char *bufp = buf;
322     int len = 0;
323
324     cb_type = us->us_allowed & us->us_type;
325     syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
326
327 #if 0
328     if (!cb_type)
329         lcp_down(us->us_unit);
330 #endif
331
332     if (cb_type & ( 1 << CB_CONF_USER ) ) {
333         syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
334         PUTCHAR(CB_CONF_USER, bufp);
335         len = 3 + 1 + strlen(us->us_number) + 1;
336         PUTCHAR(len , bufp);
337         PUTCHAR(5, bufp); /* delay */
338         PUTCHAR(1, bufp);
339         BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
340         cbcp_send(us, CBCP_RESP, buf, len);
341         return;
342     }
343
344     if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
345         syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
346         PUTCHAR(CB_CONF_ADMIN, bufp);
347         len = 3;
348         PUTCHAR(len, bufp);
349         PUTCHAR(5, bufp); /* delay */
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 = 2;
358         PUTCHAR(len , bufp);
359         cbcp_send(us, CBCP_RESP, buf, len);
360         (*ipcp_protent.open)(us->us_unit);
361         return;
362     }
363 }
364
365 static void
366 cbcp_send(us, code, buf, len)
367     cbcp_state *us;
368     u_char code;
369     u_char *buf;
370     int len;
371 {
372     u_char *outp;
373     int outlen;
374
375     outp = outpacket_buf;
376
377     outlen = 4 + len;
378     
379     MAKEHEADER(outp, PPP_CBCP);
380
381     PUTCHAR(code, outp);
382     PUTCHAR(us->us_id, outp);
383     PUTSHORT(outlen, outp);
384     
385     if (len)
386         BCOPY(buf, outp, len);
387
388     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
389 }
390
391 static void
392 cbcp_recvack(us, pckt, len)
393     cbcp_state *us;
394     char *pckt;
395     int len;
396 {
397     u_char type, delay, addr_type;
398     int opt_len;
399     char address[256];
400
401     if (len > 1) {
402         GETCHAR(type, pckt);
403         GETCHAR(opt_len, pckt);
404      
405         if (opt_len > len)
406                 return;
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, "Call me back, please");
432 }