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