xref: /openbsd-src/usr.sbin/pppd/cbcp.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: cbcp.c,v 1.2 1997/09/05 04:32:33 millert Exp $	*/
2 
3 /*
4  * cbcp - Call Back Configuration Protocol.
5  *
6  * Copyright (c) 1995 Pedro Roque Marques
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by Pedro Roque Marques.  The name of the author may not be used to
15  * endorse or promote products derived from this software without
16  * specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22 
23 #ifndef lint
24 #if 0
25 static char rcsid[] = "Id: cbcp.c,v 1.2 1997/04/30 05:50:26 paulus Exp";
26 #else
27 static char rcsid[] = "$OpenBSD: cbcp.c,v 1.2 1997/09/05 04:32:33 millert Exp $";
28 #endif
29 #endif
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <syslog.h>
36 
37 #include "pppd.h"
38 #include "cbcp.h"
39 #include "fsm.h"
40 #include "lcp.h"
41 #include "ipcp.h"
42 
43 /*
44  * Protocol entry points.
45  */
46 static void cbcp_init      __P((int unit));
47 static void cbcp_open      __P((int unit));
48 static void cbcp_lowerup   __P((int unit));
49 static void cbcp_input     __P((int unit, u_char *pkt, int len));
50 static void cbcp_protrej   __P((int unit));
51 static int  cbcp_printpkt  __P((u_char *pkt, int len,
52 				void (*printer) __P((void *, char *, ...)),
53 				void *arg));
54 
55 struct protent cbcp_protent = {
56     PPP_CBCP,
57     cbcp_init,
58     cbcp_input,
59     cbcp_protrej,
60     cbcp_lowerup,
61     NULL,
62     cbcp_open,
63     NULL,
64     cbcp_printpkt,
65     NULL,
66     0,
67     "CBCP",
68     NULL,
69     NULL,
70     NULL
71 };
72 
73 cbcp_state cbcp[NUM_PPP];
74 
75 /* internal prototypes */
76 
77 static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
78 static void cbcp_resp __P((cbcp_state *us));
79 static void cbcp_up __P((cbcp_state *us));
80 static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
81 static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
82 
83 /* init state */
84 static void
85 cbcp_init(iface)
86     int iface;
87 {
88     cbcp_state *us;
89 
90     us = &cbcp[iface];
91     memset(us, 0, sizeof(cbcp_state));
92     us->us_unit = iface;
93     us->us_type |= (1 << CB_CONF_NO);
94 }
95 
96 /* lower layer is up */
97 static void
98 cbcp_lowerup(iface)
99     int iface;
100 {
101     cbcp_state *us = &cbcp[iface];
102 
103     syslog(LOG_DEBUG, "cbcp_lowerup");
104     syslog(LOG_DEBUG, "want: %d", us->us_type);
105 
106     if (us->us_type == CB_CONF_USER)
107         syslog(LOG_DEBUG, "phone no: %s", us->us_number);
108 }
109 
110 static void
111 cbcp_open(unit)
112     int unit;
113 {
114     syslog(LOG_DEBUG, "cbcp_open");
115 }
116 
117 /* process an incomming packet */
118 static void
119 cbcp_input(unit, inpacket, pktlen)
120     int unit;
121     u_char *inpacket;
122     int pktlen;
123 {
124     u_char *inp;
125     u_char code, id;
126     u_short len;
127 
128     cbcp_state *us = &cbcp[unit];
129 
130     inp = inpacket;
131 
132     if (pktlen < CBCP_MINLEN) {
133         syslog(LOG_ERR, "CBCP packet is too small");
134 	return;
135     }
136 
137     GETCHAR(code, inp);
138     GETCHAR(id, inp);
139     GETSHORT(len, inp);
140 
141 #if 0
142     if (len > pktlen) {
143         syslog(LOG_ERR, "CBCP packet: invalid length");
144         return;
145     }
146 #endif
147 
148     len -= CBCP_MINLEN;
149 
150     switch(code) {
151     case CBCP_REQ:
152         us->us_id = id;
153 	cbcp_recvreq(us, inp, len);
154 	break;
155 
156     case CBCP_RESP:
157 	syslog(LOG_DEBUG, "CBCP_RESP received");
158 	break;
159 
160     case CBCP_ACK:
161 	if (id != us->us_id)
162 	    syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
163 		   us->us_id, id);
164 
165 	cbcp_recvack(us, inp, len);
166 	break;
167 
168     default:
169 	break;
170     }
171 }
172 
173 /* protocol was rejected by foe */
174 void cbcp_protrej(int iface)
175 {
176 }
177 
178 char *cbcp_codenames[] = {
179     "Request", "Response", "Ack"
180 };
181 
182 char *cbcp_optionnames[] = {
183     "NoCallback",
184     "UserDefined",
185     "AdminDefined",
186     "List"
187 };
188 
189 /* pretty print a packet */
190 static int
191 cbcp_printpkt(p, plen, printer, arg)
192     u_char *p;
193     int plen;
194     void (*printer) __P((void *, char *, ...));
195     void *arg;
196 {
197     int code, opt, id, len, olen, delay;
198     u_char *pstart;
199 
200     if (plen < HEADERLEN)
201 	return 0;
202     pstart = p;
203     GETCHAR(code, p);
204     GETCHAR(id, p);
205     GETSHORT(len, p);
206     if (len < HEADERLEN || len > plen)
207 	return 0;
208 
209     if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
210 	printer(arg, " %s", cbcp_codenames[code-1]);
211     else
212 	printer(arg, " code=0x%x", code);
213 
214     printer(arg, " id=0x%x", id);
215     len -= HEADERLEN;
216 
217     switch (code) {
218     case CBCP_REQ:
219     case CBCP_RESP:
220     case CBCP_ACK:
221         while(len >= 2) {
222 	    GETCHAR(opt, p);
223 	    GETCHAR(olen, p);
224 
225 	    if (olen < 2 || olen > len) {
226 	        break;
227 	    }
228 
229 	    printer(arg, " <");
230 	    len -= olen;
231 
232 	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
233 	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
234 	    else
235 	        printer(arg, " option=0x%x", opt);
236 
237 	    if (olen > 2) {
238 	        GETCHAR(delay, p);
239 		printer(arg, " delay = %d", delay);
240 	    }
241 
242 	    if (olen > 3) {
243 	        int addrt;
244 		char str[256];
245 
246 		GETCHAR(addrt, p);
247 		memcpy(str, p, olen - 4);
248 		str[olen - 4] = 0;
249 		printer(arg, " number = %s", str);
250 	    }
251 	    printer(arg, ">");
252 	    break;
253 	}
254 
255     default:
256 	break;
257     }
258 
259     for (; len > 0; --len) {
260 	GETCHAR(code, p);
261 	printer(arg, " %.2x", code);
262     }
263 
264     return p - pstart;
265 }
266 
267 /* received CBCP request */
268 static void
269 cbcp_recvreq(us, pckt, pcktlen)
270     cbcp_state *us;
271     char *pckt;
272     int pcktlen;
273 {
274     u_char type, opt_len, delay, addr_type;
275     char address[256];
276     int len = pcktlen;
277 
278     address[0] = 0;
279 
280     while (len) {
281         syslog(LOG_DEBUG, "length: %d", len);
282 
283 	GETCHAR(type, pckt);
284 	GETCHAR(opt_len, pckt);
285 
286 	if (opt_len > 2)
287 	    GETCHAR(delay, pckt);
288 
289 	us->us_allowed |= (1 << type);
290 
291 	switch(type) {
292 	case CB_CONF_NO:
293 	    syslog(LOG_DEBUG, "no callback allowed");
294 	    break;
295 
296 	case CB_CONF_USER:
297 	    syslog(LOG_DEBUG, "user callback allowed");
298 	    if (opt_len > 4) {
299 	        GETCHAR(addr_type, pckt);
300 		memcpy(address, pckt, opt_len - 4);
301 		address[opt_len - 4] = 0;
302 		if (address[0])
303 		    syslog(LOG_DEBUG, "address: %s", address);
304 	    }
305 	    break;
306 
307 	case CB_CONF_ADMIN:
308 	    syslog(LOG_DEBUG, "user admin defined allowed");
309 	    break;
310 
311 	case CB_CONF_LIST:
312 	    break;
313 	}
314 	len -= opt_len;
315     }
316 
317     cbcp_resp(us);
318 }
319 
320 static void
321 cbcp_resp(us)
322     cbcp_state *us;
323 {
324     u_char cb_type;
325     u_char buf[256];
326     u_char *bufp = buf;
327     int len = 0;
328 
329     cb_type = us->us_allowed & us->us_type;
330     syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
331 
332 #if 0
333     if (!cb_type)
334         lcp_down(us->us_unit);
335 #endif
336 
337     if (cb_type & ( 1 << CB_CONF_USER ) ) {
338 	syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
339 	PUTCHAR(CB_CONF_USER, bufp);
340 	len = 3 + 1 + strlen(us->us_number) + 1;
341 	PUTCHAR(len , bufp);
342 	PUTCHAR(5, bufp); /* delay */
343 	PUTCHAR(1, bufp);
344 	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
345 	cbcp_send(us, CBCP_RESP, buf, len);
346 	return;
347     }
348 
349     if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
350 	syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
351         PUTCHAR(CB_CONF_ADMIN, bufp);
352 	len = 3 + 1;
353 	PUTCHAR(len , bufp);
354 	PUTCHAR(5, bufp); /* delay */
355 	PUTCHAR(0, bufp);
356 	cbcp_send(us, CBCP_RESP, buf, len);
357 	return;
358     }
359 
360     if (cb_type & ( 1 << CB_CONF_NO ) ) {
361         syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
362 	PUTCHAR(CB_CONF_NO, bufp);
363 	len = 3;
364 	PUTCHAR(len , bufp);
365 	PUTCHAR(0, bufp);
366 	cbcp_send(us, CBCP_RESP, buf, len);
367 	(*ipcp_protent.open)(us->us_unit);
368 	return;
369     }
370 }
371 
372 static void
373 cbcp_send(us, code, buf, len)
374     cbcp_state *us;
375     u_char code;
376     u_char *buf;
377     int len;
378 {
379     u_char *outp;
380     int outlen;
381 
382     outp = outpacket_buf;
383 
384     outlen = 4 + len;
385 
386     MAKEHEADER(outp, PPP_CBCP);
387 
388     PUTCHAR(code, outp);
389     PUTCHAR(us->us_id, outp);
390     PUTSHORT(outlen, outp);
391 
392     if (len)
393         BCOPY(buf, outp, len);
394 
395     output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
396 }
397 
398 static void
399 cbcp_recvack(us, pckt, len)
400     cbcp_state *us;
401     char *pckt;
402     int len;
403 {
404     u_char type, delay, addr_type;
405     int opt_len;
406     char address[256];
407 
408     if (len) {
409         GETCHAR(type, pckt);
410 	GETCHAR(opt_len, pckt);
411 
412 	if (opt_len > 2)
413 	    GETCHAR(delay, pckt);
414 
415 	if (opt_len > 4) {
416 	    GETCHAR(addr_type, pckt);
417 	    memcpy(address, pckt, opt_len - 4);
418 	    address[opt_len - 4] = 0;
419 	    if (address[0])
420 	        syslog(LOG_DEBUG, "peer will call: %s", address);
421 	}
422     }
423 
424     cbcp_up(us);
425 }
426 
427 extern int persist;
428 
429 /* ok peer will do callback */
430 static void
431 cbcp_up(us)
432     cbcp_state *us;
433 {
434     persist = 0;
435     lcp_close(0, "Call me back, please");
436 }
437