Deleted Added
full compact
cbcp.c (50479) cbcp.c (50867)
1/*-
2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/ppp/cbcp.c 50479 1999-08-28 01:35:59Z peter $
26 * $FreeBSD: head/usr.sbin/ppp/cbcp.c 50867 1999-09-04 00:00:21Z brian $
27 */
28
29#include <sys/param.h>
30
31#include <sys/un.h>
32
33#include <string.h>
34#include <termios.h>
35
36#include "layer.h"
37#include "defs.h"
38#include "log.h"
39#include "timer.h"
40#include "descriptor.h"
41#include "lqr.h"
42#include "mbuf.h"
43#include "fsm.h"
44#include "lcp.h"
45#include "throughput.h"
46#include "hdlc.h"
47#include "ccp.h"
48#include "link.h"
49#include "async.h"
50#include "physical.h"
51#include "proto.h"
52#include "cbcp.h"
53#include "mp.h"
54#include "chat.h"
55#include "auth.h"
56#include "chap.h"
57#include "datalink.h"
58
59void
60cbcp_Init(struct cbcp *cbcp, struct physical *p)
61{
62 cbcp->required = 0;
63 cbcp->fsm.state = CBCP_CLOSED;
64 cbcp->fsm.id = 0;
65 cbcp->fsm.delay = 0;
66 *cbcp->fsm.phone = '\0';
67 memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer);
68 cbcp->p = p;
69}
70
71static void cbcp_SendReq(struct cbcp *);
72static void cbcp_SendResponse(struct cbcp *);
73static void cbcp_SendAck(struct cbcp *);
74
75static void
76cbcp_Timeout(void *v)
77{
78 struct cbcp *cbcp = (struct cbcp *)v;
79
80 timer_Stop(&cbcp->fsm.timer);
81 if (cbcp->fsm.restart) {
82 switch (cbcp->fsm.state) {
83 case CBCP_CLOSED:
84 case CBCP_STOPPED:
85 log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
86 cbcp->p->dl->name);
87 break;
88
89 case CBCP_REQSENT:
90 cbcp_SendReq(cbcp);
91 break;
92 case CBCP_RESPSENT:
93 cbcp_SendResponse(cbcp);
94 break;
95 case CBCP_ACKSENT:
96 cbcp_SendAck(cbcp);
97 break;
98 }
99 } else {
100 const char *missed;
101
102 switch (cbcp->fsm.state) {
103 case CBCP_STOPPED:
104 missed = "REQ";
105 break;
106 case CBCP_REQSENT:
107 missed = "RESPONSE";
108 break;
109 case CBCP_RESPSENT:
110 missed = "ACK";
111 break;
112 case CBCP_ACKSENT:
113 missed = "Terminate REQ";
114 break;
115 default:
116 log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
117 cbcp->p->dl->name);
118 missed = NULL;
119 break;
120 }
121 if (missed)
122 log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n",
123 cbcp->p->dl->name, missed);
124 datalink_CBCPFailed(cbcp->p->dl);
125 }
126}
127
128static void
129cbcp_StartTimer(struct cbcp *cbcp, int timeout)
130{
131 timer_Stop(&cbcp->fsm.timer);
132 cbcp->fsm.timer.func = cbcp_Timeout;
133 cbcp->fsm.timer.name = "cbcp";
134 cbcp->fsm.timer.load = timeout * SECTICKS;
135 cbcp->fsm.timer.arg = cbcp;
136 timer_Start(&cbcp->fsm.timer);
137}
138
139#define CBCP_CLOSED (0) /* Not in use */
140#define CBCP_STOPPED (1) /* Waiting for a REQ */
141#define CBCP_REQSENT (2) /* Waiting for a RESP */
142#define CBCP_RESPSENT (3) /* Waiting for an ACK */
143#define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */
144
145static const char *cbcpname[] = {
146 "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
147};
148
149static const char *
150cbcpstate(int s)
151{
152 if (s < sizeof cbcpname / sizeof cbcpname[0])
153 return cbcpname[s];
154 return "???";
155}
156
157static void
158cbcp_NewPhase(struct cbcp *cbcp, int new)
159{
160 if (cbcp->fsm.state != new) {
161 log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name,
162 cbcpstate(cbcp->fsm.state), cbcpstate(new));
163 cbcp->fsm.state = new;
164 }
165}
166
167struct cbcp_header {
168 u_char code;
169 u_char id;
170 u_int16_t length; /* Network byte order */
171};
172
173
174/* cbcp_header::code values */
175#define CBCP_REQ (1)
176#define CBCP_RESPONSE (2)
177#define CBCP_ACK (3)
178
179struct cbcp_data {
180 u_char type;
181 u_char length;
182 u_char delay;
183 char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */
184};
185
186/* cbcp_data::type values */
187#define CBCP_NONUM (1)
188#define CBCP_CLIENTNUM (2)
189#define CBCP_SERVERNUM (3)
190#define CBCP_LISTNUM (4)
191
192static void
193cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
194{
195 struct cbcp_header *head;
196 struct mbuf *bp;
197
198 bp = mbuf_Alloc(sizeof *head + data->length, MB_CBCPOUT);
199 head = (struct cbcp_header *)MBUF_CTOP(bp);
200 head->code = code;
201 head->id = cbcp->fsm.id;
202 head->length = htons(sizeof *head + data->length);
203 memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length);
204 log_DumpBp(LogDEBUG, "cbcp_Output", bp);
205 link_PushPacket(&cbcp->p->link, bp, cbcp->p->dl->bundle,
27 */
28
29#include <sys/param.h>
30
31#include <sys/un.h>
32
33#include <string.h>
34#include <termios.h>
35
36#include "layer.h"
37#include "defs.h"
38#include "log.h"
39#include "timer.h"
40#include "descriptor.h"
41#include "lqr.h"
42#include "mbuf.h"
43#include "fsm.h"
44#include "lcp.h"
45#include "throughput.h"
46#include "hdlc.h"
47#include "ccp.h"
48#include "link.h"
49#include "async.h"
50#include "physical.h"
51#include "proto.h"
52#include "cbcp.h"
53#include "mp.h"
54#include "chat.h"
55#include "auth.h"
56#include "chap.h"
57#include "datalink.h"
58
59void
60cbcp_Init(struct cbcp *cbcp, struct physical *p)
61{
62 cbcp->required = 0;
63 cbcp->fsm.state = CBCP_CLOSED;
64 cbcp->fsm.id = 0;
65 cbcp->fsm.delay = 0;
66 *cbcp->fsm.phone = '\0';
67 memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer);
68 cbcp->p = p;
69}
70
71static void cbcp_SendReq(struct cbcp *);
72static void cbcp_SendResponse(struct cbcp *);
73static void cbcp_SendAck(struct cbcp *);
74
75static void
76cbcp_Timeout(void *v)
77{
78 struct cbcp *cbcp = (struct cbcp *)v;
79
80 timer_Stop(&cbcp->fsm.timer);
81 if (cbcp->fsm.restart) {
82 switch (cbcp->fsm.state) {
83 case CBCP_CLOSED:
84 case CBCP_STOPPED:
85 log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
86 cbcp->p->dl->name);
87 break;
88
89 case CBCP_REQSENT:
90 cbcp_SendReq(cbcp);
91 break;
92 case CBCP_RESPSENT:
93 cbcp_SendResponse(cbcp);
94 break;
95 case CBCP_ACKSENT:
96 cbcp_SendAck(cbcp);
97 break;
98 }
99 } else {
100 const char *missed;
101
102 switch (cbcp->fsm.state) {
103 case CBCP_STOPPED:
104 missed = "REQ";
105 break;
106 case CBCP_REQSENT:
107 missed = "RESPONSE";
108 break;
109 case CBCP_RESPSENT:
110 missed = "ACK";
111 break;
112 case CBCP_ACKSENT:
113 missed = "Terminate REQ";
114 break;
115 default:
116 log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
117 cbcp->p->dl->name);
118 missed = NULL;
119 break;
120 }
121 if (missed)
122 log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n",
123 cbcp->p->dl->name, missed);
124 datalink_CBCPFailed(cbcp->p->dl);
125 }
126}
127
128static void
129cbcp_StartTimer(struct cbcp *cbcp, int timeout)
130{
131 timer_Stop(&cbcp->fsm.timer);
132 cbcp->fsm.timer.func = cbcp_Timeout;
133 cbcp->fsm.timer.name = "cbcp";
134 cbcp->fsm.timer.load = timeout * SECTICKS;
135 cbcp->fsm.timer.arg = cbcp;
136 timer_Start(&cbcp->fsm.timer);
137}
138
139#define CBCP_CLOSED (0) /* Not in use */
140#define CBCP_STOPPED (1) /* Waiting for a REQ */
141#define CBCP_REQSENT (2) /* Waiting for a RESP */
142#define CBCP_RESPSENT (3) /* Waiting for an ACK */
143#define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */
144
145static const char *cbcpname[] = {
146 "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
147};
148
149static const char *
150cbcpstate(int s)
151{
152 if (s < sizeof cbcpname / sizeof cbcpname[0])
153 return cbcpname[s];
154 return "???";
155}
156
157static void
158cbcp_NewPhase(struct cbcp *cbcp, int new)
159{
160 if (cbcp->fsm.state != new) {
161 log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name,
162 cbcpstate(cbcp->fsm.state), cbcpstate(new));
163 cbcp->fsm.state = new;
164 }
165}
166
167struct cbcp_header {
168 u_char code;
169 u_char id;
170 u_int16_t length; /* Network byte order */
171};
172
173
174/* cbcp_header::code values */
175#define CBCP_REQ (1)
176#define CBCP_RESPONSE (2)
177#define CBCP_ACK (3)
178
179struct cbcp_data {
180 u_char type;
181 u_char length;
182 u_char delay;
183 char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */
184};
185
186/* cbcp_data::type values */
187#define CBCP_NONUM (1)
188#define CBCP_CLIENTNUM (2)
189#define CBCP_SERVERNUM (3)
190#define CBCP_LISTNUM (4)
191
192static void
193cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
194{
195 struct cbcp_header *head;
196 struct mbuf *bp;
197
198 bp = mbuf_Alloc(sizeof *head + data->length, MB_CBCPOUT);
199 head = (struct cbcp_header *)MBUF_CTOP(bp);
200 head->code = code;
201 head->id = cbcp->fsm.id;
202 head->length = htons(sizeof *head + data->length);
203 memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length);
204 log_DumpBp(LogDEBUG, "cbcp_Output", bp);
205 link_PushPacket(&cbcp->p->link, bp, cbcp->p->dl->bundle,
206 PRI_LINK, PROTO_CBCP);
206 LINK_QUEUES(&cbcp->p->link) - 1, PROTO_CBCP);
207}
208
209static const char *
210cbcp_data_Type(int type)
211{
212 static const char *types[] = {
213 "No callback", "User-spec", "Server-spec", "list"
214 };
215
216 if (type < 1 || type > sizeof types / sizeof types[0])
217 return "???";
218 return types[type-1];
219}
220
221struct cbcp_addr {
222 u_char type;
223 char addr[1]; /* Really ASCIIZ */
224};
225
226/* cbcp_data::type values */
227#define CBCP_ADDR_PSTN (1)
228
229static void
230cbcp_data_Show(struct cbcp_data *data)
231{
232 struct cbcp_addr *addr;
233 char *end;
234
235 addr = (struct cbcp_addr *)data->addr_start;
236 end = (char *)data + data->length;
237 *end = '\0';
238
239 log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type));
240 if ((char *)&data->delay < end) {
241 log_Printf(LogCBCP, " DELAY %d\n", data->delay);
242 while (addr->addr < end) {
243 if (addr->type == CBCP_ADDR_PSTN)
244 log_Printf(LogCBCP, " ADDR %s\n", addr->addr);
245 else
246 log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type);
247 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
248 }
249 }
250}
251
252static void
253cbcp_SendReq(struct cbcp *cbcp)
254{
255 struct cbcp_data data;
256 struct cbcp_addr *addr;
257 char list[sizeof cbcp->fsm.phone], *next;
258 int len, max;
259
260 /* Only callees send REQs */
261
262 log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name,
263 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
264 data.type = cbcp->fsm.type;
265 data.delay = 0;
266 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
267 list[sizeof list - 1] = '\0';
268
269 switch (data.type) {
270 case CBCP_CLIENTNUM:
271 addr = (struct cbcp_addr *)data.addr_start;
272 addr->type = CBCP_ADDR_PSTN;
273 *addr->addr = '\0';
274 data.length = addr->addr - (char *)&data;
275 break;
276
277 case CBCP_LISTNUM:
278 addr = (struct cbcp_addr *)data.addr_start;
279 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
280 len = strlen(next);
281 max = data.addr_start + sizeof data.addr_start - addr->addr - 1;
282 if (len <= max) {
283 addr->type = CBCP_ADDR_PSTN;
284 strcpy(addr->addr, next);
285 addr = (struct cbcp_addr *)((char *)addr + len + 2);
286 } else
287 log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n",
288 next);
289 }
290 data.length = (char *)addr - (char *)&data;
291 break;
292
293 case CBCP_SERVERNUM:
294 data.length = data.addr_start - (char *)&data;
295 break;
296
297 default:
298 data.length = (char *)&data.delay - (char *)&data;
299 break;
300 }
301
302 cbcp_data_Show(&data);
303 cbcp_Output(cbcp, CBCP_REQ, &data);
304 cbcp->fsm.restart--;
305 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
306 cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */
307}
308
309void
310cbcp_Up(struct cbcp *cbcp)
311{
312 struct lcp *lcp = &cbcp->p->link.lcp;
313
314 cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay;
315 if (*cbcp->p->dl->peer.authname == '\0' ||
316 !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone,
317 sizeof cbcp->fsm.phone)) {
318 strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone,
319 sizeof cbcp->fsm.phone - 1);
320 cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0';
321 }
322
323 if (lcp->want_callback.opmask) {
324 if (*cbcp->fsm.phone == '\0')
325 cbcp->fsm.type = CBCP_NONUM;
326 else if (!strcmp(cbcp->fsm.phone, "*")) {
327 cbcp->fsm.type = CBCP_SERVERNUM;
328 *cbcp->fsm.phone = '\0';
329 } else
330 cbcp->fsm.type = CBCP_CLIENTNUM;
331 cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */
332 cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_FSMTRIES);
333 } else {
334 if (*cbcp->fsm.phone == '\0')
335 cbcp->fsm.type = CBCP_NONUM;
336 else if (!strcmp(cbcp->fsm.phone, "*")) {
337 cbcp->fsm.type = CBCP_CLIENTNUM;
338 *cbcp->fsm.phone = '\0';
339 } else if (strchr(cbcp->fsm.phone, ','))
340 cbcp->fsm.type = CBCP_LISTNUM;
341 else
342 cbcp->fsm.type = CBCP_SERVERNUM;
343 cbcp->fsm.restart = DEF_FSMTRIES;
344 cbcp_SendReq(cbcp);
345 }
346}
347
348static int
349cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
350{
351 /*
352 * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*)
353 * so that we (hopefully) agree with the peer
354 */
355 struct cbcp_addr *addr;
356
357 switch (data->type) {
358 case CBCP_NONUM:
359 if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))
360 /*
361 * if ``none'' is a configured callback possibility
362 * (ie, ``set callback cbcp none''), go along with the callees
363 * request
364 */
365 cbcp->fsm.type = CBCP_NONUM;
366
367 /*
368 * Otherwise, we send our desired response anyway. This seems to be
369 * what Win95 does - although I can't find this behaviour documented
370 * in the CBCP spec....
371 */
372
373 return 1;
374
375 case CBCP_CLIENTNUM:
376 if (cbcp->fsm.type == CBCP_CLIENTNUM) {
377 char *ptr;
378
379 if (data->length > data->addr_start - (char *)data) {
380 /*
381 * The peer has given us an address type spec - make sure we
382 * understand !
383 */
384 addr = (struct cbcp_addr *)data->addr_start;
385 if (addr->type != CBCP_ADDR_PSTN) {
386 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
387 (int)addr->type);
388 return 0;
389 }
390 }
391 /* we accept the REQ even if the peer didn't specify an addr->type */
392 ptr = strchr(cbcp->fsm.phone, ',');
393 if (ptr)
394 *ptr = '\0'; /* Just use the first number in our list */
395 return 1;
396 }
397 log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
398 return 0;
399
400 case CBCP_SERVERNUM:
401 if (cbcp->fsm.type == CBCP_SERVERNUM) {
402 *cbcp->fsm.phone = '\0';
403 return 1;
404 }
405 if (data->length > data->addr_start - (char *)data) {
406 /*
407 * This violates the spec, but if the peer has told us the
408 * number it wants to call back, take advantage of this fact
409 * and allow things to proceed if we've specified the same
410 * number
411 */
412 addr = (struct cbcp_addr *)data->addr_start;
413 if (addr->type != CBCP_ADDR_PSTN) {
414 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
415 (int)addr->type);
416 return 0;
417 } else if (cbcp->fsm.type == CBCP_CLIENTNUM) {
418 /*
419 * If the peer's insisting on deciding the number, make sure
420 * it's one of the ones in our list. If it is, let the peer
421 * think it's in control :-)
422 */
423 char list[sizeof cbcp->fsm.phone], *next;
424
425 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
426 list[sizeof list - 1] = '\0';
427 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
428 if (!strcmp(next, addr->addr)) {
429 cbcp->fsm.type = CBCP_SERVERNUM;
430 strcpy(cbcp->fsm.phone, next);
431 return 1;
432 }
433 }
434 }
435 log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
436 return 0;
437
438 case CBCP_LISTNUM:
439 if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
440 /*
441 * Search through ``data''s addresses and see if cbcp->fsm.phone
442 * contains any of them
443 */
444 char list[sizeof cbcp->fsm.phone], *next, *end;
445
446 addr = (struct cbcp_addr *)data->addr_start;
447 end = (char *)data + data->length;
448
449 while (addr->addr < end) {
450 if (addr->type == CBCP_ADDR_PSTN) {
451 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
452 list[sizeof list - 1] = '\0';
453 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
454 if (!strcmp(next, addr->addr)) {
455 cbcp->fsm.type = CBCP_LISTNUM;
456 strcpy(cbcp->fsm.phone, next);
457 return 1;
458 }
459 } else
460 log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n",
461 (int)addr->type);
462 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
463 }
464 }
465 log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
466 return 0;
467 }
468
469 log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
470 return 0;
471}
472
473static void
474cbcp_SendResponse(struct cbcp *cbcp)
475{
476 struct cbcp_data data;
477 struct cbcp_addr *addr;
478
479 /* Only callers send RESPONSEs */
480
481 log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
482 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
483
484 data.type = cbcp->fsm.type;
485 data.delay = cbcp->fsm.delay;
486 addr = (struct cbcp_addr *)data.addr_start;
487 if (data.type == CBCP_NONUM)
488 data.length = (char *)&data.delay - (char *)&data;
489 else if (*cbcp->fsm.phone) {
490 addr->type = CBCP_ADDR_PSTN;
491 strcpy(addr->addr, cbcp->fsm.phone);
492 data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
493 } else
494 data.length = data.addr_start - (char *)&data;
495
496 cbcp_data_Show(&data);
497 cbcp_Output(cbcp, CBCP_RESPONSE, &data);
498 cbcp->fsm.restart--;
499 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
500 cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */
501}
502
503/* What to do after checking an incoming response */
504#define CBCP_ACTION_DOWN (0)
505#define CBCP_ACTION_REQ (1)
506#define CBCP_ACTION_ACK (2)
507
508static int
509cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
510{
511 /*
512 * We've received a RESPONSE (data). Check if it agrees with
513 * our REQ (cbcp->fsm)
514 */
515 struct cbcp_addr *addr;
516
517 addr = (struct cbcp_addr *)data->addr_start;
518
519 if (data->type == cbcp->fsm.type) {
520 switch (cbcp->fsm.type) {
521 case CBCP_NONUM:
522 return CBCP_ACTION_ACK;
523
524 case CBCP_CLIENTNUM:
525 if ((char *)data + data->length <= addr->addr)
526 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
527 else if (addr->type != CBCP_ADDR_PSTN)
528 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
529 addr->type);
530 else {
531 strcpy(cbcp->fsm.phone, addr->addr);
532 cbcp->fsm.delay = data->delay;
533 return CBCP_ACTION_ACK;
534 }
535 return CBCP_ACTION_DOWN;
536
537 case CBCP_SERVERNUM:
538 cbcp->fsm.delay = data->delay;
539 return CBCP_ACTION_ACK;
540
541 case CBCP_LISTNUM:
542 if ((char *)data + data->length <= addr->addr)
543 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
544 else if (addr->type != CBCP_ADDR_PSTN)
545 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
546 addr->type);
547 else {
548 char list[sizeof cbcp->fsm.phone], *next;
549
550 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
551 list[sizeof list - 1] = '\0';
552 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
553 if (!strcmp(addr->addr, next)) {
554 strcpy(cbcp->fsm.phone, next);
555 cbcp->fsm.delay = data->delay;
556 return CBCP_ACTION_ACK;
557 }
558 log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
559 "valid number !\n");
560 }
561 return CBCP_ACTION_DOWN;
562 }
563 log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n",
564 (int)cbcp->fsm.type);
565 return CBCP_ACTION_DOWN;
566 } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
567 /*
568 * Client doesn't want CBCP after all....
569 * We only allow this when ``set cbcp *'' has been specified.
570 */
571 cbcp->fsm.type = CBCP_NONUM;
572 return CBCP_ACTION_ACK;
573 }
574 log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
575 return CBCP_ACTION_REQ;
576}
577
578static void
579cbcp_SendAck(struct cbcp *cbcp)
580{
581 struct cbcp_data data;
582 struct cbcp_addr *addr;
583
584 /* Only callees send ACKs */
585
586 log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
587 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
588
589 data.type = cbcp->fsm.type;
590 switch (data.type) {
591 case CBCP_NONUM:
592 data.length = (char *)&data.delay - (char *)&data;
593 break;
594 case CBCP_CLIENTNUM:
595 addr = (struct cbcp_addr *)data.addr_start;
596 addr->type = CBCP_ADDR_PSTN;
597 strcpy(addr->addr, cbcp->fsm.phone);
598 data.delay = cbcp->fsm.delay;
599 data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
600 break;
601 default:
602 data.delay = cbcp->fsm.delay;
603 data.length = data.addr_start - (char *)&data;
604 break;
605 }
606
607 cbcp_data_Show(&data);
608 cbcp_Output(cbcp, CBCP_ACK, &data);
609 cbcp->fsm.restart--;
610 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
611 cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */
612}
613
614extern struct mbuf *
615cbcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
616{
617 struct physical *p = link2physical(l);
618 struct cbcp_header *head;
619 struct cbcp_data *data;
620 struct cbcp *cbcp = &p->dl->cbcp;
621 int len;
622
623 if (p == NULL) {
624 log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
625 mbuf_Free(bp);
626 return NULL;
627 }
628
629 bp = mbuf_Contiguous(bp);
630 len = mbuf_Length(bp);
631 if (len < sizeof(struct cbcp_header)) {
632 mbuf_Free(bp);
633 return NULL;
634 }
635 head = (struct cbcp_header *)MBUF_CTOP(bp);
636 if (ntohs(head->length) != len) {
637 log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)"
638 " - ignored\n", head->code, ntohs(head->length), len);
639 mbuf_Free(bp);
640 return NULL;
641 }
642 mbuf_SetType(bp, MB_CBCPIN);
643
644 /* XXX check the id */
645
646 bp->offset += sizeof(struct cbcp_header);
647 bp->cnt -= sizeof(struct cbcp_header);
648 data = (struct cbcp_data *)MBUF_CTOP(bp);
649
650 switch (head->code) {
651 case CBCP_REQ:
652 log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
653 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
654 cbcp_data_Show(data);
655 if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
656 timer_Stop(&cbcp->fsm.timer);
657 if (cbcp_AdjustResponse(cbcp, data)) {
658 cbcp->fsm.restart = DEF_FSMTRIES;
659 cbcp->fsm.id = head->id;
660 cbcp_SendResponse(cbcp);
661 } else
662 datalink_CBCPFailed(cbcp->p->dl);
663 } else
664 log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
665 break;
666
667 case CBCP_RESPONSE:
668 log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
669 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
670 cbcp_data_Show(data);
671 if (cbcp->fsm.id != head->id) {
672 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
673 cbcp->fsm.id, head->id);
674 cbcp->fsm.id = head->id;
675 }
676 if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
677 timer_Stop(&cbcp->fsm.timer);
678 switch (cbcp_CheckResponse(cbcp, data)) {
679 case CBCP_ACTION_REQ:
680 cbcp_SendReq(cbcp);
681 break;
682
683 case CBCP_ACTION_ACK:
684 cbcp->fsm.restart = DEF_FSMTRIES;
685 cbcp_SendAck(cbcp);
686 if (cbcp->fsm.type == CBCP_NONUM) {
687 /*
688 * Don't change state in case the peer doesn't get our ACK,
689 * just bring the layer up.
690 */
691 timer_Stop(&cbcp->fsm.timer);
692 datalink_NCPUp(cbcp->p->dl);
693 }
694 break;
695
696 default:
697 datalink_CBCPFailed(cbcp->p->dl);
698 break;
699 }
700 } else
701 log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
702 break;
703
704 case CBCP_ACK:
705 log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
706 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
707 cbcp_data_Show(data);
708 if (cbcp->fsm.id != head->id) {
709 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
710 cbcp->fsm.id, head->id);
711 cbcp->fsm.id = head->id;
712 }
713 if (cbcp->fsm.type == CBCP_NONUM) {
714 /*
715 * Don't change state in case the peer doesn't get our ACK,
716 * just bring the layer up.
717 */
718 timer_Stop(&cbcp->fsm.timer);
719 datalink_NCPUp(cbcp->p->dl);
720 } else if (cbcp->fsm.state == CBCP_RESPSENT) {
721 timer_Stop(&cbcp->fsm.timer);
722 datalink_CBCPComplete(cbcp->p->dl);
723 log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
724 } else
725 log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
726 break;
727
728 default:
729 log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n",
730 head->code, len);
731 break;
732 }
733
734 mbuf_Free(bp);
735 return NULL;
736}
737
738void
739cbcp_Down(struct cbcp *cbcp)
740{
741 timer_Stop(&cbcp->fsm.timer);
742 cbcp_NewPhase(cbcp, CBCP_CLOSED);
743 cbcp->required = 0;
744}
745
746void
747cbcp_ReceiveTerminateReq(struct physical *p)
748{
749 if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
750 /* Don't change our state in case the peer doesn't get the ACK */
751 p->dl->cbcp.required = 1;
752 log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
753 p->dl->cbcp.fsm.phone);
754 } else
755 cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);
756}
207}
208
209static const char *
210cbcp_data_Type(int type)
211{
212 static const char *types[] = {
213 "No callback", "User-spec", "Server-spec", "list"
214 };
215
216 if (type < 1 || type > sizeof types / sizeof types[0])
217 return "???";
218 return types[type-1];
219}
220
221struct cbcp_addr {
222 u_char type;
223 char addr[1]; /* Really ASCIIZ */
224};
225
226/* cbcp_data::type values */
227#define CBCP_ADDR_PSTN (1)
228
229static void
230cbcp_data_Show(struct cbcp_data *data)
231{
232 struct cbcp_addr *addr;
233 char *end;
234
235 addr = (struct cbcp_addr *)data->addr_start;
236 end = (char *)data + data->length;
237 *end = '\0';
238
239 log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type));
240 if ((char *)&data->delay < end) {
241 log_Printf(LogCBCP, " DELAY %d\n", data->delay);
242 while (addr->addr < end) {
243 if (addr->type == CBCP_ADDR_PSTN)
244 log_Printf(LogCBCP, " ADDR %s\n", addr->addr);
245 else
246 log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type);
247 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
248 }
249 }
250}
251
252static void
253cbcp_SendReq(struct cbcp *cbcp)
254{
255 struct cbcp_data data;
256 struct cbcp_addr *addr;
257 char list[sizeof cbcp->fsm.phone], *next;
258 int len, max;
259
260 /* Only callees send REQs */
261
262 log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name,
263 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
264 data.type = cbcp->fsm.type;
265 data.delay = 0;
266 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
267 list[sizeof list - 1] = '\0';
268
269 switch (data.type) {
270 case CBCP_CLIENTNUM:
271 addr = (struct cbcp_addr *)data.addr_start;
272 addr->type = CBCP_ADDR_PSTN;
273 *addr->addr = '\0';
274 data.length = addr->addr - (char *)&data;
275 break;
276
277 case CBCP_LISTNUM:
278 addr = (struct cbcp_addr *)data.addr_start;
279 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
280 len = strlen(next);
281 max = data.addr_start + sizeof data.addr_start - addr->addr - 1;
282 if (len <= max) {
283 addr->type = CBCP_ADDR_PSTN;
284 strcpy(addr->addr, next);
285 addr = (struct cbcp_addr *)((char *)addr + len + 2);
286 } else
287 log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n",
288 next);
289 }
290 data.length = (char *)addr - (char *)&data;
291 break;
292
293 case CBCP_SERVERNUM:
294 data.length = data.addr_start - (char *)&data;
295 break;
296
297 default:
298 data.length = (char *)&data.delay - (char *)&data;
299 break;
300 }
301
302 cbcp_data_Show(&data);
303 cbcp_Output(cbcp, CBCP_REQ, &data);
304 cbcp->fsm.restart--;
305 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
306 cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */
307}
308
309void
310cbcp_Up(struct cbcp *cbcp)
311{
312 struct lcp *lcp = &cbcp->p->link.lcp;
313
314 cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay;
315 if (*cbcp->p->dl->peer.authname == '\0' ||
316 !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone,
317 sizeof cbcp->fsm.phone)) {
318 strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone,
319 sizeof cbcp->fsm.phone - 1);
320 cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0';
321 }
322
323 if (lcp->want_callback.opmask) {
324 if (*cbcp->fsm.phone == '\0')
325 cbcp->fsm.type = CBCP_NONUM;
326 else if (!strcmp(cbcp->fsm.phone, "*")) {
327 cbcp->fsm.type = CBCP_SERVERNUM;
328 *cbcp->fsm.phone = '\0';
329 } else
330 cbcp->fsm.type = CBCP_CLIENTNUM;
331 cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */
332 cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_FSMTRIES);
333 } else {
334 if (*cbcp->fsm.phone == '\0')
335 cbcp->fsm.type = CBCP_NONUM;
336 else if (!strcmp(cbcp->fsm.phone, "*")) {
337 cbcp->fsm.type = CBCP_CLIENTNUM;
338 *cbcp->fsm.phone = '\0';
339 } else if (strchr(cbcp->fsm.phone, ','))
340 cbcp->fsm.type = CBCP_LISTNUM;
341 else
342 cbcp->fsm.type = CBCP_SERVERNUM;
343 cbcp->fsm.restart = DEF_FSMTRIES;
344 cbcp_SendReq(cbcp);
345 }
346}
347
348static int
349cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
350{
351 /*
352 * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*)
353 * so that we (hopefully) agree with the peer
354 */
355 struct cbcp_addr *addr;
356
357 switch (data->type) {
358 case CBCP_NONUM:
359 if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))
360 /*
361 * if ``none'' is a configured callback possibility
362 * (ie, ``set callback cbcp none''), go along with the callees
363 * request
364 */
365 cbcp->fsm.type = CBCP_NONUM;
366
367 /*
368 * Otherwise, we send our desired response anyway. This seems to be
369 * what Win95 does - although I can't find this behaviour documented
370 * in the CBCP spec....
371 */
372
373 return 1;
374
375 case CBCP_CLIENTNUM:
376 if (cbcp->fsm.type == CBCP_CLIENTNUM) {
377 char *ptr;
378
379 if (data->length > data->addr_start - (char *)data) {
380 /*
381 * The peer has given us an address type spec - make sure we
382 * understand !
383 */
384 addr = (struct cbcp_addr *)data->addr_start;
385 if (addr->type != CBCP_ADDR_PSTN) {
386 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
387 (int)addr->type);
388 return 0;
389 }
390 }
391 /* we accept the REQ even if the peer didn't specify an addr->type */
392 ptr = strchr(cbcp->fsm.phone, ',');
393 if (ptr)
394 *ptr = '\0'; /* Just use the first number in our list */
395 return 1;
396 }
397 log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
398 return 0;
399
400 case CBCP_SERVERNUM:
401 if (cbcp->fsm.type == CBCP_SERVERNUM) {
402 *cbcp->fsm.phone = '\0';
403 return 1;
404 }
405 if (data->length > data->addr_start - (char *)data) {
406 /*
407 * This violates the spec, but if the peer has told us the
408 * number it wants to call back, take advantage of this fact
409 * and allow things to proceed if we've specified the same
410 * number
411 */
412 addr = (struct cbcp_addr *)data->addr_start;
413 if (addr->type != CBCP_ADDR_PSTN) {
414 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
415 (int)addr->type);
416 return 0;
417 } else if (cbcp->fsm.type == CBCP_CLIENTNUM) {
418 /*
419 * If the peer's insisting on deciding the number, make sure
420 * it's one of the ones in our list. If it is, let the peer
421 * think it's in control :-)
422 */
423 char list[sizeof cbcp->fsm.phone], *next;
424
425 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
426 list[sizeof list - 1] = '\0';
427 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
428 if (!strcmp(next, addr->addr)) {
429 cbcp->fsm.type = CBCP_SERVERNUM;
430 strcpy(cbcp->fsm.phone, next);
431 return 1;
432 }
433 }
434 }
435 log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
436 return 0;
437
438 case CBCP_LISTNUM:
439 if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
440 /*
441 * Search through ``data''s addresses and see if cbcp->fsm.phone
442 * contains any of them
443 */
444 char list[sizeof cbcp->fsm.phone], *next, *end;
445
446 addr = (struct cbcp_addr *)data->addr_start;
447 end = (char *)data + data->length;
448
449 while (addr->addr < end) {
450 if (addr->type == CBCP_ADDR_PSTN) {
451 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
452 list[sizeof list - 1] = '\0';
453 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
454 if (!strcmp(next, addr->addr)) {
455 cbcp->fsm.type = CBCP_LISTNUM;
456 strcpy(cbcp->fsm.phone, next);
457 return 1;
458 }
459 } else
460 log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n",
461 (int)addr->type);
462 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
463 }
464 }
465 log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
466 return 0;
467 }
468
469 log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
470 return 0;
471}
472
473static void
474cbcp_SendResponse(struct cbcp *cbcp)
475{
476 struct cbcp_data data;
477 struct cbcp_addr *addr;
478
479 /* Only callers send RESPONSEs */
480
481 log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
482 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
483
484 data.type = cbcp->fsm.type;
485 data.delay = cbcp->fsm.delay;
486 addr = (struct cbcp_addr *)data.addr_start;
487 if (data.type == CBCP_NONUM)
488 data.length = (char *)&data.delay - (char *)&data;
489 else if (*cbcp->fsm.phone) {
490 addr->type = CBCP_ADDR_PSTN;
491 strcpy(addr->addr, cbcp->fsm.phone);
492 data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
493 } else
494 data.length = data.addr_start - (char *)&data;
495
496 cbcp_data_Show(&data);
497 cbcp_Output(cbcp, CBCP_RESPONSE, &data);
498 cbcp->fsm.restart--;
499 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
500 cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */
501}
502
503/* What to do after checking an incoming response */
504#define CBCP_ACTION_DOWN (0)
505#define CBCP_ACTION_REQ (1)
506#define CBCP_ACTION_ACK (2)
507
508static int
509cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
510{
511 /*
512 * We've received a RESPONSE (data). Check if it agrees with
513 * our REQ (cbcp->fsm)
514 */
515 struct cbcp_addr *addr;
516
517 addr = (struct cbcp_addr *)data->addr_start;
518
519 if (data->type == cbcp->fsm.type) {
520 switch (cbcp->fsm.type) {
521 case CBCP_NONUM:
522 return CBCP_ACTION_ACK;
523
524 case CBCP_CLIENTNUM:
525 if ((char *)data + data->length <= addr->addr)
526 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
527 else if (addr->type != CBCP_ADDR_PSTN)
528 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
529 addr->type);
530 else {
531 strcpy(cbcp->fsm.phone, addr->addr);
532 cbcp->fsm.delay = data->delay;
533 return CBCP_ACTION_ACK;
534 }
535 return CBCP_ACTION_DOWN;
536
537 case CBCP_SERVERNUM:
538 cbcp->fsm.delay = data->delay;
539 return CBCP_ACTION_ACK;
540
541 case CBCP_LISTNUM:
542 if ((char *)data + data->length <= addr->addr)
543 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
544 else if (addr->type != CBCP_ADDR_PSTN)
545 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
546 addr->type);
547 else {
548 char list[sizeof cbcp->fsm.phone], *next;
549
550 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
551 list[sizeof list - 1] = '\0';
552 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
553 if (!strcmp(addr->addr, next)) {
554 strcpy(cbcp->fsm.phone, next);
555 cbcp->fsm.delay = data->delay;
556 return CBCP_ACTION_ACK;
557 }
558 log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
559 "valid number !\n");
560 }
561 return CBCP_ACTION_DOWN;
562 }
563 log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n",
564 (int)cbcp->fsm.type);
565 return CBCP_ACTION_DOWN;
566 } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
567 /*
568 * Client doesn't want CBCP after all....
569 * We only allow this when ``set cbcp *'' has been specified.
570 */
571 cbcp->fsm.type = CBCP_NONUM;
572 return CBCP_ACTION_ACK;
573 }
574 log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
575 return CBCP_ACTION_REQ;
576}
577
578static void
579cbcp_SendAck(struct cbcp *cbcp)
580{
581 struct cbcp_data data;
582 struct cbcp_addr *addr;
583
584 /* Only callees send ACKs */
585
586 log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
587 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
588
589 data.type = cbcp->fsm.type;
590 switch (data.type) {
591 case CBCP_NONUM:
592 data.length = (char *)&data.delay - (char *)&data;
593 break;
594 case CBCP_CLIENTNUM:
595 addr = (struct cbcp_addr *)data.addr_start;
596 addr->type = CBCP_ADDR_PSTN;
597 strcpy(addr->addr, cbcp->fsm.phone);
598 data.delay = cbcp->fsm.delay;
599 data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
600 break;
601 default:
602 data.delay = cbcp->fsm.delay;
603 data.length = data.addr_start - (char *)&data;
604 break;
605 }
606
607 cbcp_data_Show(&data);
608 cbcp_Output(cbcp, CBCP_ACK, &data);
609 cbcp->fsm.restart--;
610 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
611 cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */
612}
613
614extern struct mbuf *
615cbcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
616{
617 struct physical *p = link2physical(l);
618 struct cbcp_header *head;
619 struct cbcp_data *data;
620 struct cbcp *cbcp = &p->dl->cbcp;
621 int len;
622
623 if (p == NULL) {
624 log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
625 mbuf_Free(bp);
626 return NULL;
627 }
628
629 bp = mbuf_Contiguous(bp);
630 len = mbuf_Length(bp);
631 if (len < sizeof(struct cbcp_header)) {
632 mbuf_Free(bp);
633 return NULL;
634 }
635 head = (struct cbcp_header *)MBUF_CTOP(bp);
636 if (ntohs(head->length) != len) {
637 log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)"
638 " - ignored\n", head->code, ntohs(head->length), len);
639 mbuf_Free(bp);
640 return NULL;
641 }
642 mbuf_SetType(bp, MB_CBCPIN);
643
644 /* XXX check the id */
645
646 bp->offset += sizeof(struct cbcp_header);
647 bp->cnt -= sizeof(struct cbcp_header);
648 data = (struct cbcp_data *)MBUF_CTOP(bp);
649
650 switch (head->code) {
651 case CBCP_REQ:
652 log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
653 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
654 cbcp_data_Show(data);
655 if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
656 timer_Stop(&cbcp->fsm.timer);
657 if (cbcp_AdjustResponse(cbcp, data)) {
658 cbcp->fsm.restart = DEF_FSMTRIES;
659 cbcp->fsm.id = head->id;
660 cbcp_SendResponse(cbcp);
661 } else
662 datalink_CBCPFailed(cbcp->p->dl);
663 } else
664 log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
665 break;
666
667 case CBCP_RESPONSE:
668 log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
669 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
670 cbcp_data_Show(data);
671 if (cbcp->fsm.id != head->id) {
672 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
673 cbcp->fsm.id, head->id);
674 cbcp->fsm.id = head->id;
675 }
676 if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
677 timer_Stop(&cbcp->fsm.timer);
678 switch (cbcp_CheckResponse(cbcp, data)) {
679 case CBCP_ACTION_REQ:
680 cbcp_SendReq(cbcp);
681 break;
682
683 case CBCP_ACTION_ACK:
684 cbcp->fsm.restart = DEF_FSMTRIES;
685 cbcp_SendAck(cbcp);
686 if (cbcp->fsm.type == CBCP_NONUM) {
687 /*
688 * Don't change state in case the peer doesn't get our ACK,
689 * just bring the layer up.
690 */
691 timer_Stop(&cbcp->fsm.timer);
692 datalink_NCPUp(cbcp->p->dl);
693 }
694 break;
695
696 default:
697 datalink_CBCPFailed(cbcp->p->dl);
698 break;
699 }
700 } else
701 log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
702 break;
703
704 case CBCP_ACK:
705 log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
706 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
707 cbcp_data_Show(data);
708 if (cbcp->fsm.id != head->id) {
709 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
710 cbcp->fsm.id, head->id);
711 cbcp->fsm.id = head->id;
712 }
713 if (cbcp->fsm.type == CBCP_NONUM) {
714 /*
715 * Don't change state in case the peer doesn't get our ACK,
716 * just bring the layer up.
717 */
718 timer_Stop(&cbcp->fsm.timer);
719 datalink_NCPUp(cbcp->p->dl);
720 } else if (cbcp->fsm.state == CBCP_RESPSENT) {
721 timer_Stop(&cbcp->fsm.timer);
722 datalink_CBCPComplete(cbcp->p->dl);
723 log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
724 } else
725 log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
726 break;
727
728 default:
729 log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n",
730 head->code, len);
731 break;
732 }
733
734 mbuf_Free(bp);
735 return NULL;
736}
737
738void
739cbcp_Down(struct cbcp *cbcp)
740{
741 timer_Stop(&cbcp->fsm.timer);
742 cbcp_NewPhase(cbcp, CBCP_CLOSED);
743 cbcp->required = 0;
744}
745
746void
747cbcp_ReceiveTerminateReq(struct physical *p)
748{
749 if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
750 /* Don't change our state in case the peer doesn't get the ACK */
751 p->dl->cbcp.required = 1;
752 log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
753 p->dl->cbcp.fsm.phone);
754 } else
755 cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);
756}