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