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