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