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