File: | src/usr.sbin/pppd/fsm.c |
Warning: | line 809, column 2 Null pointer passed as 2nd argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: fsm.c,v 1.8 2009/10/27 23:59:53 deraadt Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * fsm.c - {Link, IP} Control Protocol Finite State Machine. | |||
5 | * | |||
6 | * Copyright (c) 1984-2000 Carnegie Mellon University. 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 name "Carnegie Mellon University" must not be used to | |||
21 | * endorse or promote products derived from this software without | |||
22 | * prior written permission. For permission or any legal | |||
23 | * details, please contact | |||
24 | * Office of Technology Transfer | |||
25 | * Carnegie Mellon University | |||
26 | * 5000 Forbes Avenue | |||
27 | * Pittsburgh, PA 15213-3890 | |||
28 | * (412) 268-4387, fax: (412) 268-7395 | |||
29 | * tech-transfer@andrew.cmu.edu | |||
30 | * | |||
31 | * 4. Redistributions of any form whatsoever must retain the following | |||
32 | * acknowledgment: | |||
33 | * "This product includes software developed by Computing Services | |||
34 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | |||
35 | * | |||
36 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | |||
37 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||
38 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | |||
39 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
40 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |||
41 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||
42 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
43 | */ | |||
44 | ||||
45 | /* | |||
46 | * TODO: | |||
47 | * Randomize fsm id on link/init. | |||
48 | * Deal with variable outgoing MTU. | |||
49 | */ | |||
50 | ||||
51 | #include <stdio.h> | |||
52 | #include <string.h> | |||
53 | #include <sys/types.h> | |||
54 | #include <syslog.h> | |||
55 | ||||
56 | #include "pppd.h" | |||
57 | #include "fsm.h" | |||
58 | ||||
59 | static void fsm_timeout(void *); | |||
60 | static void fsm_rconfreq(fsm *, int, u_char *, int); | |||
61 | static void fsm_rconfack(fsm *, int, u_char *, int); | |||
62 | static void fsm_rconfnakrej(fsm *, int, int, u_char *, int); | |||
63 | static void fsm_rtermreq(fsm *, int, u_char *, int); | |||
64 | static void fsm_rtermack(fsm *); | |||
65 | static void fsm_rcoderej(fsm *, u_char *, int); | |||
66 | static void fsm_sconfreq(fsm *, int); | |||
67 | ||||
68 | #define PROTO_NAME(f)((f)->callbacks->proto_name) ((f)->callbacks->proto_name) | |||
69 | ||||
70 | int peer_mru[NUM_PPP1]; | |||
71 | ||||
72 | ||||
73 | /* | |||
74 | * fsm_init - Initialize fsm. | |||
75 | * | |||
76 | * Initialize fsm state. | |||
77 | */ | |||
78 | void | |||
79 | fsm_init(f) | |||
80 | fsm *f; | |||
81 | { | |||
82 | f->state = INITIAL0; | |||
83 | f->flags = 0; | |||
84 | f->id = 0; /* XXX Start with random id? */ | |||
85 | f->timeouttime = DEFTIMEOUT3; | |||
86 | f->maxconfreqtransmits = DEFMAXCONFREQS10; | |||
87 | f->maxtermtransmits = DEFMAXTERMREQS2; | |||
88 | f->maxnakloops = DEFMAXNAKLOOPS5; | |||
89 | f->term_reason_len = 0; | |||
90 | } | |||
91 | ||||
92 | ||||
93 | /* | |||
94 | * fsm_lowerup - The lower layer is up. | |||
95 | */ | |||
96 | void | |||
97 | fsm_lowerup(f) | |||
98 | fsm *f; | |||
99 | { | |||
100 | switch( f->state ){ | |||
101 | case INITIAL0: | |||
102 | f->state = CLOSED2; | |||
103 | break; | |||
104 | ||||
105 | case STARTING1: | |||
106 | if( f->flags & OPT_SILENT4 ) | |||
107 | f->state = STOPPED3; | |||
108 | else { | |||
109 | /* Send an initial configure-request */ | |||
110 | fsm_sconfreq(f, 0); | |||
111 | f->state = REQSENT6; | |||
112 | } | |||
113 | break; | |||
114 | ||||
115 | default: | |||
116 | FSMDEBUG((LOG_INFO, "%s: Up event in state %d!", | |||
117 | PROTO_NAME(f), f->state)); | |||
118 | } | |||
119 | } | |||
120 | ||||
121 | ||||
122 | /* | |||
123 | * fsm_lowerdown - The lower layer is down. | |||
124 | * | |||
125 | * Cancel all timeouts and inform upper layers. | |||
126 | */ | |||
127 | void | |||
128 | fsm_lowerdown(f) | |||
129 | fsm *f; | |||
130 | { | |||
131 | switch( f->state ){ | |||
132 | case CLOSED2: | |||
133 | f->state = INITIAL0; | |||
134 | break; | |||
135 | ||||
136 | case STOPPED3: | |||
137 | f->state = STARTING1; | |||
138 | if( f->callbacks->starting ) | |||
139 | (*f->callbacks->starting)(f); | |||
140 | break; | |||
141 | ||||
142 | case CLOSING4: | |||
143 | f->state = INITIAL0; | |||
144 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
145 | break; | |||
146 | ||||
147 | case STOPPING5: | |||
148 | case REQSENT6: | |||
149 | case ACKRCVD7: | |||
150 | case ACKSENT8: | |||
151 | f->state = STARTING1; | |||
152 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
153 | break; | |||
154 | ||||
155 | case OPENED9: | |||
156 | if( f->callbacks->down ) | |||
157 | (*f->callbacks->down)(f); | |||
158 | f->state = STARTING1; | |||
159 | break; | |||
160 | ||||
161 | default: | |||
162 | FSMDEBUG((LOG_INFO, "%s: Down event in state %d!", | |||
163 | PROTO_NAME(f), f->state)); | |||
164 | } | |||
165 | } | |||
166 | ||||
167 | ||||
168 | /* | |||
169 | * fsm_open - Link is allowed to come up. | |||
170 | */ | |||
171 | void | |||
172 | fsm_open(f) | |||
173 | fsm *f; | |||
174 | { | |||
175 | switch( f->state ){ | |||
176 | case INITIAL0: | |||
177 | f->state = STARTING1; | |||
178 | if( f->callbacks->starting ) | |||
179 | (*f->callbacks->starting)(f); | |||
180 | break; | |||
181 | ||||
182 | case CLOSED2: | |||
183 | if( f->flags & OPT_SILENT4 ) | |||
184 | f->state = STOPPED3; | |||
185 | else { | |||
186 | /* Send an initial configure-request */ | |||
187 | fsm_sconfreq(f, 0); | |||
188 | f->state = REQSENT6; | |||
189 | } | |||
190 | break; | |||
191 | ||||
192 | case CLOSING4: | |||
193 | f->state = STOPPING5; | |||
194 | /* fall through */ | |||
195 | case STOPPED3: | |||
196 | case OPENED9: | |||
197 | if( f->flags & OPT_RESTART2 ){ | |||
198 | fsm_lowerdown(f); | |||
199 | fsm_lowerup(f); | |||
200 | } | |||
201 | break; | |||
202 | } | |||
203 | } | |||
204 | ||||
205 | ||||
206 | /* | |||
207 | * fsm_close - Start closing connection. | |||
208 | * | |||
209 | * Cancel timeouts and either initiate close or possibly go directly to | |||
210 | * the CLOSED state. | |||
211 | */ | |||
212 | void | |||
213 | fsm_close(f, reason) | |||
214 | fsm *f; | |||
215 | char *reason; | |||
216 | { | |||
217 | f->term_reason = reason; | |||
| ||||
218 | f->term_reason_len = (reason == NULL((void *)0)? 0: strlen(reason)); | |||
219 | switch( f->state ){ | |||
220 | case STARTING1: | |||
221 | f->state = INITIAL0; | |||
222 | break; | |||
223 | case STOPPED3: | |||
224 | f->state = CLOSED2; | |||
225 | break; | |||
226 | case STOPPING5: | |||
227 | f->state = CLOSING4; | |||
228 | break; | |||
229 | ||||
230 | case REQSENT6: | |||
231 | case ACKRCVD7: | |||
232 | case ACKSENT8: | |||
233 | case OPENED9: | |||
234 | if( f->state
| |||
235 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
236 | else if( f->callbacks->down ) | |||
237 | (*f->callbacks->down)(f); /* Inform upper layers we're down */ | |||
238 | ||||
239 | /* Init restart counter, send Terminate-Request */ | |||
240 | f->retransmits = f->maxtermtransmits; | |||
241 | fsm_sdata(f, TERMREQ5, f->reqid = ++f->id, | |||
242 | (u_char *) f->term_reason, f->term_reason_len); | |||
243 | TIMEOUT(fsm_timeout, f, f->timeouttime)timeout((fsm_timeout), (f), (f->timeouttime)); | |||
244 | --f->retransmits; | |||
245 | ||||
246 | f->state = CLOSING4; | |||
247 | break; | |||
248 | } | |||
249 | } | |||
250 | ||||
251 | ||||
252 | /* | |||
253 | * fsm_timeout - Timeout expired. | |||
254 | */ | |||
255 | static void | |||
256 | fsm_timeout(arg) | |||
257 | void *arg; | |||
258 | { | |||
259 | fsm *f = (fsm *) arg; | |||
260 | ||||
261 | switch (f->state) { | |||
262 | case CLOSING4: | |||
263 | case STOPPING5: | |||
264 | if( f->retransmits <= 0 ){ | |||
265 | /* | |||
266 | * We've waited for an ack long enough. Peer probably heard us. | |||
267 | */ | |||
268 | f->state = (f->state == CLOSING4)? CLOSED2: STOPPED3; | |||
269 | if( f->callbacks->finished ) | |||
270 | (*f->callbacks->finished)(f); | |||
271 | } else { | |||
272 | /* Send Terminate-Request */ | |||
273 | fsm_sdata(f, TERMREQ5, f->reqid = ++f->id, | |||
274 | (u_char *) f->term_reason, f->term_reason_len); | |||
275 | TIMEOUT(fsm_timeout, f, f->timeouttime)timeout((fsm_timeout), (f), (f->timeouttime)); | |||
276 | --f->retransmits; | |||
277 | } | |||
278 | break; | |||
279 | ||||
280 | case REQSENT6: | |||
281 | case ACKRCVD7: | |||
282 | case ACKSENT8: | |||
283 | if (f->retransmits <= 0) { | |||
284 | syslog(LOG_WARNING4, "%s: timeout sending Config-Requests", | |||
285 | PROTO_NAME(f)((f)->callbacks->proto_name)); | |||
286 | f->state = STOPPED3; | |||
287 | if( (f->flags & OPT_PASSIVE1) == 0 && f->callbacks->finished ) | |||
288 | (*f->callbacks->finished)(f); | |||
289 | ||||
290 | } else { | |||
291 | /* Retransmit the configure-request */ | |||
292 | if (f->callbacks->retransmit) | |||
293 | (*f->callbacks->retransmit)(f); | |||
294 | fsm_sconfreq(f, 1); /* Re-send Configure-Request */ | |||
295 | if( f->state == ACKRCVD7 ) | |||
296 | f->state = REQSENT6; | |||
297 | } | |||
298 | break; | |||
299 | ||||
300 | default: | |||
301 | FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!", | |||
302 | PROTO_NAME(f), f->state)); | |||
303 | } | |||
304 | } | |||
305 | ||||
306 | ||||
307 | /* | |||
308 | * fsm_input - Input packet. | |||
309 | */ | |||
310 | void | |||
311 | fsm_input(f, inpacket, l) | |||
312 | fsm *f; | |||
313 | u_char *inpacket; | |||
314 | int l; | |||
315 | { | |||
316 | u_char *inp; | |||
317 | u_char code, id; | |||
318 | int len; | |||
319 | ||||
320 | /* | |||
321 | * Parse header (code, id and length). | |||
322 | * If packet too short, drop it. | |||
323 | */ | |||
324 | inp = inpacket; | |||
325 | if (l < HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))) { | |||
326 | FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", | |||
327 | f->protocol)); | |||
328 | return; | |||
329 | } | |||
330 | GETCHAR(code, inp){ (code) = *(inp)++; }; | |||
331 | GETCHAR(id, inp){ (id) = *(inp)++; }; | |||
332 | GETSHORT(len, inp){ (len) = *(inp)++ << 8; (len) |= *(inp)++; }; | |||
333 | if (len < HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))) { | |||
334 | FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.", | |||
335 | f->protocol)); | |||
336 | return; | |||
337 | } | |||
338 | if (len > l) { | |||
339 | FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", | |||
340 | f->protocol)); | |||
341 | return; | |||
342 | } | |||
343 | len -= HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); /* subtract header length */ | |||
344 | ||||
345 | if( f->state == INITIAL0 || f->state == STARTING1 ){ | |||
346 | FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.", | |||
347 | f->protocol, f->state)); | |||
348 | return; | |||
349 | } | |||
350 | ||||
351 | /* | |||
352 | * Action depends on code. | |||
353 | */ | |||
354 | switch (code) { | |||
355 | case CONFREQ1: | |||
356 | fsm_rconfreq(f, id, inp, len); | |||
357 | break; | |||
358 | ||||
359 | case CONFACK2: | |||
360 | fsm_rconfack(f, id, inp, len); | |||
361 | break; | |||
362 | ||||
363 | case CONFNAK3: | |||
364 | case CONFREJ4: | |||
365 | fsm_rconfnakrej(f, code, id, inp, len); | |||
366 | break; | |||
367 | ||||
368 | case TERMREQ5: | |||
369 | fsm_rtermreq(f, id, inp, len); | |||
370 | break; | |||
371 | ||||
372 | case TERMACK6: | |||
373 | fsm_rtermack(f); | |||
374 | break; | |||
375 | ||||
376 | case CODEREJ7: | |||
377 | fsm_rcoderej(f, inp, len); | |||
378 | break; | |||
379 | ||||
380 | default: | |||
381 | if( !f->callbacks->extcode | |||
382 | || !(*f->callbacks->extcode)(f, code, id, inp, len) ) | |||
383 | fsm_sdata(f, CODEREJ7, ++f->id, inpacket, len + HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))); | |||
384 | break; | |||
385 | } | |||
386 | } | |||
387 | ||||
388 | ||||
389 | /* | |||
390 | * fsm_rconfreq - Receive Configure-Request. | |||
391 | */ | |||
392 | static void | |||
393 | fsm_rconfreq(f, id, inp, len) | |||
394 | fsm *f; | |||
395 | u_char id; | |||
396 | u_char *inp; | |||
397 | int len; | |||
398 | { | |||
399 | int code, reject_if_disagree; | |||
400 | ||||
401 | FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); | |||
402 | switch( f->state ){ | |||
403 | case CLOSED2: | |||
404 | /* Go away, we're closed */ | |||
405 | fsm_sdata(f, TERMACK6, id, NULL((void *)0), 0); | |||
406 | return; | |||
407 | case CLOSING4: | |||
408 | case STOPPING5: | |||
409 | return; | |||
410 | ||||
411 | case OPENED9: | |||
412 | /* Go down and restart negotiation */ | |||
413 | if( f->callbacks->down ) | |||
414 | (*f->callbacks->down)(f); /* Inform upper layers */ | |||
415 | fsm_sconfreq(f, 0); /* Send initial Configure-Request */ | |||
416 | break; | |||
417 | ||||
418 | case STOPPED3: | |||
419 | /* Negotiation started by our peer */ | |||
420 | fsm_sconfreq(f, 0); /* Send initial Configure-Request */ | |||
421 | f->state = REQSENT6; | |||
422 | break; | |||
423 | } | |||
424 | ||||
425 | /* | |||
426 | * Pass the requested configuration options | |||
427 | * to protocol-specific code for checking. | |||
428 | */ | |||
429 | if (f->callbacks->reqci){ /* Check CI */ | |||
430 | reject_if_disagree = (f->nakloops >= f->maxnakloops); | |||
431 | code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); | |||
432 | } else if (len) | |||
433 | code = CONFREJ4; /* Reject all CI */ | |||
434 | else | |||
435 | code = CONFACK2; | |||
436 | ||||
437 | /* send the Ack, Nak or Rej to the peer */ | |||
438 | fsm_sdata(f, code, id, inp, len); | |||
439 | ||||
440 | if (code == CONFACK2) { | |||
441 | if (f->state == ACKRCVD7) { | |||
442 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
443 | f->state = OPENED9; | |||
444 | if (f->callbacks->up) | |||
445 | (*f->callbacks->up)(f); /* Inform upper layers */ | |||
446 | } else | |||
447 | f->state = ACKSENT8; | |||
448 | f->nakloops = 0; | |||
449 | ||||
450 | } else { | |||
451 | /* we sent CONFACK or CONFREJ */ | |||
452 | if (f->state != ACKRCVD7) | |||
453 | f->state = REQSENT6; | |||
454 | if( code == CONFNAK3 ) | |||
455 | ++f->nakloops; | |||
456 | } | |||
457 | } | |||
458 | ||||
459 | ||||
460 | /* | |||
461 | * fsm_rconfack - Receive Configure-Ack. | |||
462 | */ | |||
463 | static void | |||
464 | fsm_rconfack(f, id, inp, len) | |||
465 | fsm *f; | |||
466 | int id; | |||
467 | u_char *inp; | |||
468 | int len; | |||
469 | { | |||
470 | FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.", | |||
471 | PROTO_NAME(f), id)); | |||
472 | ||||
473 | if (id != f->reqid || f->seen_ack) /* Expected id? */ | |||
474 | return; /* Nope, toss... */ | |||
475 | if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): | |||
476 | (len == 0)) ){ | |||
477 | /* Ack is bad - ignore it */ | |||
478 | log_packet(inp, len, "Received bad configure-ack: ", LOG_ERR3); | |||
479 | FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)", | |||
480 | PROTO_NAME(f), len)); | |||
481 | return; | |||
482 | } | |||
483 | f->seen_ack = 1; | |||
484 | ||||
485 | switch (f->state) { | |||
486 | case CLOSED2: | |||
487 | case STOPPED3: | |||
488 | fsm_sdata(f, TERMACK6, id, NULL((void *)0), 0); | |||
489 | break; | |||
490 | ||||
491 | case REQSENT6: | |||
492 | f->state = ACKRCVD7; | |||
493 | f->retransmits = f->maxconfreqtransmits; | |||
494 | break; | |||
495 | ||||
496 | case ACKRCVD7: | |||
497 | /* Huh? an extra valid Ack? oh well... */ | |||
498 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
499 | fsm_sconfreq(f, 0); | |||
500 | f->state = REQSENT6; | |||
501 | break; | |||
502 | ||||
503 | case ACKSENT8: | |||
504 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
505 | f->state = OPENED9; | |||
506 | f->retransmits = f->maxconfreqtransmits; | |||
507 | if (f->callbacks->up) | |||
508 | (*f->callbacks->up)(f); /* Inform upper layers */ | |||
509 | break; | |||
510 | ||||
511 | case OPENED9: | |||
512 | /* Go down and restart negotiation */ | |||
513 | if (f->callbacks->down) | |||
514 | (*f->callbacks->down)(f); /* Inform upper layers */ | |||
515 | fsm_sconfreq(f, 0); /* Send initial Configure-Request */ | |||
516 | f->state = REQSENT6; | |||
517 | break; | |||
518 | } | |||
519 | } | |||
520 | ||||
521 | ||||
522 | /* | |||
523 | * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. | |||
524 | */ | |||
525 | static void | |||
526 | fsm_rconfnakrej(f, code, id, inp, len) | |||
527 | fsm *f; | |||
528 | int code, id; | |||
529 | u_char *inp; | |||
530 | int len; | |||
531 | { | |||
532 | int (*proc)(fsm *, u_char *, int); | |||
533 | int ret; | |||
534 | ||||
535 | FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.", | |||
536 | PROTO_NAME(f), id)); | |||
537 | ||||
538 | if (id != f->reqid || f->seen_ack) /* Expected id? */ | |||
539 | return; /* Nope, toss... */ | |||
540 | proc = (code == CONFNAK3)? f->callbacks->nakci: f->callbacks->rejci; | |||
541 | if (!proc || !(ret = proc(f, inp, len))) { | |||
542 | /* Nak/reject is bad - ignore it */ | |||
543 | log_packet(inp, len, "Received bad configure-nak/rej: ", LOG_ERR3); | |||
544 | FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)", | |||
545 | PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); | |||
546 | return; | |||
547 | } | |||
548 | f->seen_ack = 1; | |||
549 | ||||
550 | switch (f->state) { | |||
551 | case CLOSED2: | |||
552 | case STOPPED3: | |||
553 | fsm_sdata(f, TERMACK6, id, NULL((void *)0), 0); | |||
554 | break; | |||
555 | ||||
556 | case REQSENT6: | |||
557 | case ACKSENT8: | |||
558 | /* They didn't agree to what we wanted - try another request */ | |||
559 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
560 | if (ret < 0) | |||
561 | f->state = STOPPED3; /* kludge for stopping CCP */ | |||
562 | else | |||
563 | fsm_sconfreq(f, 0); /* Send Configure-Request */ | |||
564 | break; | |||
565 | ||||
566 | case ACKRCVD7: | |||
567 | /* Got a Nak/reject when we had already had an Ack?? oh well... */ | |||
568 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
569 | fsm_sconfreq(f, 0); | |||
570 | f->state = REQSENT6; | |||
571 | break; | |||
572 | ||||
573 | case OPENED9: | |||
574 | /* Go down and restart negotiation */ | |||
575 | if (f->callbacks->down) | |||
576 | (*f->callbacks->down)(f); /* Inform upper layers */ | |||
577 | fsm_sconfreq(f, 0); /* Send initial Configure-Request */ | |||
578 | f->state = REQSENT6; | |||
579 | break; | |||
580 | } | |||
581 | } | |||
582 | ||||
583 | ||||
584 | /* | |||
585 | * fsm_rtermreq - Receive Terminate-Req. | |||
586 | */ | |||
587 | static void | |||
588 | fsm_rtermreq(f, id, p, len) | |||
589 | fsm *f; | |||
590 | int id; | |||
591 | u_char *p; | |||
592 | int len; | |||
593 | { | |||
594 | char str[80]; | |||
595 | ||||
596 | FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.", | |||
597 | PROTO_NAME(f), id)); | |||
598 | ||||
599 | switch (f->state) { | |||
600 | case ACKRCVD7: | |||
601 | case ACKSENT8: | |||
602 | f->state = REQSENT6; /* Start over but keep trying */ | |||
603 | break; | |||
604 | ||||
605 | case OPENED9: | |||
606 | if (len > 0) { | |||
607 | fmtmsg(str, sizeof(str), "%0.*v", len, p); | |||
608 | syslog(LOG_INFO6, "%s terminated by peer (%s)", PROTO_NAME(f)((f)->callbacks->proto_name), str); | |||
609 | } else | |||
610 | syslog(LOG_INFO6, "%s terminated by peer", PROTO_NAME(f)((f)->callbacks->proto_name)); | |||
611 | if (f->callbacks->down) | |||
612 | (*f->callbacks->down)(f); /* Inform upper layers */ | |||
613 | f->retransmits = 0; | |||
614 | f->state = STOPPING5; | |||
615 | TIMEOUT(fsm_timeout, f, f->timeouttime)timeout((fsm_timeout), (f), (f->timeouttime)); | |||
616 | break; | |||
617 | } | |||
618 | ||||
619 | fsm_sdata(f, TERMACK6, id, NULL((void *)0), 0); | |||
620 | } | |||
621 | ||||
622 | ||||
623 | /* | |||
624 | * fsm_rtermack - Receive Terminate-Ack. | |||
625 | */ | |||
626 | static void | |||
627 | fsm_rtermack(f) | |||
628 | fsm *f; | |||
629 | { | |||
630 | FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f))); | |||
631 | ||||
632 | switch (f->state) { | |||
633 | case CLOSING4: | |||
634 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); | |||
635 | f->state = CLOSED2; | |||
636 | if( f->callbacks->finished ) | |||
637 | (*f->callbacks->finished)(f); | |||
638 | break; | |||
639 | case STOPPING5: | |||
640 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); | |||
641 | f->state = STOPPED3; | |||
642 | if( f->callbacks->finished ) | |||
643 | (*f->callbacks->finished)(f); | |||
644 | break; | |||
645 | ||||
646 | case ACKRCVD7: | |||
647 | f->state = REQSENT6; | |||
648 | break; | |||
649 | ||||
650 | case OPENED9: | |||
651 | if (f->callbacks->down) | |||
652 | (*f->callbacks->down)(f); /* Inform upper layers */ | |||
653 | fsm_sconfreq(f, 0); | |||
654 | break; | |||
655 | } | |||
656 | } | |||
657 | ||||
658 | ||||
659 | /* | |||
660 | * fsm_rcoderej - Receive an Code-Reject. | |||
661 | */ | |||
662 | static void | |||
663 | fsm_rcoderej(f, inp, len) | |||
664 | fsm *f; | |||
665 | u_char *inp; | |||
666 | int len; | |||
667 | { | |||
668 | u_char code, id; | |||
669 | ||||
670 | FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f))); | |||
671 | ||||
672 | if (len < HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))) { | |||
673 | FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!")); | |||
674 | return; | |||
675 | } | |||
676 | GETCHAR(code, inp){ (code) = *(inp)++; }; | |||
677 | GETCHAR(id, inp){ (id) = *(inp)++; }; | |||
678 | syslog(LOG_WARNING4, "%s: Rcvd Code-Reject for code %d, id %d", | |||
679 | PROTO_NAME(f)((f)->callbacks->proto_name), code, id); | |||
680 | ||||
681 | if( f->state == ACKRCVD7 ) | |||
682 | f->state = REQSENT6; | |||
683 | } | |||
684 | ||||
685 | ||||
686 | /* | |||
687 | * fsm_protreject - Peer doesn't speak this protocol. | |||
688 | * | |||
689 | * Treat this as a catastrophic error (RXJ-). | |||
690 | */ | |||
691 | void | |||
692 | fsm_protreject(f) | |||
693 | fsm *f; | |||
694 | { | |||
695 | switch( f->state ){ | |||
696 | case CLOSING4: | |||
697 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
698 | /* fall through */ | |||
699 | case CLOSED2: | |||
700 | f->state = CLOSED2; | |||
701 | if( f->callbacks->finished ) | |||
702 | (*f->callbacks->finished)(f); | |||
703 | break; | |||
704 | ||||
705 | case STOPPING5: | |||
706 | case REQSENT6: | |||
707 | case ACKRCVD7: | |||
708 | case ACKSENT8: | |||
709 | UNTIMEOUT(fsm_timeout, f)untimeout((fsm_timeout), (f)); /* Cancel timeout */ | |||
710 | /* fall through */ | |||
711 | case STOPPED3: | |||
712 | f->state = STOPPED3; | |||
713 | if( f->callbacks->finished ) | |||
714 | (*f->callbacks->finished)(f); | |||
715 | break; | |||
716 | ||||
717 | case OPENED9: | |||
718 | if( f->callbacks->down ) | |||
719 | (*f->callbacks->down)(f); | |||
720 | ||||
721 | /* Init restart counter, send Terminate-Request */ | |||
722 | f->retransmits = f->maxtermtransmits; | |||
723 | fsm_sdata(f, TERMREQ5, f->reqid = ++f->id, | |||
724 | (u_char *) f->term_reason, f->term_reason_len); | |||
725 | TIMEOUT(fsm_timeout, f, f->timeouttime)timeout((fsm_timeout), (f), (f->timeouttime)); | |||
726 | --f->retransmits; | |||
727 | ||||
728 | f->state = STOPPING5; | |||
729 | break; | |||
730 | ||||
731 | default: | |||
732 | FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!", | |||
733 | PROTO_NAME(f), f->state)); | |||
734 | } | |||
735 | } | |||
736 | ||||
737 | ||||
738 | /* | |||
739 | * fsm_sconfreq - Send a Configure-Request. | |||
740 | */ | |||
741 | static void | |||
742 | fsm_sconfreq(f, retransmit) | |||
743 | fsm *f; | |||
744 | int retransmit; | |||
745 | { | |||
746 | u_char *outp; | |||
747 | int cilen; | |||
748 | ||||
749 | if( f->state != REQSENT6 && f->state != ACKRCVD7 && f->state != ACKSENT8 ){ | |||
750 | /* Not currently negotiating - reset options */ | |||
751 | if( f->callbacks->resetci ) | |||
752 | (*f->callbacks->resetci)(f); | |||
753 | f->nakloops = 0; | |||
754 | } | |||
755 | ||||
756 | if( !retransmit ){ | |||
757 | /* New request - reset retransmission counter, use new ID */ | |||
758 | f->retransmits = f->maxconfreqtransmits; | |||
759 | f->reqid = ++f->id; | |||
760 | } | |||
761 | ||||
762 | f->seen_ack = 0; | |||
763 | ||||
764 | /* | |||
765 | * Make up the request packet | |||
766 | */ | |||
767 | outp = outpacket_buf + PPP_HDRLEN4 + HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); | |||
768 | if( f->callbacks->cilen && f->callbacks->addci ){ | |||
769 | cilen = (*f->callbacks->cilen)(f); | |||
770 | if( cilen > peer_mru[f->unit] - HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) ) | |||
771 | cilen = peer_mru[f->unit] - HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); | |||
772 | if (f->callbacks->addci) | |||
773 | (*f->callbacks->addci)(f, outp, &cilen); | |||
774 | } else | |||
775 | cilen = 0; | |||
776 | ||||
777 | /* send the request to our peer */ | |||
778 | fsm_sdata(f, CONFREQ1, f->reqid, outp, cilen); | |||
779 | ||||
780 | /* start the retransmit timer */ | |||
781 | --f->retransmits; | |||
782 | TIMEOUT(fsm_timeout, f, f->timeouttime)timeout((fsm_timeout), (f), (f->timeouttime)); | |||
783 | ||||
784 | FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d", | |||
785 | PROTO_NAME(f), f->reqid)); | |||
786 | } | |||
787 | ||||
788 | ||||
789 | /* | |||
790 | * fsm_sdata - Send some data. | |||
791 | * | |||
792 | * Used for all packets sent to our peer by this module. | |||
793 | */ | |||
794 | void | |||
795 | fsm_sdata(f, code, id, data, datalen) | |||
796 | fsm *f; | |||
797 | u_char code, id; | |||
798 | u_char *data; | |||
799 | int datalen; | |||
800 | { | |||
801 | u_char *outp; | |||
802 | int outlen; | |||
803 | ||||
804 | /* Adjust length to be smaller than MTU */ | |||
805 | outp = outpacket_buf; | |||
806 | if (datalen > peer_mru[f->unit] - HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))) | |||
807 | datalen = peer_mru[f->unit] - HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); | |||
808 | if (datalen && data != outp + PPP_HDRLEN4 + HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))) | |||
809 | BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen)memcpy(outp + 4 + (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)), data, datalen); | |||
| ||||
810 | outlen = datalen + HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); | |||
811 | MAKEHEADER(outp, f->protocol){ { *(outp)++ = (u_char) (0xff); }; { *(outp)++ = (u_char) (0x03 ); }; { *(outp)++ = (u_char) ((f->protocol) >> 8); * (outp)++ = (u_char) (f->protocol); }; }; | |||
812 | PUTCHAR(code, outp){ *(outp)++ = (u_char) (code); }; | |||
813 | PUTCHAR(id, outp){ *(outp)++ = (u_char) (id); }; | |||
814 | PUTSHORT(outlen, outp){ *(outp)++ = (u_char) ((outlen) >> 8); *(outp)++ = (u_char ) (outlen); }; | |||
815 | output(f->unit, outpacket_buf, outlen + PPP_HDRLEN4); | |||
816 | ||||
817 | FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.", | |||
818 | PROTO_NAME(f), code, id)); | |||
819 | } |