8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / cbcp.c
blobca5ebab9755bea70adcb4b2b32598abf93ded72f
1 /*
2 * cbcp - Call Back Configuration Protocol.
4 * Copyright (c) 2000 by Sun Microsystems, Inc.
5 * All rights reserved.
7 * Copyright (c) 1995 Pedro Roque Marques
8 * All rights reserved.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by Pedro Roque Marques. The name of the author may not be used to
16 * endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 #pragma ident "%Z%%M% %I% %E% SMI"
25 #define RCSID "$Id: cbcp.c,v 1.10 1999/08/13 06:46:10 paulus Exp $"
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
32 #include "pppd.h"
33 #include "cbcp.h"
34 #include "fsm.h"
35 #include "lcp.h"
37 #if !defined(lint) && !defined(_lint)
38 static const char rcsid[] = RCSID;
39 #endif
42 * Options.
44 static int setcbcp __P((char **, option_t *));
46 static option_t cbcp_option_list[] = {
47 { "callback", o_special, (void *)setcbcp,
48 "Ask for callback" },
49 { NULL }
53 * Protocol entry points.
55 static void cbcp_init __P((int unit));
56 static void cbcp_lowerup __P((int unit));
57 static void cbcp_input __P((int unit, u_char *pkt, int len));
58 static void cbcp_protrej __P((int unit));
59 static int cbcp_printpkt __P((u_char *pkt, int len,
60 void (*printer) __P((void *, const char *, ...)),
61 void *arg));
63 struct protent cbcp_protent = {
64 PPP_CBCP, /* PPP protocol number */
65 cbcp_init, /* Initialization procedure */
66 cbcp_input, /* Process a received packet */
67 cbcp_protrej, /* Process a received protocol-reject */
68 cbcp_lowerup, /* Lower layer has come up */
69 NULL, /* Lower layer has gone down */
70 NULL, /* Open the protocol */
71 NULL, /* Close the protocol */
72 cbcp_printpkt, /* Print a packet in readable form */
73 NULL, /* Process a received data packet */
74 0, /* 0 iff protocol is disabled */
75 "CBCP", /* Text name of protocol */
76 NULL, /* Text name of corresponding data protocol */
77 cbcp_option_list, /* List of command-line options */
78 NULL, /* Check requested options, assign defaults */
79 NULL, /* Configure interface for demand-dial */
80 NULL /* Say whether to bring up link for this pkt */
83 /* Not static'd for plug-ins */
84 cbcp_state cbcp[NUM_PPP];
86 /* internal prototypes */
88 static void cbcp_recvreq __P((cbcp_state *us, u_char *pckt, int len));
89 static void cbcp_recvack __P((cbcp_state *us, u_char *pckt, int len));
90 static void cbcp_send __P((cbcp_state *us, int code, u_char *buf, int len));
92 /* option processing */
93 /*ARGSUSED*/
94 static int
95 setcbcp(argv, opt)
96 char **argv;
97 option_t *opt;
99 lcp_wantoptions[0].neg_cbcp = 1;
100 cbcp_protent.enabled_flag = 1;
101 cbcp[0].us_number = strdup(*argv);
102 if (cbcp[0].us_number == NULL)
103 novm("callback number");
104 cbcp[0].us_type |= (1 << CB_CONF_USER);
105 cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
106 return (1);
109 /* init state */
110 static void
111 cbcp_init(unit)
112 int unit;
114 cbcp_state *us;
116 us = &cbcp[unit];
117 BZERO(us, sizeof(cbcp_state));
118 us->us_unit = unit;
119 us->us_type |= (1 << CB_CONF_NO);
122 /* lower layer is up */
123 static void
124 cbcp_lowerup(unit)
125 int unit;
127 cbcp_state *us = &cbcp[unit];
129 if (debug) {
130 dbglog("cbcp_lowerup: want: %d", us->us_type);
132 if (us->us_type == CB_CONF_USER)
133 dbglog("phone no: %s", us->us_number);
137 /* process an incoming packet */
138 static void
139 cbcp_input(unit, inpacket, pktlen)
140 int unit;
141 u_char *inpacket;
142 int pktlen;
144 u_char *inp;
145 u_char code, id;
146 u_short len;
148 cbcp_state *us = &cbcp[unit];
150 inp = inpacket;
152 if (pktlen < CBCP_MINLEN) {
153 error("CBCP packet is too small (%d < %d)", pktlen, CBCP_MINLEN);
154 return;
157 GETCHAR(code, inp);
158 GETCHAR(id, inp);
159 GETSHORT(len, inp);
161 if (len > pktlen) {
162 error("CBCP packet: invalid length (%d > %d)", len, pktlen);
163 return;
166 len -= CBCP_MINLEN;
168 switch (code) {
169 case CBCP_REQ:
170 us->us_id = id;
171 cbcp_recvreq(us, inp, len);
172 break;
174 case CBCP_RESP:
175 if (debug)
176 dbglog("CBCP Response received; no request sent");
177 break;
179 case CBCP_ACK:
180 if (id != us->us_id) {
181 if (debug)
182 dbglog("CBCP Ack ID %d doesn't match expected %d", id,
183 us->us_id);
184 break;
187 cbcp_recvack(us, inp, len);
188 break;
190 default:
191 if (debug)
192 dbglog("Unknown CBCP code number %d", code);
193 break;
197 /* protocol was rejected by foe */
198 /*ARGSUSED*/
199 static void
200 cbcp_protrej(int unit)
202 start_networks();
205 static char *cbcp_codenames[] = {
206 "Request", "Response", "Ack"
209 static char *cbcp_optionnames[] = {
210 "NoCallback",
211 "UserDefined",
212 "AdminDefined",
213 "List"
217 * Pretty print a packet. Return value is number of bytes parsed out
218 * of the packet and printed in some way. Caller (in util.c) will
219 * print the remainder of the packet.
221 static int
222 cbcp_printpkt(p, plen, printer, arg)
223 u_char *p;
224 int plen;
225 void (*printer) __P((void *, const char *, ...));
226 void *arg;
228 int code, id, len, olen, alen;
229 u_char *pstart, cichar;
231 if (plen < HEADERLEN) {
232 printer(arg, "too short (%d<%d)", plen, HEADERLEN);
233 return (0);
235 pstart = p;
236 GETCHAR(code, p);
237 GETCHAR(id, p);
238 GETSHORT(len, p);
240 if (code >= 1 && code <= Dim(cbcp_codenames))
241 printer(arg, " %s", cbcp_codenames[code-1]);
242 else
243 printer(arg, " code=0x%x", code);
245 printer(arg, " id=0x%x", id);
247 if (len < HEADERLEN) {
248 printer(arg, " header length %d<%d", len, HEADERLEN);
249 return (HEADERLEN);
251 if (len > plen) {
252 printer(arg, " truncated (%d>%d)", len, plen);
253 len = plen;
255 len -= HEADERLEN;
257 switch (code) {
258 case CBCP_REQ:
259 case CBCP_RESP:
260 case CBCP_ACK:
261 while (len >= 2) {
262 GETCHAR(cichar, p);
263 GETCHAR(olen, p);
265 if (olen < 2)
266 break;
268 printer(arg, " <");
270 if (olen > len) {
271 printer(arg, "trunc[%d>%d] ", olen, len);
272 olen = len;
274 len -= olen;
275 olen -= 2;
277 if (cichar >= 1 && cichar <= Dim(cbcp_optionnames))
278 printer(arg, " %s", cbcp_optionnames[cichar-1]);
279 else
280 printer(arg, " option=0x%x", cichar);
282 if (olen > 0) {
283 GETCHAR(cichar, p);
284 olen--;
285 printer(arg, " delay=%d", cichar);
288 while (olen > 0) {
289 GETCHAR(cichar, p);
290 olen--;
291 if (cichar != 1)
292 printer(arg, " (type %d?)", cichar);
293 alen = strllen((const char *)p, olen);
294 if (olen > 0 && alen > 0)
295 printer(arg, " '%.*s'", alen, p);
296 else
297 printer(arg, " null");
298 p += alen + 1;
299 olen -= alen + 1;
301 printer(arg, ">");
304 default:
305 break;
308 if (len > 0) {
309 if (len > 8)
310 printer(arg, "%8B ...", p);
311 else
312 printer(arg, "%.*B", len, p);
314 p += len;
316 return p - pstart;
320 * received CBCP request.
321 * No reason to print packet contents in detail here, since enabling
322 * debug mode will cause the print routine above to be invoked.
324 static void
325 cbcp_recvreq(us, pckt, pcktlen)
326 cbcp_state *us;
327 u_char *pckt;
328 int pcktlen;
330 u_char type, opt_len;
331 int len = pcktlen;
332 u_char cb_type;
333 u_char buf[256];
334 u_char *bufp = buf;
336 us->us_allowed = 0;
337 while (len > 0) {
338 GETCHAR(type, pckt);
339 GETCHAR(opt_len, pckt);
341 if (opt_len > 2) {
342 pckt++; /* ignore the delay time */
345 len -= opt_len;
348 * Careful; don't use left-shift operator on numbers that are
349 * too big.
351 if (type > CB_CONF_LIST) {
352 if (debug)
353 dbglog("CBCP: ignoring unknown type %d", type);
354 continue;
357 us->us_allowed |= (1 << type);
359 switch (type) {
360 case CB_CONF_NO:
361 if (debug)
362 dbglog("CBCP: operation without callback allowed");
363 break;
365 case CB_CONF_USER:
366 if (debug)
367 dbglog("callback to user-specified number allowed");
368 break;
370 case CB_CONF_ADMIN:
371 if (debug)
372 dbglog("CBCP: callback to admin-defined address allowed");
373 break;
375 case CB_CONF_LIST:
376 if (debug)
377 dbglog("CBCP: callback to one out of list allowed");
378 break;
382 /* Now generate the response */
383 len = 0;
384 cb_type = us->us_allowed & us->us_type;
386 if (cb_type & ( 1 << CB_CONF_USER ) ) {
387 if (debug)
388 dbglog("CBCP Response: selecting user-specified number");
389 PUTCHAR(CB_CONF_USER, bufp);
390 len = 3 + 1 + strlen(us->us_number) + 1;
391 PUTCHAR(len , bufp);
392 PUTCHAR(5, bufp); /* delay */
393 PUTCHAR(1, bufp);
394 BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
395 cbcp_send(us, CBCP_RESP, buf, len);
396 return;
399 if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
400 if (debug)
401 dbglog("CBCP Response: selecting admin-specified number");
402 PUTCHAR(CB_CONF_ADMIN, bufp);
403 len = 3;
404 PUTCHAR(len, bufp);
405 PUTCHAR(5, bufp); /* delay */
406 cbcp_send(us, CBCP_RESP, buf, len);
407 return;
410 if (cb_type & ( 1 << CB_CONF_NO ) ) {
411 if (debug)
412 dbglog("CBCP Response: selecting no-callback mode");
413 PUTCHAR(CB_CONF_NO, bufp);
414 len = 3;
415 PUTCHAR(len , bufp);
416 PUTCHAR(0, bufp);
417 cbcp_send(us, CBCP_RESP, buf, len);
418 start_networks();
419 return;
422 if (debug)
423 dbglog("CBCP: no callback types in common");
424 lcp_close(us->us_unit, "No CBCP callback options available");
427 static void
428 cbcp_send(us, code, buf, len)
429 cbcp_state *us;
430 int code;
431 u_char *buf;
432 int len;
434 u_char *outp;
435 int outlen;
437 outp = outpacket_buf;
439 outlen = 4 + len;
441 MAKEHEADER(outp, PPP_CBCP);
443 PUTCHAR(code, outp);
444 PUTCHAR(us->us_id, outp);
445 PUTSHORT(outlen, outp);
447 if (len > 0)
448 BCOPY(buf, outp, len);
450 output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
454 * Received CBCP Acknowledgment message.
456 static void
457 cbcp_recvack(us, pckt, len)
458 cbcp_state *us;
459 u_char *pckt;
460 int len;
462 u_char type, addr_type;
463 int opt_len;
465 if (len > 0) {
466 GETCHAR(type, pckt);
467 GETCHAR(opt_len, pckt);
469 if (type == CB_CONF_NO) {
470 if (debug)
471 dbglog("CBCP: proceeding without callback");
472 return;
475 /* just ignore the delay time */
476 pckt++;
478 if (opt_len > 4) {
479 GETCHAR(addr_type, pckt);
480 if (addr_type != 1)
481 warn("CBCP: unknown callback address type %d", addr_type);
483 if (debug && opt_len > 5)
484 dbglog("CBCP: peer will call %.*s", pckt, opt_len - 4);
487 persist = 0;
488 lcp_close(us->us_unit, "Call me back, please");
489 status = EXIT_CALLBACK;