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