File: | src/usr.sbin/pppd/ccp.c |
Warning: | line 671, column 2 Value stored to 'p' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ccp.c,v 1.13 2009/10/27 23:59:53 deraadt Exp $ */ |
2 | |
3 | /* |
4 | * ccp.c - PPP Compression Control Protocol. |
5 | * |
6 | * Copyright (c) 1989-2002 Paul Mackerras. 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(s) 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 Paul Mackerras |
27 | * <paulus@samba.org>". |
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 <string.h> |
39 | #include <syslog.h> |
40 | #include <sys/ioctl.h> |
41 | #include <sys/types.h> |
42 | |
43 | #include "pppd.h" |
44 | #include "fsm.h" |
45 | #include "ccp.h" |
46 | #include <net/ppp-comp.h> |
47 | |
48 | /* |
49 | * Protocol entry points from main code. |
50 | */ |
51 | static void ccp_init(int unit); |
52 | static void ccp_open(int unit); |
53 | static void ccp_close(int unit, char *); |
54 | static void ccp_lowerup(int unit); |
55 | static void ccp_lowerdown(int); |
56 | static void ccp_input(int unit, u_char *pkt, int len); |
57 | static void ccp_protrej(int unit); |
58 | static int ccp_printpkt(u_char *pkt, int len, |
59 | void (*printer)(void *, char *, ...), void *arg); |
60 | static void ccp_datainput(int unit, u_char *pkt, int len); |
61 | |
62 | struct protent ccp_protent = { |
63 | PPP_CCP0x80fd, |
64 | ccp_init, |
65 | ccp_input, |
66 | ccp_protrej, |
67 | ccp_lowerup, |
68 | ccp_lowerdown, |
69 | ccp_open, |
70 | ccp_close, |
71 | ccp_printpkt, |
72 | ccp_datainput, |
73 | 1, |
74 | "CCP", |
75 | NULL((void *)0), |
76 | NULL((void *)0), |
77 | NULL((void *)0) |
78 | }; |
79 | |
80 | fsm ccp_fsm[NUM_PPP1]; |
81 | ccp_options ccp_wantoptions[NUM_PPP1]; /* what to request the peer to use */ |
82 | ccp_options ccp_gotoptions[NUM_PPP1]; /* what the peer agreed to do */ |
83 | ccp_options ccp_allowoptions[NUM_PPP1]; /* what we'll agree to do */ |
84 | ccp_options ccp_hisoptions[NUM_PPP1]; /* what we agreed to do */ |
85 | |
86 | /* |
87 | * Callbacks for fsm code. |
88 | */ |
89 | static void ccp_resetci(fsm *); |
90 | static int ccp_cilen(fsm *); |
91 | static void ccp_addci(fsm *, u_char *, int *); |
92 | static int ccp_ackci(fsm *, u_char *, int); |
93 | static int ccp_nakci(fsm *, u_char *, int); |
94 | static int ccp_rejci(fsm *, u_char *, int); |
95 | static int ccp_reqci(fsm *, u_char *, int *, int); |
96 | static void ccp_up(fsm *); |
97 | static void ccp_down(fsm *); |
98 | static int ccp_extcode(fsm *, int, int, u_char *, int); |
99 | static void ccp_rack_timeout(void *); |
100 | static char *method_name(ccp_options *, ccp_options *); |
101 | |
102 | static fsm_callbacks ccp_callbacks = { |
103 | ccp_resetci, |
104 | ccp_cilen, |
105 | ccp_addci, |
106 | ccp_ackci, |
107 | ccp_nakci, |
108 | ccp_rejci, |
109 | ccp_reqci, |
110 | ccp_up, |
111 | ccp_down, |
112 | NULL((void *)0), |
113 | NULL((void *)0), |
114 | NULL((void *)0), |
115 | NULL((void *)0), |
116 | ccp_extcode, |
117 | "CCP" |
118 | }; |
119 | |
120 | /* |
121 | * Do we want / did we get any compression? |
122 | */ |
123 | #define ANY_COMPRESS(opt)((opt).deflate || (opt).bsd_compress || (opt).predictor_1 || ( opt).predictor_2) ((opt).deflate || (opt).bsd_compress \ |
124 | || (opt).predictor_1 || (opt).predictor_2) |
125 | |
126 | /* |
127 | * Local state (mainly for handling reset-reqs and reset-acks). |
128 | */ |
129 | static int ccp_localstate[NUM_PPP1]; |
130 | #define RACK_PENDING1 1 /* waiting for reset-ack */ |
131 | #define RREQ_REPEAT2 2 /* send another reset-req if no reset-ack */ |
132 | |
133 | #define RACKTIMEOUT1 1 /* second */ |
134 | |
135 | static int all_rejected[NUM_PPP1]; /* we rejected all peer's options */ |
136 | |
137 | /* |
138 | * ccp_init - initialize CCP. |
139 | */ |
140 | static void |
141 | ccp_init(unit) |
142 | int unit; |
143 | { |
144 | fsm *f = &ccp_fsm[unit]; |
145 | |
146 | f->unit = unit; |
147 | f->protocol = PPP_CCP0x80fd; |
148 | f->callbacks = &ccp_callbacks; |
149 | fsm_init(f); |
150 | |
151 | memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options)); |
152 | memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options)); |
153 | memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options)); |
154 | memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options)); |
155 | |
156 | ccp_wantoptions[0].deflate = 1; |
157 | ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE15; |
158 | ccp_wantoptions[0].deflate_correct = 1; |
159 | ccp_wantoptions[0].deflate_draft = 1; |
160 | ccp_allowoptions[0].deflate = 1; |
161 | ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE15; |
162 | ccp_allowoptions[0].deflate_correct = 1; |
163 | ccp_allowoptions[0].deflate_draft = 1; |
164 | |
165 | ccp_wantoptions[0].bsd_compress = 1; |
166 | ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS15; |
167 | ccp_allowoptions[0].bsd_compress = 1; |
168 | ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS15; |
169 | |
170 | ccp_allowoptions[0].predictor_1 = 1; |
171 | } |
172 | |
173 | /* |
174 | * ccp_open - CCP is allowed to come up. |
175 | */ |
176 | static void |
177 | ccp_open(unit) |
178 | int unit; |
179 | { |
180 | fsm *f = &ccp_fsm[unit]; |
181 | |
182 | if (f->state != OPENED9) |
183 | ccp_flags_set(unit, 1, 0); |
184 | |
185 | /* |
186 | * Find out which compressors the kernel supports before |
187 | * deciding whether to open in silent mode. |
188 | */ |
189 | ccp_resetci(f); |
190 | if (!ANY_COMPRESS(ccp_gotoptions[unit])((ccp_gotoptions[unit]).deflate || (ccp_gotoptions[unit]).bsd_compress || (ccp_gotoptions[unit]).predictor_1 || (ccp_gotoptions[unit ]).predictor_2)) |
191 | f->flags |= OPT_SILENT4; |
192 | |
193 | fsm_open(f); |
194 | } |
195 | |
196 | /* |
197 | * ccp_close - Terminate CCP. |
198 | */ |
199 | static void |
200 | ccp_close(unit, reason) |
201 | int unit; |
202 | char *reason; |
203 | { |
204 | ccp_flags_set(unit, 0, 0); |
205 | fsm_close(&ccp_fsm[unit], reason); |
206 | } |
207 | |
208 | /* |
209 | * ccp_lowerup - we may now transmit CCP packets. |
210 | */ |
211 | static void |
212 | ccp_lowerup(unit) |
213 | int unit; |
214 | { |
215 | fsm_lowerup(&ccp_fsm[unit]); |
216 | } |
217 | |
218 | /* |
219 | * ccp_lowerdown - we may not transmit CCP packets. |
220 | */ |
221 | static void |
222 | ccp_lowerdown(unit) |
223 | int unit; |
224 | { |
225 | fsm_lowerdown(&ccp_fsm[unit]); |
226 | } |
227 | |
228 | /* |
229 | * ccp_input - process a received CCP packet. |
230 | */ |
231 | static void |
232 | ccp_input(unit, p, len) |
233 | int unit; |
234 | u_char *p; |
235 | int len; |
236 | { |
237 | fsm *f = &ccp_fsm[unit]; |
238 | int oldstate; |
239 | |
240 | /* |
241 | * Check for a terminate-request so we can print a message. |
242 | */ |
243 | oldstate = f->state; |
244 | fsm_input(f, p, len); |
245 | if (oldstate == OPENED9 && p[0] == TERMREQ5 && f->state != OPENED9) |
246 | syslog(LOG_NOTICE5, "Compression disabled by peer."); |
247 | |
248 | /* |
249 | * If we get a terminate-ack and we're not asking for compression, |
250 | * close CCP. |
251 | */ |
252 | if (oldstate == REQSENT6 && p[0] == TERMACK6 |
253 | && !ANY_COMPRESS(ccp_gotoptions[unit])((ccp_gotoptions[unit]).deflate || (ccp_gotoptions[unit]).bsd_compress || (ccp_gotoptions[unit]).predictor_1 || (ccp_gotoptions[unit ]).predictor_2)) |
254 | ccp_close(unit, "No compression negotiated"); |
255 | } |
256 | |
257 | /* |
258 | * Handle a CCP-specific code. |
259 | */ |
260 | static int |
261 | ccp_extcode(f, code, id, p, len) |
262 | fsm *f; |
263 | int code, id; |
264 | u_char *p; |
265 | int len; |
266 | { |
267 | switch (code) { |
268 | case CCP_RESETREQ14: |
269 | if (f->state != OPENED9) |
270 | break; |
271 | /* send a reset-ack, which the transmitter will see and |
272 | reset its compression state. */ |
273 | fsm_sdata(f, CCP_RESETACK15, id, NULL((void *)0), 0); |
274 | break; |
275 | |
276 | case CCP_RESETACK15: |
277 | if (ccp_localstate[f->unit] & RACK_PENDING1 && id == f->reqid) { |
278 | ccp_localstate[f->unit] &= ~(RACK_PENDING1 | RREQ_REPEAT2); |
279 | UNTIMEOUT(ccp_rack_timeout, f)untimeout((ccp_rack_timeout), (f)); |
280 | } |
281 | break; |
282 | |
283 | default: |
284 | return 0; |
285 | } |
286 | |
287 | return 1; |
288 | } |
289 | |
290 | /* |
291 | * ccp_protrej - peer doesn't talk CCP. |
292 | */ |
293 | static void |
294 | ccp_protrej(unit) |
295 | int unit; |
296 | { |
297 | ccp_flags_set(unit, 0, 0); |
298 | fsm_lowerdown(&ccp_fsm[unit]); |
299 | } |
300 | |
301 | /* |
302 | * ccp_resetci - initialize at start of negotiation. |
303 | */ |
304 | static void |
305 | ccp_resetci(f) |
306 | fsm *f; |
307 | { |
308 | ccp_options *go = &ccp_gotoptions[f->unit]; |
309 | u_char opt_buf[16]; |
310 | |
311 | *go = ccp_wantoptions[f->unit]; |
312 | all_rejected[f->unit] = 0; |
313 | |
314 | /* |
315 | * Check whether the kernel knows about the various |
316 | * compression methods we might request. |
317 | */ |
318 | if (go->bsd_compress) { |
319 | opt_buf[0] = CI_BSD_COMPRESS21; |
320 | opt_buf[1] = CILEN_BSD_COMPRESS3; |
321 | opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS)(((1) << 5) | (9)); |
322 | if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS3, 0) <= 0) |
323 | go->bsd_compress = 0; |
324 | } |
325 | if (go->deflate) { |
326 | if (go->deflate_correct) { |
327 | opt_buf[0] = CI_DEFLATE26; |
328 | opt_buf[1] = CILEN_DEFLATE4; |
329 | opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE)((((8) - 8) << 4) + 8); |
330 | opt_buf[3] = DEFLATE_CHK_SEQUENCE0; |
331 | if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE4, 0) <= 0) |
332 | go->deflate_correct = 0; |
333 | } |
334 | if (go->deflate_draft) { |
335 | opt_buf[0] = CI_DEFLATE_DRAFT24; |
336 | opt_buf[1] = CILEN_DEFLATE4; |
337 | opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE)((((8) - 8) << 4) + 8); |
338 | opt_buf[3] = DEFLATE_CHK_SEQUENCE0; |
339 | if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE4, 0) <= 0) |
340 | go->deflate_draft = 0; |
341 | } |
342 | if (!go->deflate_correct && !go->deflate_draft) |
343 | go->deflate = 0; |
344 | } |
345 | if (go->predictor_1) { |
346 | opt_buf[0] = CI_PREDICTOR_11; |
347 | opt_buf[1] = CILEN_PREDICTOR_12; |
348 | if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_12, 0) <= 0) |
349 | go->predictor_1 = 0; |
350 | } |
351 | if (go->predictor_2) { |
352 | opt_buf[0] = CI_PREDICTOR_22; |
353 | opt_buf[1] = CILEN_PREDICTOR_22; |
354 | if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_22, 0) <= 0) |
355 | go->predictor_2 = 0; |
356 | } |
357 | } |
358 | |
359 | /* |
360 | * ccp_cilen - Return total length of our configuration info. |
361 | */ |
362 | static int |
363 | ccp_cilen(f) |
364 | fsm *f; |
365 | { |
366 | ccp_options *go = &ccp_gotoptions[f->unit]; |
367 | |
368 | return (go->bsd_compress? CILEN_BSD_COMPRESS3: 0) |
369 | + (go->deflate? CILEN_DEFLATE4: 0) |
370 | + (go->predictor_1? CILEN_PREDICTOR_12: 0) |
371 | + (go->predictor_2? CILEN_PREDICTOR_22: 0); |
372 | } |
373 | |
374 | /* |
375 | * ccp_addci - put our requests in a packet. |
376 | */ |
377 | static void |
378 | ccp_addci(f, p, lenp) |
379 | fsm *f; |
380 | u_char *p; |
381 | int *lenp; |
382 | { |
383 | int res; |
384 | ccp_options *go = &ccp_gotoptions[f->unit]; |
385 | u_char *p0 = p; |
386 | |
387 | /* |
388 | * Add the compression types that we can receive, in decreasing |
389 | * preference order. Get the kernel to allocate the first one |
390 | * in case it gets Acked. |
391 | */ |
392 | if (go->deflate) { |
393 | p[0] = go->deflate_correct? CI_DEFLATE26: CI_DEFLATE_DRAFT24; |
394 | p[1] = CILEN_DEFLATE4; |
395 | p[2] = DEFLATE_MAKE_OPT(go->deflate_size)((((go->deflate_size) - 8) << 4) + 8); |
396 | p[3] = DEFLATE_CHK_SEQUENCE0; |
397 | for (;;) { |
398 | res = ccp_test(f->unit, p, CILEN_DEFLATE4, 0); |
399 | if (res > 0) { |
400 | p += CILEN_DEFLATE4; |
401 | break; |
402 | } |
403 | if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE8) { |
404 | go->deflate = 0; |
405 | break; |
406 | } |
407 | --go->deflate_size; |
408 | p[2] = DEFLATE_MAKE_OPT(go->deflate_size)((((go->deflate_size) - 8) << 4) + 8); |
409 | } |
410 | if (p != p0 && go->deflate_correct && go->deflate_draft) { |
411 | p[0] = CI_DEFLATE_DRAFT24; |
412 | p[1] = CILEN_DEFLATE4; |
413 | p[2] = p[2 - CILEN_DEFLATE4]; |
414 | p[3] = DEFLATE_CHK_SEQUENCE0; |
415 | p += CILEN_DEFLATE4; |
416 | } |
417 | } |
418 | if (go->bsd_compress) { |
419 | p[0] = CI_BSD_COMPRESS21; |
420 | p[1] = CILEN_BSD_COMPRESS3; |
421 | p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)(((1) << 5) | (go->bsd_bits)); |
422 | if (p != p0) { |
423 | p += CILEN_BSD_COMPRESS3; /* not the first option */ |
424 | } else { |
425 | for (;;) { |
426 | res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS3, 0); |
427 | if (res > 0) { |
428 | p += CILEN_BSD_COMPRESS3; |
429 | break; |
430 | } |
431 | if (res < 0 || go->bsd_bits <= BSD_MIN_BITS9) { |
432 | go->bsd_compress = 0; |
433 | break; |
434 | } |
435 | --go->bsd_bits; |
436 | p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)(((1) << 5) | (go->bsd_bits)); |
437 | } |
438 | } |
439 | } |
440 | /* XXX Should Predictor 2 be preferable to Predictor 1? */ |
441 | if (go->predictor_1) { |
442 | p[0] = CI_PREDICTOR_11; |
443 | p[1] = CILEN_PREDICTOR_12; |
444 | if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_12, 0) <= 0) { |
445 | go->predictor_1 = 0; |
446 | } else { |
447 | p += CILEN_PREDICTOR_12; |
448 | } |
449 | } |
450 | if (go->predictor_2) { |
451 | p[0] = CI_PREDICTOR_22; |
452 | p[1] = CILEN_PREDICTOR_22; |
453 | if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_22, 0) <= 0) { |
454 | go->predictor_2 = 0; |
455 | } else { |
456 | p += CILEN_PREDICTOR_22; |
457 | } |
458 | } |
459 | |
460 | go->method = (p > p0)? p0[0]: -1; |
461 | |
462 | *lenp = p - p0; |
463 | } |
464 | |
465 | /* |
466 | * ccp_ackci - process a received configure-ack, and return |
467 | * 1 iff the packet was OK. |
468 | */ |
469 | static int |
470 | ccp_ackci(f, p, len) |
471 | fsm *f; |
472 | u_char *p; |
473 | int len; |
474 | { |
475 | ccp_options *go = &ccp_gotoptions[f->unit]; |
476 | u_char *p0 = p; |
477 | |
478 | if (go->deflate) { |
479 | if (len < CILEN_DEFLATE4 |
480 | || p[0] != (go->deflate_correct? CI_DEFLATE26: CI_DEFLATE_DRAFT24) |
481 | || p[1] != CILEN_DEFLATE4 |
482 | || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)((((go->deflate_size) - 8) << 4) + 8) |
483 | || p[3] != DEFLATE_CHK_SEQUENCE0) |
484 | return 0; |
485 | p += CILEN_DEFLATE4; |
486 | len -= CILEN_DEFLATE4; |
487 | /* XXX Cope with first/fast ack */ |
488 | if (len == 0) |
489 | return 1; |
490 | if (go->deflate_correct && go->deflate_draft) { |
491 | if (len < CILEN_DEFLATE4 |
492 | || p[0] != CI_DEFLATE_DRAFT24 |
493 | || p[1] != CILEN_DEFLATE4 |
494 | || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)((((go->deflate_size) - 8) << 4) + 8) |
495 | || p[3] != DEFLATE_CHK_SEQUENCE0) |
496 | return 0; |
497 | p += CILEN_DEFLATE4; |
498 | len -= CILEN_DEFLATE4; |
499 | } |
500 | } |
501 | if (go->bsd_compress) { |
502 | if (len < CILEN_BSD_COMPRESS3 |
503 | || p[0] != CI_BSD_COMPRESS21 || p[1] != CILEN_BSD_COMPRESS3 |
504 | || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)(((1) << 5) | (go->bsd_bits))) |
505 | return 0; |
506 | p += CILEN_BSD_COMPRESS3; |
507 | len -= CILEN_BSD_COMPRESS3; |
508 | /* XXX Cope with first/fast ack */ |
509 | if (p == p0 && len == 0) |
510 | return 1; |
511 | } |
512 | if (go->predictor_1) { |
513 | if (len < CILEN_PREDICTOR_12 |
514 | || p[0] != CI_PREDICTOR_11 || p[1] != CILEN_PREDICTOR_12) |
515 | return 0; |
516 | p += CILEN_PREDICTOR_12; |
517 | len -= CILEN_PREDICTOR_12; |
518 | /* XXX Cope with first/fast ack */ |
519 | if (p == p0 && len == 0) |
520 | return 1; |
521 | } |
522 | if (go->predictor_2) { |
523 | if (len < CILEN_PREDICTOR_22 |
524 | || p[0] != CI_PREDICTOR_22 || p[1] != CILEN_PREDICTOR_22) |
525 | return 0; |
526 | p += CILEN_PREDICTOR_22; |
527 | len -= CILEN_PREDICTOR_22; |
528 | /* XXX Cope with first/fast ack */ |
529 | if (p == p0 && len == 0) |
530 | return 1; |
531 | } |
532 | |
533 | if (len != 0) |
534 | return 0; |
535 | return 1; |
536 | } |
537 | |
538 | /* |
539 | * ccp_nakci - process received configure-nak. |
540 | * Returns 1 iff the nak was OK. |
541 | */ |
542 | static int |
543 | ccp_nakci(f, p, len) |
544 | fsm *f; |
545 | u_char *p; |
546 | int len; |
547 | { |
548 | ccp_options *go = &ccp_gotoptions[f->unit]; |
549 | ccp_options no; /* options we've seen already */ |
550 | ccp_options try; /* options to ask for next time */ |
551 | |
552 | memset(&no, 0, sizeof(no)); |
553 | try = *go; |
554 | |
555 | if (go->deflate && len >= CILEN_DEFLATE4 |
556 | && p[0] == (go->deflate_correct? CI_DEFLATE26: CI_DEFLATE_DRAFT24) |
557 | && p[1] == CILEN_DEFLATE4) { |
558 | no.deflate = 1; |
559 | /* |
560 | * Peer wants us to use a different code size or something. |
561 | * Stop asking for Deflate if we don't understand his suggestion. |
562 | */ |
563 | if (DEFLATE_METHOD(p[2])((p[2]) & 0x0F) != DEFLATE_METHOD_VAL8 |
564 | || DEFLATE_SIZE(p[2])(((p[2]) >> 4) + 8) < DEFLATE_MIN_SIZE8 |
565 | || p[3] != DEFLATE_CHK_SEQUENCE0) |
566 | try.deflate = 0; |
567 | else if (DEFLATE_SIZE(p[2])(((p[2]) >> 4) + 8) < go->deflate_size) |
568 | try.deflate_size = DEFLATE_SIZE(p[2])(((p[2]) >> 4) + 8); |
569 | p += CILEN_DEFLATE4; |
570 | len -= CILEN_DEFLATE4; |
571 | if (go->deflate_correct && go->deflate_draft |
572 | && len >= CILEN_DEFLATE4 && p[0] == CI_DEFLATE_DRAFT24 |
573 | && p[1] == CILEN_DEFLATE4) { |
574 | p += CILEN_DEFLATE4; |
575 | len -= CILEN_DEFLATE4; |
576 | } |
577 | } |
578 | |
579 | if (go->bsd_compress && len >= CILEN_BSD_COMPRESS3 |
580 | && p[0] == CI_BSD_COMPRESS21 && p[1] == CILEN_BSD_COMPRESS3) { |
581 | no.bsd_compress = 1; |
582 | /* |
583 | * Peer wants us to use a different number of bits |
584 | * or a different version. |
585 | */ |
586 | if (BSD_VERSION(p[2])((p[2]) >> 5) != BSD_CURRENT_VERSION1) |
587 | try.bsd_compress = 0; |
588 | else if (BSD_NBITS(p[2])((p[2]) & 0x1F) < go->bsd_bits) |
589 | try.bsd_bits = BSD_NBITS(p[2])((p[2]) & 0x1F); |
590 | p += CILEN_BSD_COMPRESS3; |
591 | len -= CILEN_BSD_COMPRESS3; |
592 | } |
593 | |
594 | /* |
595 | * Predictor-1 and 2 have no options, so they can't be Naked. |
596 | * |
597 | * XXX What should we do with any remaining options? |
598 | */ |
599 | |
600 | if (len != 0) |
601 | return 0; |
602 | |
603 | if (f->state != OPENED9) |
604 | *go = try; |
605 | return 1; |
606 | } |
607 | |
608 | /* |
609 | * ccp_rejci - reject some of our suggested compression methods. |
610 | */ |
611 | static int |
612 | ccp_rejci(f, p, len) |
613 | fsm *f; |
614 | u_char *p; |
615 | int len; |
616 | { |
617 | ccp_options *go = &ccp_gotoptions[f->unit]; |
618 | ccp_options try; /* options to request next time */ |
619 | |
620 | try = *go; |
621 | |
622 | /* |
623 | * Cope with empty configure-rejects by ceasing to send |
624 | * configure-requests. |
625 | */ |
626 | if (len == 0 && all_rejected[f->unit]) |
627 | return -1; |
628 | |
629 | if (go->deflate && len >= CILEN_DEFLATE4 |
630 | && p[0] == (go->deflate_correct? CI_DEFLATE26: CI_DEFLATE_DRAFT24) |
631 | && p[1] == CILEN_DEFLATE4) { |
632 | if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)((((go->deflate_size) - 8) << 4) + 8) |
633 | || p[3] != DEFLATE_CHK_SEQUENCE0) |
634 | return 0; /* Rej is bad */ |
635 | if (go->deflate_correct) |
636 | try.deflate_correct = 0; |
637 | else |
638 | try.deflate_draft = 0; |
639 | p += CILEN_DEFLATE4; |
640 | len -= CILEN_DEFLATE4; |
641 | if (go->deflate_correct && go->deflate_draft |
642 | && len >= CILEN_DEFLATE4 && p[0] == CI_DEFLATE_DRAFT24 |
643 | && p[1] == CILEN_DEFLATE4) { |
644 | if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)((((go->deflate_size) - 8) << 4) + 8) |
645 | || p[3] != DEFLATE_CHK_SEQUENCE0) |
646 | return 0; /* Rej is bad */ |
647 | try.deflate_draft = 0; |
648 | p += CILEN_DEFLATE4; |
649 | len -= CILEN_DEFLATE4; |
650 | } |
651 | if (!try.deflate_correct && !try.deflate_draft) |
652 | try.deflate = 0; |
653 | } |
654 | if (go->bsd_compress && len >= CILEN_BSD_COMPRESS3 |
655 | && p[0] == CI_BSD_COMPRESS21 && p[1] == CILEN_BSD_COMPRESS3) { |
656 | if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)(((1) << 5) | (go->bsd_bits))) |
657 | return 0; |
658 | try.bsd_compress = 0; |
659 | p += CILEN_BSD_COMPRESS3; |
660 | len -= CILEN_BSD_COMPRESS3; |
661 | } |
662 | if (go->predictor_1 && len >= CILEN_PREDICTOR_12 |
663 | && p[0] == CI_PREDICTOR_11 && p[1] == CILEN_PREDICTOR_12) { |
664 | try.predictor_1 = 0; |
665 | p += CILEN_PREDICTOR_12; |
666 | len -= CILEN_PREDICTOR_12; |
667 | } |
668 | if (go->predictor_2 && len >= CILEN_PREDICTOR_22 |
669 | && p[0] == CI_PREDICTOR_22 && p[1] == CILEN_PREDICTOR_22) { |
670 | try.predictor_2 = 0; |
671 | p += CILEN_PREDICTOR_22; |
Value stored to 'p' is never read | |
672 | len -= CILEN_PREDICTOR_22; |
673 | } |
674 | |
675 | if (len != 0) |
676 | return 0; |
677 | |
678 | if (f->state != OPENED9) |
679 | *go = try; |
680 | |
681 | return 1; |
682 | } |
683 | |
684 | /* |
685 | * ccp_reqci - processed a received configure-request. |
686 | * Returns CONFACK, CONFNAK or CONFREJ and the packet modified |
687 | * appropriately. |
688 | */ |
689 | static int |
690 | ccp_reqci(f, p, lenp, dont_nak) |
691 | fsm *f; |
692 | u_char *p; |
693 | int *lenp; |
694 | int dont_nak; |
695 | { |
696 | int ret, newret, res; |
697 | u_char *p0, *retp; |
698 | int len, clen, type, nb; |
699 | ccp_options *ho = &ccp_hisoptions[f->unit]; |
700 | ccp_options *ao = &ccp_allowoptions[f->unit]; |
701 | |
702 | ret = CONFACK2; |
703 | retp = p0 = p; |
704 | len = *lenp; |
705 | |
706 | memset(ho, 0, sizeof(ccp_options)); |
707 | ho->method = (len > 0)? p[0]: -1; |
708 | |
709 | while (len > 0) { |
710 | newret = CONFACK2; |
711 | if (len < 2 || p[1] < 2 || p[1] > len) { |
712 | /* length is bad */ |
713 | clen = len; |
714 | newret = CONFREJ4; |
715 | |
716 | } else { |
717 | type = p[0]; |
718 | clen = p[1]; |
719 | |
720 | switch (type) { |
721 | case CI_DEFLATE26: |
722 | case CI_DEFLATE_DRAFT24: |
723 | if (!ao->deflate || clen != CILEN_DEFLATE4 |
724 | || (!ao->deflate_correct && type == CI_DEFLATE26) |
725 | || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT24)) { |
726 | newret = CONFREJ4; |
727 | break; |
728 | } |
729 | |
730 | ho->deflate = 1; |
731 | ho->deflate_size = nb = DEFLATE_SIZE(p[2])(((p[2]) >> 4) + 8); |
732 | if (DEFLATE_METHOD(p[2])((p[2]) & 0x0F) != DEFLATE_METHOD_VAL8 |
733 | || p[3] != DEFLATE_CHK_SEQUENCE0 |
734 | || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE8) { |
735 | newret = CONFNAK3; |
736 | if (!dont_nak) { |
737 | p[2] = DEFLATE_MAKE_OPT(ao->deflate_size)((((ao->deflate_size) - 8) << 4) + 8); |
738 | p[3] = DEFLATE_CHK_SEQUENCE0; |
739 | /* fall through to test this #bits below */ |
740 | } else |
741 | break; |
742 | } |
743 | |
744 | /* |
745 | * Check whether we can do Deflate with the window |
746 | * size they want. If the window is too big, reduce |
747 | * it until the kernel can cope and nak with that. |
748 | * We only check this for the first option. |
749 | */ |
750 | if (p == p0) { |
751 | for (;;) { |
752 | res = ccp_test(f->unit, p, CILEN_DEFLATE4, 1); |
753 | if (res > 0) |
754 | break; /* it's OK now */ |
755 | if (res < 0 || nb == DEFLATE_MIN_SIZE8 || dont_nak) { |
756 | newret = CONFREJ4; |
757 | p[2] = DEFLATE_MAKE_OPT(ho->deflate_size)((((ho->deflate_size) - 8) << 4) + 8); |
758 | break; |
759 | } |
760 | newret = CONFNAK3; |
761 | --nb; |
762 | p[2] = DEFLATE_MAKE_OPT(nb)((((nb) - 8) << 4) + 8); |
763 | } |
764 | } |
765 | break; |
766 | |
767 | case CI_BSD_COMPRESS21: |
768 | if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS3) { |
769 | newret = CONFREJ4; |
770 | break; |
771 | } |
772 | |
773 | ho->bsd_compress = 1; |
774 | ho->bsd_bits = nb = BSD_NBITS(p[2])((p[2]) & 0x1F); |
775 | if (BSD_VERSION(p[2])((p[2]) >> 5) != BSD_CURRENT_VERSION1 |
776 | || nb > ao->bsd_bits || nb < BSD_MIN_BITS9) { |
777 | newret = CONFNAK3; |
778 | if (!dont_nak) { |
779 | p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits)(((1) << 5) | (ao->bsd_bits)); |
780 | /* fall through to test this #bits below */ |
781 | } else |
782 | break; |
783 | } |
784 | |
785 | /* |
786 | * Check whether we can do BSD-Compress with the code |
787 | * size they want. If the code size is too big, reduce |
788 | * it until the kernel can cope and nak with that. |
789 | * We only check this for the first option. |
790 | */ |
791 | if (p == p0) { |
792 | for (;;) { |
793 | res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS3, 1); |
794 | if (res > 0) |
795 | break; |
796 | if (res < 0 || nb == BSD_MIN_BITS9 || dont_nak) { |
797 | newret = CONFREJ4; |
798 | p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,(((1) << 5) | (ho->bsd_bits)) |
799 | ho->bsd_bits)(((1) << 5) | (ho->bsd_bits)); |
800 | break; |
801 | } |
802 | newret = CONFNAK3; |
803 | --nb; |
804 | p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb)(((1) << 5) | (nb)); |
805 | } |
806 | } |
807 | break; |
808 | |
809 | case CI_PREDICTOR_11: |
810 | if (!ao->predictor_1 || clen != CILEN_PREDICTOR_12) { |
811 | newret = CONFREJ4; |
812 | break; |
813 | } |
814 | |
815 | ho->predictor_1 = 1; |
816 | if (p == p0 |
817 | && ccp_test(f->unit, p, CILEN_PREDICTOR_12, 1) <= 0) { |
818 | newret = CONFREJ4; |
819 | } |
820 | break; |
821 | |
822 | case CI_PREDICTOR_22: |
823 | if (!ao->predictor_2 || clen != CILEN_PREDICTOR_22) { |
824 | newret = CONFREJ4; |
825 | break; |
826 | } |
827 | |
828 | ho->predictor_2 = 1; |
829 | if (p == p0 |
830 | && ccp_test(f->unit, p, CILEN_PREDICTOR_22, 1) <= 0) { |
831 | newret = CONFREJ4; |
832 | } |
833 | break; |
834 | |
835 | default: |
836 | newret = CONFREJ4; |
837 | } |
838 | } |
839 | |
840 | if (newret == CONFNAK3 && dont_nak) |
841 | newret = CONFREJ4; |
842 | if (!(newret == CONFACK2 || (newret == CONFNAK3 && ret == CONFREJ4))) { |
843 | /* we're returning this option */ |
844 | if (newret == CONFREJ4 && ret == CONFNAK3) |
845 | retp = p0; |
846 | ret = newret; |
847 | if (p != retp) |
848 | BCOPY(p, retp, clen)memcpy(retp, p, clen); |
849 | retp += clen; |
850 | } |
851 | |
852 | p += clen; |
853 | len -= clen; |
854 | } |
855 | |
856 | if (ret != CONFACK2) { |
857 | if (ret == CONFREJ4 && *lenp == retp - p0) |
858 | all_rejected[f->unit] = 1; |
859 | else |
860 | *lenp = retp - p0; |
861 | } |
862 | return ret; |
863 | } |
864 | |
865 | /* |
866 | * Make a string name for a compression method (or 2). |
867 | */ |
868 | static char * |
869 | method_name(opt, opt2) |
870 | ccp_options *opt, *opt2; |
871 | { |
872 | static char result[64]; |
873 | |
874 | if (!ANY_COMPRESS(*opt)((*opt).deflate || (*opt).bsd_compress || (*opt).predictor_1 || (*opt).predictor_2)) |
875 | return "(none)"; |
876 | switch (opt->method) { |
877 | case CI_DEFLATE26: |
878 | case CI_DEFLATE_DRAFT24: |
879 | if (opt2 != NULL((void *)0) && opt2->deflate_size != opt->deflate_size) |
880 | snprintf(result, sizeof result, "Deflate%s (%d/%d)", |
881 | (opt->method == CI_DEFLATE_DRAFT24? "(old#)": ""), |
882 | opt->deflate_size, opt2->deflate_size); |
883 | else |
884 | snprintf(result, sizeof result, "Deflate%s (%d)", |
885 | (opt->method == CI_DEFLATE_DRAFT24? "(old#)": ""), |
886 | opt->deflate_size); |
887 | break; |
888 | case CI_BSD_COMPRESS21: |
889 | if (opt2 != NULL((void *)0) && opt2->bsd_bits != opt->bsd_bits) |
890 | snprintf(result, sizeof result, |
891 | "BSD-Compress (%d/%d)", opt->bsd_bits, |
892 | opt2->bsd_bits); |
893 | else |
894 | snprintf(result, sizeof result, "BSD-Compress (%d)", opt->bsd_bits); |
895 | break; |
896 | case CI_PREDICTOR_11: |
897 | return "Predictor 1"; |
898 | case CI_PREDICTOR_22: |
899 | return "Predictor 2"; |
900 | default: |
901 | snprintf(result, sizeof result, "Method %d", opt->method); |
902 | } |
903 | return result; |
904 | } |
905 | |
906 | /* |
907 | * CCP has come up - inform the kernel driver and log a message. |
908 | */ |
909 | static void |
910 | ccp_up(f) |
911 | fsm *f; |
912 | { |
913 | ccp_options *go = &ccp_gotoptions[f->unit]; |
914 | ccp_options *ho = &ccp_hisoptions[f->unit]; |
915 | char method1[64]; |
916 | |
917 | ccp_flags_set(f->unit, 1, 1); |
918 | if (ANY_COMPRESS(*go)((*go).deflate || (*go).bsd_compress || (*go).predictor_1 || ( *go).predictor_2)) { |
919 | if (ANY_COMPRESS(*ho)((*ho).deflate || (*ho).bsd_compress || (*ho).predictor_1 || ( *ho).predictor_2)) { |
920 | if (go->method == ho->method) { |
921 | syslog(LOG_NOTICE5, "%s compression enabled", |
922 | method_name(go, ho)); |
923 | } else { |
924 | strncpy(method1, method_name(go, NULL((void *)0)), sizeof method1); |
925 | syslog(LOG_NOTICE5, "%s / %s compression enabled", |
926 | method1, method_name(ho, NULL((void *)0))); |
927 | } |
928 | } else |
929 | syslog(LOG_NOTICE5, "%s receive compression enabled", |
930 | method_name(go, NULL((void *)0))); |
931 | } else if (ANY_COMPRESS(*ho)((*ho).deflate || (*ho).bsd_compress || (*ho).predictor_1 || ( *ho).predictor_2)) |
932 | syslog(LOG_NOTICE5, "%s transmit compression enabled", |
933 | method_name(ho, NULL((void *)0))); |
934 | } |
935 | |
936 | /* |
937 | * CCP has gone down - inform the kernel driver. |
938 | */ |
939 | static void |
940 | ccp_down(f) |
941 | fsm *f; |
942 | { |
943 | if (ccp_localstate[f->unit] & RACK_PENDING1) |
944 | UNTIMEOUT(ccp_rack_timeout, f)untimeout((ccp_rack_timeout), (f)); |
945 | ccp_localstate[f->unit] = 0; |
946 | ccp_flags_set(f->unit, 1, 0); |
947 | } |
948 | |
949 | /* |
950 | * Print the contents of a CCP packet. |
951 | */ |
952 | static char *ccp_codenames[] = { |
953 | "ConfReq", "ConfAck", "ConfNak", "ConfRej", |
954 | "TermReq", "TermAck", "CodeRej", |
955 | NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0), |
956 | "ResetReq", "ResetAck", |
957 | }; |
958 | |
959 | static int |
960 | ccp_printpkt(p, plen, printer, arg) |
961 | u_char *p; |
962 | int plen; |
963 | void (*printer)(void *, char *, ...); |
964 | void *arg; |
965 | { |
966 | u_char *p0, *optend; |
967 | int code, id, len; |
968 | int optlen; |
969 | |
970 | p0 = p; |
971 | if (plen < HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))) |
972 | return 0; |
973 | code = p[0]; |
974 | id = p[1]; |
975 | len = (p[2] << 8) + p[3]; |
976 | if (len < HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) || len > plen) |
977 | return 0; |
978 | |
979 | if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *) |
980 | && ccp_codenames[code-1] != NULL((void *)0)) |
981 | printer(arg, " %s", ccp_codenames[code-1]); |
982 | else |
983 | printer(arg, " code=0x%x", code); |
984 | printer(arg, " id=0x%x", id); |
985 | len -= HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); |
986 | p += HEADERLEN(sizeof (u_char) + sizeof (u_char) + sizeof (u_short)); |
987 | |
988 | switch (code) { |
989 | case CONFREQ1: |
990 | case CONFACK2: |
991 | case CONFNAK3: |
992 | case CONFREJ4: |
993 | /* print list of possible compression methods */ |
994 | while (len >= 2) { |
995 | code = p[0]; |
996 | optlen = p[1]; |
997 | if (optlen < 2 || optlen > len) |
998 | break; |
999 | printer(arg, " <"); |
1000 | len -= optlen; |
1001 | optend = p + optlen; |
1002 | switch (code) { |
1003 | case CI_DEFLATE26: |
1004 | case CI_DEFLATE_DRAFT24: |
1005 | if (optlen >= CILEN_DEFLATE4) { |
1006 | printer(arg, "deflate%s %d", |
1007 | (code == CI_DEFLATE_DRAFT24? "(old#)": ""), |
1008 | DEFLATE_SIZE(p[2])(((p[2]) >> 4) + 8)); |
1009 | if (DEFLATE_METHOD(p[2])((p[2]) & 0x0F) != DEFLATE_METHOD_VAL8) |
1010 | printer(arg, " method %d", DEFLATE_METHOD(p[2])((p[2]) & 0x0F)); |
1011 | if (p[3] != DEFLATE_CHK_SEQUENCE0) |
1012 | printer(arg, " check %d", p[3]); |
1013 | p += CILEN_DEFLATE4; |
1014 | } |
1015 | break; |
1016 | case CI_BSD_COMPRESS21: |
1017 | if (optlen >= CILEN_BSD_COMPRESS3) { |
1018 | printer(arg, "bsd v%d %d", BSD_VERSION(p[2])((p[2]) >> 5), |
1019 | BSD_NBITS(p[2])((p[2]) & 0x1F)); |
1020 | p += CILEN_BSD_COMPRESS3; |
1021 | } |
1022 | break; |
1023 | case CI_PREDICTOR_11: |
1024 | if (optlen >= CILEN_PREDICTOR_12) { |
1025 | printer(arg, "predictor 1"); |
1026 | p += CILEN_PREDICTOR_12; |
1027 | } |
1028 | break; |
1029 | case CI_PREDICTOR_22: |
1030 | if (optlen >= CILEN_PREDICTOR_22) { |
1031 | printer(arg, "predictor 2"); |
1032 | p += CILEN_PREDICTOR_22; |
1033 | } |
1034 | break; |
1035 | } |
1036 | while (p < optend) |
1037 | printer(arg, " %.2x", *p++); |
1038 | printer(arg, ">"); |
1039 | } |
1040 | break; |
1041 | |
1042 | case TERMACK6: |
1043 | case TERMREQ5: |
1044 | if (len > 0 && *p >= ' ' && *p < 0x7f) { |
1045 | print_string(p, len, printer, arg); |
1046 | p += len; |
1047 | len = 0; |
1048 | } |
1049 | break; |
1050 | } |
1051 | |
1052 | /* dump out the rest of the packet in hex */ |
1053 | while (--len >= 0) |
1054 | printer(arg, " %.2x", *p++); |
1055 | |
1056 | return p - p0; |
1057 | } |
1058 | |
1059 | /* |
1060 | * We have received a packet that the decompressor failed to |
1061 | * decompress. Here we would expect to issue a reset-request, but |
1062 | * Motorola has a patent on resetting the compressor as a result of |
1063 | * detecting an error in the decompressed data after decompression. |
1064 | * (See US patent 5,130,993; international patent publication number |
1065 | * WO 91/10289; Australian patent 73296/91.) |
1066 | * |
1067 | * So we ask the kernel whether the error was detected after |
1068 | * decompression; if it was, we take CCP down, thus disabling |
1069 | * compression :-(, otherwise we issue the reset-request. |
1070 | */ |
1071 | static void |
1072 | ccp_datainput(unit, pkt, len) |
1073 | int unit; |
1074 | u_char *pkt; |
1075 | int len; |
1076 | { |
1077 | fsm *f; |
1078 | |
1079 | f = &ccp_fsm[unit]; |
1080 | if (f->state == OPENED9) { |
1081 | if (ccp_fatal_error(unit)) { |
1082 | /* |
1083 | * Disable compression by taking CCP down. |
1084 | */ |
1085 | syslog(LOG_ERR3, "Lost compression sync: disabling compression"); |
1086 | ccp_close(unit, "Lost compression sync"); |
1087 | } else { |
1088 | /* |
1089 | * Send a reset-request to reset the peer's compressor. |
1090 | * We don't do that if we are still waiting for an |
1091 | * acknowledgement to a previous reset-request. |
1092 | */ |
1093 | if (!(ccp_localstate[f->unit] & RACK_PENDING1)) { |
1094 | fsm_sdata(f, CCP_RESETREQ14, f->reqid = ++f->id, NULL((void *)0), 0); |
1095 | TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT)timeout((ccp_rack_timeout), (f), (1)); |
1096 | ccp_localstate[f->unit] |= RACK_PENDING1; |
1097 | } else |
1098 | ccp_localstate[f->unit] |= RREQ_REPEAT2; |
1099 | } |
1100 | } |
1101 | } |
1102 | |
1103 | /* |
1104 | * Timeout waiting for reset-ack. |
1105 | */ |
1106 | static void |
1107 | ccp_rack_timeout(arg) |
1108 | void *arg; |
1109 | { |
1110 | fsm *f = arg; |
1111 | |
1112 | if (f->state == OPENED9 && ccp_localstate[f->unit] & RREQ_REPEAT2) { |
1113 | fsm_sdata(f, CCP_RESETREQ14, f->reqid, NULL((void *)0), 0); |
1114 | TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT)timeout((ccp_rack_timeout), (f), (1)); |
1115 | ccp_localstate[f->unit] &= ~RREQ_REPEAT2; |
1116 | } else |
1117 | ccp_localstate[f->unit] &= ~RACK_PENDING1; |
1118 | } |
1119 |