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