cbcp.c revision 1.2
1/*	$NetBSD: cbcp.c,v 1.2 2013/11/28 22:33:42 christos 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 names 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 * 4. Redistributions of any form whatsoever must retain the following
25 *    acknowledgment:
26 *    "This product includes software developed by Pedro Roque Marques
27 *     <pedro_m@yahoo.com>"
28 *
29 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
30 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
31 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
32 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
33 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
34 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
35 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
36 */
37
38#include <sys/cdefs.h>
39#if 0
40#define RCSID	"Id: cbcp.c,v 1.17 2006/05/22 00:04:07 paulus Exp "
41static const char rcsid[] = RCSID;
42#else
43__RCSID("$NetBSD: cbcp.c,v 1.2 2013/11/28 22:33:42 christos Exp $");
44#endif
45
46#include <stdio.h>
47#include <string.h>
48#include <sys/types.h>
49#include <sys/time.h>
50
51#include "pppd.h"
52#include "cbcp.h"
53#include "fsm.h"
54#include "lcp.h"
55
56/*
57 * Options.
58 */
59static int setcbcp __P((char **));
60
61static option_t cbcp_option_list[] = {
62    { "callback", o_special, (void *)setcbcp,
63      "Ask for callback", OPT_PRIO | OPT_A2STRVAL, &cbcp[0].us_number },
64    { NULL }
65};
66
67/*
68 * Protocol entry points.
69 */
70static void cbcp_init      __P((int unit));
71static void cbcp_open      __P((int unit));
72static void cbcp_lowerup   __P((int unit));
73static void cbcp_input     __P((int unit, u_char *pkt, int len));
74static void cbcp_protrej   __P((int unit));
75static int  cbcp_printpkt  __P((u_char *pkt, int len,
76				void (*printer) __P((void *, char *, ...)),
77				void *arg));
78
79struct protent cbcp_protent = {
80    PPP_CBCP,
81    cbcp_init,
82    cbcp_input,
83    cbcp_protrej,
84    cbcp_lowerup,
85    NULL,
86    cbcp_open,
87    NULL,
88    cbcp_printpkt,
89    NULL,
90    0,
91    "CBCP",
92    NULL,
93    cbcp_option_list,
94    NULL,
95    NULL,
96    NULL
97};
98
99cbcp_state cbcp[NUM_PPP];
100
101/* internal prototypes */
102
103static void cbcp_recvreq __P((cbcp_state *us, u_char *pckt, int len));
104static void cbcp_resp __P((cbcp_state *us));
105static void cbcp_up __P((cbcp_state *us));
106static void cbcp_recvack __P((cbcp_state *us, u_char *pckt, int len));
107static void cbcp_send __P((cbcp_state *us, int code, u_char *buf, int len));
108
109/* option processing */
110static int
111setcbcp(argv)
112    char **argv;
113{
114    lcp_wantoptions[0].neg_cbcp = 1;
115    cbcp_protent.enabled_flag = 1;
116    cbcp[0].us_number = strdup(*argv);
117    if (cbcp[0].us_number == 0)
118	novm("callback number");
119    cbcp[0].us_type |= (1 << CB_CONF_USER);
120    cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
121    return (1);
122}
123
124/* init state */
125static void
126cbcp_init(iface)
127    int iface;
128{
129    cbcp_state *us;
130
131    us = &cbcp[iface];
132    memset(us, 0, sizeof(cbcp_state));
133    us->us_unit = iface;
134    us->us_type |= (1 << CB_CONF_NO);
135}
136
137/* lower layer is up */
138static void
139cbcp_lowerup(iface)
140    int iface;
141{
142    cbcp_state *us = &cbcp[iface];
143
144    dbglog("cbcp_lowerup");
145    dbglog("want: %d", us->us_type);
146
147    if (us->us_type == CB_CONF_USER)
148        dbglog("phone no: %s", us->us_number);
149}
150
151static void
152cbcp_open(unit)
153    int unit;
154{
155    dbglog("cbcp_open");
156}
157
158/* process an incomming packet */
159static void
160cbcp_input(unit, inpacket, pktlen)
161    int unit;
162    u_char *inpacket;
163    int pktlen;
164{
165    u_char *inp;
166    u_char code, id;
167    u_short len;
168
169    cbcp_state *us = &cbcp[unit];
170
171    inp = inpacket;
172
173    if (pktlen < CBCP_MINLEN) {
174	if (debug)
175	    dbglog("CBCP: Packet too short (%d)", pktlen);
176	return;
177    }
178
179    GETCHAR(code, inp);
180    GETCHAR(id, inp);
181    GETSHORT(len, inp);
182
183    if (len > pktlen || len < CBCP_MINLEN) {
184	if (debug)
185	    dbglog("CBCP: Invalid packet length (%d/%d)", len, pktlen);
186        return;
187    }
188
189    len -= CBCP_MINLEN;
190
191    switch(code) {
192    case CBCP_REQ:
193        us->us_id = id;
194	cbcp_recvreq(us, inp, len);
195	break;
196
197    case CBCP_RESP:
198	if (debug)
199	    dbglog("CBCP_RESP received");
200	break;
201
202    case CBCP_ACK:
203	if (debug && id != us->us_id)
204	    dbglog("id doesn't match: expected %d recv %d",
205		   us->us_id, id);
206
207	cbcp_recvack(us, inp, len);
208	break;
209
210    default:
211	break;
212    }
213}
214
215/* protocol was rejected by foe */
216void cbcp_protrej(int iface)
217{
218}
219
220char *cbcp_codenames[] = {
221    "Request", "Response", "Ack"
222};
223
224char *cbcp_optionnames[] = {
225    "NoCallback",
226    "UserDefined",
227    "AdminDefined",
228    "List"
229};
230
231/* pretty print a packet */
232static int
233cbcp_printpkt(p, plen, printer, arg)
234    u_char *p;
235    int plen;
236    void (*printer) __P((void *, char *, ...));
237    void *arg;
238{
239    int code, opt, id, len, olen, delay;
240    u_char *pstart;
241
242    if (plen < HEADERLEN)
243	return 0;
244    pstart = p;
245    GETCHAR(code, p);
246    GETCHAR(id, p);
247    GETSHORT(len, p);
248    if (len < HEADERLEN || len > plen)
249	return 0;
250
251    if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
252	printer(arg, " %s", cbcp_codenames[code-1]);
253    else
254	printer(arg, " code=0x%x", code);
255
256    printer(arg, " id=0x%x", id);
257    len -= HEADERLEN;
258
259    switch (code) {
260    case CBCP_REQ:
261    case CBCP_RESP:
262    case CBCP_ACK:
263        while(len >= 2) {
264	    GETCHAR(opt, p);
265	    GETCHAR(olen, p);
266
267	    if (olen < 2 || olen > len) {
268	        break;
269	    }
270
271	    printer(arg, " <");
272	    len -= olen;
273
274	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
275	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
276	    else
277	        printer(arg, " option=0x%x", opt);
278
279	    if (olen > 2) {
280	        GETCHAR(delay, p);
281		printer(arg, " delay = %d", delay);
282	    }
283
284	    if (olen > 3) {
285	        int addrt;
286		char str[256];
287
288		GETCHAR(addrt, p);
289		__USE(addrt);
290		memcpy(str, p, olen - 4);
291		str[olen - 4] = 0;
292		printer(arg, " number = %s", str);
293	    }
294	    printer(arg, ">");
295	}
296	break;
297
298    default:
299	break;
300    }
301
302    for (; len > 0; --len) {
303	GETCHAR(code, p);
304	printer(arg, " %.2x", code);
305    }
306
307    return p - pstart;
308}
309
310/* received CBCP request */
311static void
312cbcp_recvreq(us, pckt, pcktlen)
313    cbcp_state *us;
314    u_char *pckt;
315    int pcktlen;
316{
317    u_char type, opt_len, delay, addr_type;
318    char address[256];
319    int len = pcktlen;
320
321    address[0] = 0;
322
323    while (len >= 2) {
324        dbglog("length: %d", len);
325
326	GETCHAR(type, pckt);
327	GETCHAR(opt_len, pckt);
328	if (opt_len < 2 || opt_len > len) {
329	    if (debug)
330		dbglog("CBCP: Malformed option length (%d/%d)", opt_len, len);
331	    break;
332	}
333
334	if (opt_len > 2) {
335	    GETCHAR(delay, pckt);
336	    __USE(delay);
337	}
338
339	us->us_allowed |= (1 << type);
340
341	switch(type) {
342	case CB_CONF_NO:
343	    dbglog("no callback allowed");
344	    break;
345
346	case CB_CONF_USER:
347	    dbglog("user callback allowed");
348	    if (opt_len > 4) {
349	        GETCHAR(addr_type, pckt);
350		__USE(addr_type);
351		memcpy(address, pckt, opt_len - 4);
352		address[opt_len - 4] = 0;
353		if (address[0])
354		    dbglog("address: %s", address);
355	    }
356	    break;
357
358	case CB_CONF_ADMIN:
359	    dbglog("user admin defined allowed");
360	    break;
361
362	case CB_CONF_LIST:
363	    break;
364	}
365	len -= opt_len;
366    }
367    if (len != 0) {
368	if (debug)
369	    dbglog("cbcp_recvreq: malformed packet (%d bytes left)", len);
370	return;
371    }
372
373    cbcp_resp(us);
374}
375
376static void
377cbcp_resp(us)
378    cbcp_state *us;
379{
380    u_char cb_type;
381    u_char buf[256];
382    u_char *bufp = buf;
383    int len = 0;
384    int slen;
385
386    cb_type = us->us_allowed & us->us_type;
387    dbglog("cbcp_resp cb_type=%d", cb_type);
388
389#if 0
390    if (!cb_type)
391        lcp_down(us->us_unit);
392#endif
393
394    if (cb_type & ( 1 << CB_CONF_USER ) ) {
395	dbglog("cbcp_resp CONF_USER");
396	slen = strlen(us->us_number);
397	if (slen > 250) {
398	    warn("callback number truncated to 250 characters");
399	    slen = 250;
400	}
401	PUTCHAR(CB_CONF_USER, bufp);
402	len = 3 + 1 + slen + 1;
403	PUTCHAR(len , bufp);
404	PUTCHAR(5, bufp); /* delay */
405	PUTCHAR(1, bufp);
406	BCOPY(us->us_number, bufp, slen + 1);
407	cbcp_send(us, CBCP_RESP, buf, len);
408	return;
409    }
410
411    if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
412	dbglog("cbcp_resp CONF_ADMIN");
413        PUTCHAR(CB_CONF_ADMIN, bufp);
414	len = 3;
415	PUTCHAR(len, bufp);
416	PUTCHAR(5, bufp); /* delay */
417	cbcp_send(us, CBCP_RESP, buf, len);
418	return;
419    }
420
421    if (cb_type & ( 1 << CB_CONF_NO ) ) {
422        dbglog("cbcp_resp CONF_NO");
423	PUTCHAR(CB_CONF_NO, bufp);
424	len = 2;
425	PUTCHAR(len , bufp);
426	cbcp_send(us, CBCP_RESP, buf, len);
427	start_networks(us->us_unit);
428	return;
429    }
430}
431
432static void
433cbcp_send(us, code, buf, len)
434    cbcp_state *us;
435    int code;
436    u_char *buf;
437    int len;
438{
439    u_char *outp;
440    int outlen;
441
442    outp = outpacket_buf;
443
444    outlen = 4 + len;
445
446    MAKEHEADER(outp, PPP_CBCP);
447
448    PUTCHAR(code, outp);
449    PUTCHAR(us->us_id, outp);
450    PUTSHORT(outlen, outp);
451
452    if (len)
453        BCOPY(buf, outp, len);
454
455    output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
456}
457
458static void
459cbcp_recvack(us, pckt, len)
460    cbcp_state *us;
461    u_char *pckt;
462    int len;
463{
464    u_char type, delay, addr_type;
465    int opt_len;
466    char address[256];
467
468    if (len >= 2) {
469        GETCHAR(type, pckt);
470	GETCHAR(opt_len, pckt);
471	if (opt_len >= 2 && opt_len <= len) {
472
473	    if (opt_len > 2) {
474		GETCHAR(delay, pckt);
475		__USE(delay);
476	    }
477
478	    if (opt_len > 4) {
479		GETCHAR(addr_type, pckt);
480		__USE(addr_type);
481		memcpy(address, pckt, opt_len - 4);
482		address[opt_len - 4] = 0;
483		if (address[0])
484		    dbglog("peer will call: %s", address);
485	    }
486	    if (type == CB_CONF_NO)
487		return;
488
489	    cbcp_up(us);
490
491	} else if (debug)
492	    dbglog("cbcp_recvack: malformed packet");
493    }
494}
495
496/* ok peer will do callback */
497static void
498cbcp_up(us)
499    cbcp_state *us;
500{
501    persist = 0;
502    status = EXIT_CALLBACK;
503    lcp_close(0, "Call me back, please");
504}
505