cbcp.c revision 1.2.4.2 1 /* $NetBSD: cbcp.c,v 1.2.4.2 2014/05/22 15:51:08 yamt 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 (at) 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 "
41 static const char rcsid[] = RCSID;
42 #else
43 __RCSID("$NetBSD: cbcp.c,v 1.2.4.2 2014/05/22 15:51:08 yamt 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 */
59 static int setcbcp __P((char **));
60
61 static 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 */
70 static void cbcp_init __P((int unit));
71 static void cbcp_open __P((int unit));
72 static void cbcp_lowerup __P((int unit));
73 static void cbcp_input __P((int unit, u_char *pkt, int len));
74 static void cbcp_protrej __P((int unit));
75 static int cbcp_printpkt __P((u_char *pkt, int len,
76 void (*printer) __P((void *, char *, ...)),
77 void *arg));
78
79 struct 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
99 cbcp_state cbcp[NUM_PPP];
100
101 /* internal prototypes */
102
103 static void cbcp_recvreq __P((cbcp_state *us, u_char *pckt, int len));
104 static void cbcp_resp __P((cbcp_state *us));
105 static void cbcp_up __P((cbcp_state *us));
106 static void cbcp_recvack __P((cbcp_state *us, u_char *pckt, int len));
107 static void cbcp_send __P((cbcp_state *us, int code, u_char *buf, int len));
108
109 /* option processing */
110 static int
111 setcbcp(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 */
125 static void
126 cbcp_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 */
138 static void
139 cbcp_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
151 static void
152 cbcp_open(unit)
153 int unit;
154 {
155 dbglog("cbcp_open");
156 }
157
158 /* process an incomming packet */
159 static void
160 cbcp_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 */
216 void cbcp_protrej(int iface)
217 {
218 }
219
220 char *cbcp_codenames[] = {
221 "Request", "Response", "Ack"
222 };
223
224 char *cbcp_optionnames[] = {
225 "NoCallback",
226 "UserDefined",
227 "AdminDefined",
228 "List"
229 };
230
231 /* pretty print a packet */
232 static int
233 cbcp_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 */
311 static void
312 cbcp_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
376 static void
377 cbcp_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
432 static void
433 cbcp_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
458 static void
459 cbcp_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 */
497 static void
498 cbcp_up(us)
499 cbcp_state *us;
500 {
501 persist = 0;
502 status = EXIT_CALLBACK;
503 lcp_close(0, "Call me back, please");
504 }
505