00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #include "lwip/opt.h"
00055
00056 #if PPP_SUPPORT
00057
00058 #include "ppp.h"
00059 #include "pppdebug.h"
00060
00061 #include "fsm.h"
00062 #include "chap.h"
00063 #include "magic.h"
00064 #include "auth.h"
00065 #include "lcp.h"
00066
00067 #include <string.h>
00068
00069 #if PPPOE_SUPPORT
00070 #include "netif/ppp_oe.h"
00071 #else
00072 #define PPPOE_MAXMTU PPP_MAXMRU
00073 #endif
00074
00075
00076
00077
00078
00079
00080
00081
00082 #define CILEN_VOID 2
00083 #define CILEN_CHAR 3
00084 #define CILEN_SHORT 4
00085 #define CILEN_CHAP 5
00086 #define CILEN_LONG 6
00087 #define CILEN_LQR 8
00088 #define CILEN_CBCP 3
00089
00090
00091
00092
00093
00094
00095
00096
00097 static void lcp_resetci (fsm*);
00098 static int lcp_cilen (fsm*);
00099 static void lcp_addci (fsm*, u_char*, int*);
00100 static int lcp_ackci (fsm*, u_char*, int);
00101 static int lcp_nakci (fsm*, u_char*, int);
00102 static int lcp_rejci (fsm*, u_char*, int);
00103 static int lcp_reqci (fsm*, u_char*, int*, int);
00104 static void lcp_up (fsm*);
00105 static void lcp_down (fsm*);
00106 static void lcp_starting (fsm*);
00107 static void lcp_finished (fsm*);
00108 static int lcp_extcode (fsm*, int, u_char, u_char*, int);
00109
00110 static void lcp_rprotrej (fsm*, u_char*, int);
00111
00112
00113
00114
00115 static void lcp_echo_lowerup (int);
00116 static void lcp_echo_lowerdown (int);
00117 static void LcpEchoTimeout (void*);
00118 static void lcp_received_echo_reply (fsm*, int, u_char*, int);
00119 static void LcpSendEchoRequest (fsm*);
00120 static void LcpLinkFailure (fsm*);
00121 static void LcpEchoCheck (fsm*);
00122
00123
00124
00125
00126
00127 static void lcp_input (int, u_char *, int);
00128 static void lcp_protrej (int);
00129
00130 #define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ")
00131
00132
00133
00134
00135
00136
00137 LinkPhase lcp_phase[NUM_PPP];
00138 lcp_options lcp_wantoptions[NUM_PPP];
00139 lcp_options lcp_gotoptions[NUM_PPP];
00140 lcp_options lcp_allowoptions[NUM_PPP];
00141 lcp_options lcp_hisoptions[NUM_PPP];
00142 ext_accm xmit_accm[NUM_PPP];
00143
00144
00145
00146
00147
00148
00149 static fsm lcp_fsm[NUM_PPP];
00150 static u_int lcp_echo_interval = LCP_ECHOINTERVAL;
00151 static u_int lcp_echo_fails = LCP_MAXECHOFAILS;
00152 static u32_t lcp_echos_pending = 0;
00153 static u32_t lcp_echo_number = 0;
00154 static u32_t lcp_echo_timer_running = 0;
00155
00156 static u_char nak_buffer[PPP_MRU];
00157
00158 static fsm_callbacks lcp_callbacks = {
00159 lcp_resetci,
00160 lcp_cilen,
00161 lcp_addci,
00162 lcp_ackci,
00163 lcp_nakci,
00164 lcp_rejci,
00165 lcp_reqci,
00166 lcp_up,
00167 lcp_down,
00168 lcp_starting,
00169 lcp_finished,
00170 NULL,
00171 NULL,
00172 lcp_extcode,
00173 "LCP"
00174 };
00175
00176 struct protent lcp_protent = {
00177 PPP_LCP,
00178 lcp_init,
00179 lcp_input,
00180 lcp_protrej,
00181 lcp_lowerup,
00182 lcp_lowerdown,
00183 lcp_open,
00184 lcp_close,
00185 #if 0
00186 lcp_printpkt,
00187 NULL,
00188 #endif
00189 1,
00190 "LCP",
00191 #if 0
00192 NULL,
00193 NULL,
00194 NULL
00195 #endif
00196 };
00197
00198 int lcp_loopbackfail = DEFLOOPBACKFAIL;
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 void
00209 lcp_init(int unit)
00210 {
00211 fsm *f = &lcp_fsm[unit];
00212 lcp_options *wo = &lcp_wantoptions[unit];
00213 lcp_options *ao = &lcp_allowoptions[unit];
00214
00215 f->unit = unit;
00216 f->protocol = PPP_LCP;
00217 f->callbacks = &lcp_callbacks;
00218
00219 fsm_init(f);
00220
00221 wo->passive = 0;
00222 wo->silent = 0;
00223 wo->restart = 0;
00224 wo->neg_mru = 1;
00225 wo->mru = PPP_DEFMRU;
00226 wo->neg_asyncmap = 1;
00227 wo->asyncmap = 0x00000000l;
00228 wo->neg_chap = 0;
00229 wo->neg_upap = 0;
00230 wo->chap_mdtype = CHAP_DIGEST_MD5;
00231 wo->neg_magicnumber = 1;
00232 wo->neg_pcompression = 1;
00233 wo->neg_accompression = 1;
00234 wo->neg_lqr = 0;
00235 wo->neg_cbcp = 0;
00236
00237 ao->neg_mru = 1;
00238 ao->mru = PPP_MAXMRU;
00239 ao->neg_asyncmap = 1;
00240 ao->asyncmap = 0x00000000l;
00241 ao->neg_chap = (CHAP_SUPPORT != 0);
00242 ao->chap_mdtype = CHAP_DIGEST_MD5;
00243 ao->neg_upap = (PAP_SUPPORT != 0);
00244 ao->neg_magicnumber = 1;
00245 ao->neg_pcompression = 1;
00246 ao->neg_accompression = 1;
00247 ao->neg_lqr = 0;
00248 ao->neg_cbcp = (CBCP_SUPPORT != 0);
00249
00250
00251
00252
00253
00254 memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
00255 xmit_accm[unit][15] = 0x60;
00256 xmit_accm[unit][0] = (u_char)((ao->asyncmap & 0xFF));
00257 xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF);
00258 xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF);
00259 xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF);
00260 LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n",
00261 xmit_accm[unit][0],
00262 xmit_accm[unit][1],
00263 xmit_accm[unit][2],
00264 xmit_accm[unit][3]));
00265
00266 lcp_phase[unit] = PHASE_INITIALIZE;
00267 }
00268
00269
00270
00271
00272
00273 void
00274 lcp_open(int unit)
00275 {
00276 fsm *f = &lcp_fsm[unit];
00277 lcp_options *wo = &lcp_wantoptions[unit];
00278
00279 f->flags = 0;
00280 if (wo->passive) {
00281 f->flags |= OPT_PASSIVE;
00282 }
00283 if (wo->silent) {
00284 f->flags |= OPT_SILENT;
00285 }
00286 fsm_open(f);
00287
00288 lcp_phase[unit] = PHASE_ESTABLISH;
00289 }
00290
00291
00292
00293
00294
00295 void
00296 lcp_close(int unit, char *reason)
00297 {
00298 fsm *f = &lcp_fsm[unit];
00299
00300 if (lcp_phase[unit] != PHASE_DEAD) {
00301 lcp_phase[unit] = PHASE_TERMINATE;
00302 }
00303 if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
00304
00305
00306
00307
00308
00309
00310 f->state = LS_CLOSED;
00311 lcp_finished(f);
00312 } else {
00313 fsm_close(&lcp_fsm[unit], reason);
00314 }
00315 }
00316
00317
00318
00319
00320
00321 void
00322 lcp_lowerup(int unit)
00323 {
00324 lcp_options *wo = &lcp_wantoptions[unit];
00325
00326
00327
00328
00329
00330
00331 ppp_set_xaccm(unit, &xmit_accm[unit]);
00332 ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);
00333 ppp_recv_config(unit, PPP_MRU, 0x00000000l,
00334 wo->neg_pcompression, wo->neg_accompression);
00335 peer_mru[unit] = PPP_MRU;
00336 lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0]
00337 | ((u_long)xmit_accm[unit][1] << 8)
00338 | ((u_long)xmit_accm[unit][2] << 16)
00339 | ((u_long)xmit_accm[unit][3] << 24);
00340 LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n",
00341 xmit_accm[unit][3],
00342 xmit_accm[unit][2],
00343 xmit_accm[unit][1],
00344 xmit_accm[unit][0]));
00345
00346 fsm_lowerup(&lcp_fsm[unit]);
00347 }
00348
00349
00350
00351
00352
00353 void
00354 lcp_lowerdown(int unit)
00355 {
00356 fsm_lowerdown(&lcp_fsm[unit]);
00357 }
00358
00359
00360
00361
00362 void
00363 lcp_sprotrej(int unit, u_char *p, int len)
00364 {
00365
00366
00367
00368
00369
00370 fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len);
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 static void
00382 lcp_input(int unit, u_char *p, int len)
00383 {
00384 fsm *f = &lcp_fsm[unit];
00385
00386 fsm_input(f, p, len);
00387 }
00388
00389
00390
00391
00392
00393 static int
00394 lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)
00395 {
00396 u_char *magp;
00397
00398 switch( code ){
00399 case PROTREJ:
00400 lcp_rprotrej(f, inp, len);
00401 break;
00402
00403 case ECHOREQ:
00404 if (f->state != LS_OPENED) {
00405 break;
00406 }
00407 LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id));
00408 magp = inp;
00409 PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
00410 fsm_sdata(f, ECHOREP, id, inp, len);
00411 break;
00412
00413 case ECHOREP:
00414 lcp_received_echo_reply(f, id, inp, len);
00415 break;
00416
00417 case DISCREQ:
00418 break;
00419
00420 default:
00421 return 0;
00422 }
00423 return 1;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432 static void
00433 lcp_rprotrej(fsm *f, u_char *inp, int len)
00434 {
00435 int i;
00436 struct protent *protp;
00437 u_short prot;
00438
00439 if (len < sizeof (u_short)) {
00440 LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));
00441 return;
00442 }
00443
00444 GETSHORT(prot, inp);
00445
00446 LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot));
00447
00448
00449
00450
00451
00452 if( f->state != LS_OPENED ) {
00453 LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state));
00454 return;
00455 }
00456
00457
00458
00459
00460 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
00461 if (protp->protocol == prot && protp->enabled_flag) {
00462 (*protp->protrej)(f->unit);
00463 return;
00464 }
00465 }
00466
00467 LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot));
00468 }
00469
00470
00471
00472
00473
00474 static void
00475 lcp_protrej(int unit)
00476 {
00477 LWIP_UNUSED_ARG(unit);
00478
00479
00480
00481 LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n"));
00482 fsm_protreject(&lcp_fsm[unit]);
00483 }
00484
00485
00486
00487
00488
00489 static void
00490 lcp_resetci(fsm *f)
00491 {
00492 lcp_wantoptions[f->unit].magicnumber = magic();
00493 lcp_wantoptions[f->unit].numloops = 0;
00494 lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
00495 peer_mru[f->unit] = PPP_MRU;
00496 auth_reset(f->unit);
00497 }
00498
00499
00500
00501
00502
00503 static int lcp_cilen(fsm *f)
00504 {
00505 lcp_options *go = &lcp_gotoptions[f->unit];
00506
00507 #define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
00508 #define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
00509 #define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
00510 #define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
00511 #define LENCILQR(neg) ((neg) ? CILEN_LQR: 0)
00512 #define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
00513
00514
00515
00516
00517 return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +
00518 LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +
00519 LENCICHAP(go->neg_chap) +
00520 LENCISHORT(!go->neg_chap && go->neg_upap) +
00521 LENCILQR(go->neg_lqr) +
00522 LENCICBCP(go->neg_cbcp) +
00523 LENCILONG(go->neg_magicnumber) +
00524 LENCIVOID(go->neg_pcompression) +
00525 LENCIVOID(go->neg_accompression));
00526 }
00527
00528
00529
00530
00531
00532 static void
00533 lcp_addci(fsm *f, u_char *ucp, int *lenp)
00534 {
00535 lcp_options *go = &lcp_gotoptions[f->unit];
00536 u_char *start_ucp = ucp;
00537
00538 #define ADDCIVOID(opt, neg) \
00539 if (neg) { \
00540 LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \
00541 PUTCHAR(opt, ucp); \
00542 PUTCHAR(CILEN_VOID, ucp); \
00543 }
00544 #define ADDCISHORT(opt, neg, val) \
00545 if (neg) { \
00546 LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \
00547 PUTCHAR(opt, ucp); \
00548 PUTCHAR(CILEN_SHORT, ucp); \
00549 PUTSHORT(val, ucp); \
00550 }
00551 #define ADDCICHAP(opt, neg, val, digest) \
00552 if (neg) { \
00553 LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \
00554 PUTCHAR(opt, ucp); \
00555 PUTCHAR(CILEN_CHAP, ucp); \
00556 PUTSHORT(val, ucp); \
00557 PUTCHAR(digest, ucp); \
00558 }
00559 #define ADDCILONG(opt, neg, val) \
00560 if (neg) { \
00561 LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \
00562 PUTCHAR(opt, ucp); \
00563 PUTCHAR(CILEN_LONG, ucp); \
00564 PUTLONG(val, ucp); \
00565 }
00566 #define ADDCILQR(opt, neg, val) \
00567 if (neg) { \
00568 LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \
00569 PUTCHAR(opt, ucp); \
00570 PUTCHAR(CILEN_LQR, ucp); \
00571 PUTSHORT(PPP_LQR, ucp); \
00572 PUTLONG(val, ucp); \
00573 }
00574 #define ADDCICHAR(opt, neg, val) \
00575 if (neg) { \
00576 LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \
00577 PUTCHAR(opt, ucp); \
00578 PUTCHAR(CILEN_CHAR, ucp); \
00579 PUTCHAR(val, ucp); \
00580 }
00581
00582 ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
00583 ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);
00584 ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
00585 ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
00586 ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
00587 ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
00588 ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
00589 ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
00590 ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
00591
00592 if (ucp - start_ucp != *lenp) {
00593
00594 LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n"));
00595 }
00596 }
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 static int
00608 lcp_ackci(fsm *f, u_char *p, int len)
00609 {
00610 lcp_options *go = &lcp_gotoptions[f->unit];
00611 u_char cilen, citype, cichar;
00612 u_short cishort;
00613 u32_t cilong;
00614
00615
00616
00617
00618
00619
00620 #define ACKCIVOID(opt, neg) \
00621 if (neg) { \
00622 if ((len -= CILEN_VOID) < 0) \
00623 goto bad; \
00624 GETCHAR(citype, p); \
00625 GETCHAR(cilen, p); \
00626 if (cilen != CILEN_VOID || citype != opt) \
00627 goto bad; \
00628 }
00629 #define ACKCISHORT(opt, neg, val) \
00630 if (neg) { \
00631 if ((len -= CILEN_SHORT) < 0) \
00632 goto bad; \
00633 GETCHAR(citype, p); \
00634 GETCHAR(cilen, p); \
00635 if (cilen != CILEN_SHORT || citype != opt) \
00636 goto bad; \
00637 GETSHORT(cishort, p); \
00638 if (cishort != val) \
00639 goto bad; \
00640 }
00641 #define ACKCICHAR(opt, neg, val) \
00642 if (neg) { \
00643 if ((len -= CILEN_CHAR) < 0) \
00644 goto bad; \
00645 GETCHAR(citype, p); \
00646 GETCHAR(cilen, p); \
00647 if (cilen != CILEN_CHAR || citype != opt) \
00648 goto bad; \
00649 GETCHAR(cichar, p); \
00650 if (cichar != val) \
00651 goto bad; \
00652 }
00653 #define ACKCICHAP(opt, neg, val, digest) \
00654 if (neg) { \
00655 if ((len -= CILEN_CHAP) < 0) \
00656 goto bad; \
00657 GETCHAR(citype, p); \
00658 GETCHAR(cilen, p); \
00659 if (cilen != CILEN_CHAP || citype != opt) \
00660 goto bad; \
00661 GETSHORT(cishort, p); \
00662 if (cishort != val) \
00663 goto bad; \
00664 GETCHAR(cichar, p); \
00665 if (cichar != digest) \
00666 goto bad; \
00667 }
00668 #define ACKCILONG(opt, neg, val) \
00669 if (neg) { \
00670 if ((len -= CILEN_LONG) < 0) \
00671 goto bad; \
00672 GETCHAR(citype, p); \
00673 GETCHAR(cilen, p); \
00674 if (cilen != CILEN_LONG || citype != opt) \
00675 goto bad; \
00676 GETLONG(cilong, p); \
00677 if (cilong != val) \
00678 goto bad; \
00679 }
00680 #define ACKCILQR(opt, neg, val) \
00681 if (neg) { \
00682 if ((len -= CILEN_LQR) < 0) \
00683 goto bad; \
00684 GETCHAR(citype, p); \
00685 GETCHAR(cilen, p); \
00686 if (cilen != CILEN_LQR || citype != opt) \
00687 goto bad; \
00688 GETSHORT(cishort, p); \
00689 if (cishort != PPP_LQR) \
00690 goto bad; \
00691 GETLONG(cilong, p); \
00692 if (cilong != val) \
00693 goto bad; \
00694 }
00695
00696 ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
00697 ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);
00698 ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
00699 ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
00700 ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
00701 ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
00702 ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
00703 ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
00704 ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
00705
00706
00707
00708
00709 if (len != 0) {
00710 goto bad;
00711 }
00712 LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n"));
00713 return (1);
00714 bad:
00715 LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n"));
00716 return (0);
00717 }
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729 static int
00730 lcp_nakci(fsm *f, u_char *p, int len)
00731 {
00732 lcp_options *go = &lcp_gotoptions[f->unit];
00733 lcp_options *wo = &lcp_wantoptions[f->unit];
00734 u_char citype, cichar, *next;
00735 u_short cishort;
00736 u32_t cilong;
00737 lcp_options no;
00738 lcp_options try;
00739 int looped_back = 0;
00740 int cilen;
00741
00742 BZERO(&no, sizeof(no));
00743 try = *go;
00744
00745
00746
00747
00748
00749
00750 #define NAKCIVOID(opt, neg, code) \
00751 if (go->neg && \
00752 len >= CILEN_VOID && \
00753 p[1] == CILEN_VOID && \
00754 p[0] == opt) { \
00755 len -= CILEN_VOID; \
00756 INCPTR(CILEN_VOID, p); \
00757 no.neg = 1; \
00758 code \
00759 }
00760 #define NAKCICHAP(opt, neg, code) \
00761 if (go->neg && \
00762 len >= CILEN_CHAP && \
00763 p[1] == CILEN_CHAP && \
00764 p[0] == opt) { \
00765 len -= CILEN_CHAP; \
00766 INCPTR(2, p); \
00767 GETSHORT(cishort, p); \
00768 GETCHAR(cichar, p); \
00769 no.neg = 1; \
00770 code \
00771 }
00772 #define NAKCICHAR(opt, neg, code) \
00773 if (go->neg && \
00774 len >= CILEN_CHAR && \
00775 p[1] == CILEN_CHAR && \
00776 p[0] == opt) { \
00777 len -= CILEN_CHAR; \
00778 INCPTR(2, p); \
00779 GETCHAR(cichar, p); \
00780 no.neg = 1; \
00781 code \
00782 }
00783 #define NAKCISHORT(opt, neg, code) \
00784 if (go->neg && \
00785 len >= CILEN_SHORT && \
00786 p[1] == CILEN_SHORT && \
00787 p[0] == opt) { \
00788 len -= CILEN_SHORT; \
00789 INCPTR(2, p); \
00790 GETSHORT(cishort, p); \
00791 no.neg = 1; \
00792 code \
00793 }
00794 #define NAKCILONG(opt, neg, code) \
00795 if (go->neg && \
00796 len >= CILEN_LONG && \
00797 p[1] == CILEN_LONG && \
00798 p[0] == opt) { \
00799 len -= CILEN_LONG; \
00800 INCPTR(2, p); \
00801 GETLONG(cilong, p); \
00802 no.neg = 1; \
00803 code \
00804 }
00805 #define NAKCILQR(opt, neg, code) \
00806 if (go->neg && \
00807 len >= CILEN_LQR && \
00808 p[1] == CILEN_LQR && \
00809 p[0] == opt) { \
00810 len -= CILEN_LQR; \
00811 INCPTR(2, p); \
00812 GETSHORT(cishort, p); \
00813 GETLONG(cilong, p); \
00814 no.neg = 1; \
00815 code \
00816 }
00817
00818
00819
00820
00821
00822
00823
00824
00825 if (go->neg_mru && go->mru != PPP_DEFMRU) {
00826 NAKCISHORT(CI_MRU, neg_mru,
00827 if (cishort <= wo->mru || cishort < PPP_DEFMRU) {
00828 try.mru = cishort;
00829 }
00830 );
00831 }
00832
00833
00834
00835
00836 if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {
00837 NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
00838 try.asyncmap = go->asyncmap | cilong;
00839 );
00840 }
00841
00842
00843
00844
00845
00846
00847 if ((go->neg_chap || go->neg_upap)
00848 && len >= CILEN_SHORT
00849 && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
00850 cilen = p[1];
00851 len -= cilen;
00852 no.neg_chap = go->neg_chap;
00853 no.neg_upap = go->neg_upap;
00854 INCPTR(2, p);
00855 GETSHORT(cishort, p);
00856 if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
00857
00858
00859
00860
00861
00862 if (!go->neg_chap) {
00863 goto bad;
00864 }
00865 try.neg_chap = 0;
00866
00867 } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
00868 GETCHAR(cichar, p);
00869 if (go->neg_chap) {
00870
00871
00872
00873
00874
00875 if (cichar != go->chap_mdtype) {
00876 try.neg_chap = 0;
00877 }
00878 } else {
00879
00880
00881
00882 try.neg_upap = 0;
00883 }
00884
00885 } else {
00886
00887
00888
00889
00890 if (go->neg_chap) {
00891 try.neg_chap = 0;
00892 } else {
00893 try.neg_upap = 0;
00894 }
00895 p += cilen - CILEN_SHORT;
00896 }
00897 }
00898
00899
00900
00901
00902
00903
00904 NAKCILQR(CI_QUALITY, neg_lqr,
00905 if (cishort != PPP_LQR) {
00906 try.neg_lqr = 0;
00907 } else {
00908 try.lqr_period = cilong;
00909 }
00910 );
00911
00912
00913
00914
00915 NAKCICHAR(CI_CALLBACK, neg_cbcp,
00916 try.neg_cbcp = 0;
00917 );
00918
00919
00920
00921
00922 NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
00923 try.magicnumber = magic();
00924 looped_back = 1;
00925 );
00926
00927
00928
00929
00930
00931
00932 NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
00933 try.neg_pcompression = 0;
00934 );
00935 NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
00936 try.neg_accompression = 0;
00937 );
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955 while (len > CILEN_VOID) {
00956 GETCHAR(citype, p);
00957 GETCHAR(cilen, p);
00958 if (cilen < CILEN_VOID || (len -= cilen) < 0) {
00959 goto bad;
00960 }
00961 next = p + cilen - 2;
00962
00963 switch (citype) {
00964 case CI_MRU:
00965 if ((go->neg_mru && go->mru != PPP_DEFMRU)
00966 || no.neg_mru || cilen != CILEN_SHORT) {
00967 goto bad;
00968 }
00969 GETSHORT(cishort, p);
00970 if (cishort < PPP_DEFMRU) {
00971 try.mru = cishort;
00972 }
00973 break;
00974 case CI_ASYNCMAP:
00975 if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)
00976 || no.neg_asyncmap || cilen != CILEN_LONG) {
00977 goto bad;
00978 }
00979 break;
00980 case CI_AUTHTYPE:
00981 if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) {
00982 goto bad;
00983 }
00984 break;
00985 case CI_MAGICNUMBER:
00986 if (go->neg_magicnumber || no.neg_magicnumber ||
00987 cilen != CILEN_LONG) {
00988 goto bad;
00989 }
00990 break;
00991 case CI_PCOMPRESSION:
00992 if (go->neg_pcompression || no.neg_pcompression
00993 || cilen != CILEN_VOID) {
00994 goto bad;
00995 }
00996 break;
00997 case CI_ACCOMPRESSION:
00998 if (go->neg_accompression || no.neg_accompression
00999 || cilen != CILEN_VOID) {
01000 goto bad;
01001 }
01002 break;
01003 case CI_QUALITY:
01004 if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) {
01005 goto bad;
01006 }
01007 break;
01008 }
01009 p = next;
01010 }
01011
01012
01013 if (len != 0) {
01014 goto bad;
01015 }
01016
01017
01018
01019
01020 if (f->state != LS_OPENED) {
01021 if (looped_back) {
01022 if (++try.numloops >= lcp_loopbackfail) {
01023 LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n"));
01024 lcp_close(f->unit, "Loopback detected");
01025 }
01026 } else {
01027 try.numloops = 0;
01028 }
01029 *go = try;
01030 }
01031
01032 return 1;
01033
01034 bad:
01035 LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n"));
01036 return 0;
01037 }
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049 static int
01050 lcp_rejci(fsm *f, u_char *p, int len)
01051 {
01052 lcp_options *go = &lcp_gotoptions[f->unit];
01053 u_char cichar;
01054 u_short cishort;
01055 u32_t cilong;
01056 lcp_options try;
01057
01058 try = *go;
01059
01060
01061
01062
01063
01064
01065 #define REJCIVOID(opt, neg) \
01066 if (go->neg && \
01067 len >= CILEN_VOID && \
01068 p[1] == CILEN_VOID && \
01069 p[0] == opt) { \
01070 len -= CILEN_VOID; \
01071 INCPTR(CILEN_VOID, p); \
01072 try.neg = 0; \
01073 LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \
01074 }
01075 #define REJCISHORT(opt, neg, val) \
01076 if (go->neg && \
01077 len >= CILEN_SHORT && \
01078 p[1] == CILEN_SHORT && \
01079 p[0] == opt) { \
01080 len -= CILEN_SHORT; \
01081 INCPTR(2, p); \
01082 GETSHORT(cishort, p); \
01083 \
01084 if (cishort != val) { \
01085 goto bad; \
01086 } \
01087 try.neg = 0; \
01088 LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \
01089 }
01090 #define REJCICHAP(opt, neg, val, digest) \
01091 if (go->neg && \
01092 len >= CILEN_CHAP && \
01093 p[1] == CILEN_CHAP && \
01094 p[0] == opt) { \
01095 len -= CILEN_CHAP; \
01096 INCPTR(2, p); \
01097 GETSHORT(cishort, p); \
01098 GETCHAR(cichar, p); \
01099 \
01100 if (cishort != val || cichar != digest) { \
01101 goto bad; \
01102 } \
01103 try.neg = 0; \
01104 try.neg_upap = 0; \
01105 LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \
01106 }
01107 #define REJCILONG(opt, neg, val) \
01108 if (go->neg && \
01109 len >= CILEN_LONG && \
01110 p[1] == CILEN_LONG && \
01111 p[0] == opt) { \
01112 len -= CILEN_LONG; \
01113 INCPTR(2, p); \
01114 GETLONG(cilong, p); \
01115 \
01116 if (cilong != val) { \
01117 goto bad; \
01118 } \
01119 try.neg = 0; \
01120 LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \
01121 }
01122 #define REJCILQR(opt, neg, val) \
01123 if (go->neg && \
01124 len >= CILEN_LQR && \
01125 p[1] == CILEN_LQR && \
01126 p[0] == opt) { \
01127 len -= CILEN_LQR; \
01128 INCPTR(2, p); \
01129 GETSHORT(cishort, p); \
01130 GETLONG(cilong, p); \
01131 \
01132 if (cishort != PPP_LQR || cilong != val) { \
01133 goto bad; \
01134 } \
01135 try.neg = 0; \
01136 LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \
01137 }
01138 #define REJCICBCP(opt, neg, val) \
01139 if (go->neg && \
01140 len >= CILEN_CBCP && \
01141 p[1] == CILEN_CBCP && \
01142 p[0] == opt) { \
01143 len -= CILEN_CBCP; \
01144 INCPTR(2, p); \
01145 GETCHAR(cichar, p); \
01146 \
01147 if (cichar != val) { \
01148 goto bad; \
01149 } \
01150 try.neg = 0; \
01151 LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \
01152 }
01153
01154 REJCISHORT(CI_MRU, neg_mru, go->mru);
01155 REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
01156 REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
01157 if (!go->neg_chap) {
01158 REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
01159 }
01160 REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
01161 REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
01162 REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
01163 REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
01164 REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
01165
01166
01167
01168
01169 if (len != 0) {
01170 goto bad;
01171 }
01172
01173
01174
01175 if (f->state != LS_OPENED) {
01176 *go = try;
01177 }
01178 return 1;
01179
01180 bad:
01181 LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n"));
01182 return 0;
01183 }
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193 static int
01194 lcp_reqci(fsm *f,
01195 u_char *inp,
01196 int *lenp,
01197 int reject_if_disagree)
01198 {
01199 lcp_options *go = &lcp_gotoptions[f->unit];
01200 lcp_options *ho = &lcp_hisoptions[f->unit];
01201 lcp_options *ao = &lcp_allowoptions[f->unit];
01202 u_char *cip, *next;
01203 int cilen, citype, cichar;
01204 u_short cishort;
01205 u32_t cilong;
01206 int rc = CONFACK;
01207 int orc;
01208 u_char *p;
01209 u_char *rejp;
01210 u_char *nakp;
01211 int l = *lenp;
01212 #if TRACELCP > 0
01213 char traceBuf[80];
01214 int traceNdx = 0;
01215 #endif
01216
01217
01218
01219
01220 BZERO(ho, sizeof(*ho));
01221
01222
01223
01224
01225 next = inp;
01226 nakp = nak_buffer;
01227 rejp = inp;
01228 while (l) {
01229 orc = CONFACK;
01230 cip = p = next;
01231 if (l < 2 ||
01232 p[1] < 2 ||
01233 p[1] > l) {
01234 LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n"));
01235 orc = CONFREJ;
01236 cilen = l;
01237 l = 0;
01238 citype = 0;
01239 goto endswitch;
01240 }
01241 GETCHAR(citype, p);
01242 GETCHAR(cilen, p);
01243 l -= cilen;
01244 next += cilen;
01245
01246 switch (citype) {
01247 case CI_MRU:
01248 if (!ao->neg_mru) {
01249 LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n"));
01250 orc = CONFREJ;
01251 break;
01252 } else if (cilen != CILEN_SHORT) {
01253 LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n"));
01254 orc = CONFREJ;
01255 break;
01256 }
01257 GETSHORT(cishort, p);
01258
01259
01260
01261
01262
01263
01264 if (cishort < PPP_MINMRU) {
01265 LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n"));
01266 orc = CONFNAK;
01267 PUTCHAR(CI_MRU, nakp);
01268 PUTCHAR(CILEN_SHORT, nakp);
01269 PUTSHORT(PPP_MINMRU, nakp);
01270 break;
01271 }
01272 ho->neg_mru = 1;
01273 ho->mru = cishort;
01274 #if TRACELCP > 0
01275 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);
01276 traceNdx = strlen(traceBuf);
01277 #endif
01278 break;
01279
01280 case CI_ASYNCMAP:
01281 if (!ao->neg_asyncmap) {
01282 LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n"));
01283 orc = CONFREJ;
01284 break;
01285 } else if (cilen != CILEN_LONG) {
01286 LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n"));
01287 orc = CONFREJ;
01288 break;
01289 }
01290 GETLONG(cilong, p);
01291
01292
01293
01294
01295
01296 if ((ao->asyncmap & ~cilong) != 0) {
01297 LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n",
01298 cilong, ao->asyncmap));
01299 orc = CONFNAK;
01300 PUTCHAR(CI_ASYNCMAP, nakp);
01301 PUTCHAR(CILEN_LONG, nakp);
01302 PUTLONG(ao->asyncmap | cilong, nakp);
01303 break;
01304 }
01305 ho->neg_asyncmap = 1;
01306 ho->asyncmap = cilong;
01307 #if TRACELCP > 0
01308 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);
01309 traceNdx = strlen(traceBuf);
01310 #endif
01311 break;
01312
01313 case CI_AUTHTYPE:
01314 if (cilen < CILEN_SHORT) {
01315 LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n"));
01316 orc = CONFREJ;
01317 break;
01318 } else if (!(ao->neg_upap || ao->neg_chap)) {
01319
01320
01321
01322 LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n"));
01323 orc = CONFREJ;
01324 break;
01325 }
01326 GETSHORT(cishort, p);
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339 if (cishort == PPP_PAP) {
01340 if (ho->neg_chap) {
01341 LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));
01342 orc = CONFREJ;
01343 break;
01344 } else if (cilen != CILEN_SHORT) {
01345 LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n"));
01346 orc = CONFREJ;
01347 break;
01348 }
01349 if (!ao->neg_upap) {
01350 LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));
01351 orc = CONFNAK;
01352 PUTCHAR(CI_AUTHTYPE, nakp);
01353 PUTCHAR(CILEN_CHAP, nakp);
01354 PUTSHORT(PPP_CHAP, nakp);
01355 PUTCHAR(ao->chap_mdtype, nakp);
01356 break;
01357 }
01358 ho->neg_upap = 1;
01359 #if TRACELCP > 0
01360 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);
01361 traceNdx = strlen(traceBuf);
01362 #endif
01363 break;
01364 }
01365 if (cishort == PPP_CHAP) {
01366 if (ho->neg_upap) {
01367 LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));
01368 orc = CONFREJ;
01369 break;
01370 } else if (cilen != CILEN_CHAP) {
01371 LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));
01372 orc = CONFREJ;
01373 break;
01374 }
01375 if (!ao->neg_chap) {
01376 LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));
01377 orc = CONFNAK;
01378 PUTCHAR(CI_AUTHTYPE, nakp);
01379 PUTCHAR(CILEN_SHORT, nakp);
01380 PUTSHORT(PPP_PAP, nakp);
01381 break;
01382 }
01383 GETCHAR(cichar, p);
01384 if (cichar != CHAP_DIGEST_MD5
01385 #ifdef CHAPMS
01386 && cichar != CHAP_MICROSOFT
01387 #endif
01388 ) {
01389 LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar));
01390 orc = CONFNAK;
01391 PUTCHAR(CI_AUTHTYPE, nakp);
01392 PUTCHAR(CILEN_CHAP, nakp);
01393 PUTSHORT(PPP_CHAP, nakp);
01394 PUTCHAR(ao->chap_mdtype, nakp);
01395 break;
01396 }
01397 #if TRACELCP > 0
01398 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar);
01399 traceNdx = strlen(traceBuf);
01400 #endif
01401 ho->chap_mdtype = cichar;
01402 ho->neg_chap = 1;
01403 break;
01404 }
01405
01406
01407
01408
01409
01410
01411 orc = CONFNAK;
01412 PUTCHAR(CI_AUTHTYPE, nakp);
01413 if (ao->neg_chap) {
01414 LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));
01415 PUTCHAR(CILEN_CHAP, nakp);
01416 PUTSHORT(PPP_CHAP, nakp);
01417 PUTCHAR(ao->chap_mdtype, nakp);
01418 } else {
01419 LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));
01420 PUTCHAR(CILEN_SHORT, nakp);
01421 PUTSHORT(PPP_PAP, nakp);
01422 }
01423 break;
01424
01425 case CI_QUALITY:
01426 GETSHORT(cishort, p);
01427 GETLONG(cilong, p);
01428 #if TRACELCP > 0
01429 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);
01430 traceNdx = strlen(traceBuf);
01431 #endif
01432
01433 if (!ao->neg_lqr ||
01434 cilen != CILEN_LQR) {
01435 orc = CONFREJ;
01436 break;
01437 }
01438
01439
01440
01441
01442
01443 if (cishort != PPP_LQR) {
01444 orc = CONFNAK;
01445 PUTCHAR(CI_QUALITY, nakp);
01446 PUTCHAR(CILEN_LQR, nakp);
01447 PUTSHORT(PPP_LQR, nakp);
01448 PUTLONG(ao->lqr_period, nakp);
01449 break;
01450 }
01451 break;
01452
01453 case CI_MAGICNUMBER:
01454 if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
01455 cilen != CILEN_LONG) {
01456 orc = CONFREJ;
01457 break;
01458 }
01459 GETLONG(cilong, p);
01460 #if TRACELCP > 0
01461 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);
01462 traceNdx = strlen(traceBuf);
01463 #endif
01464
01465
01466
01467
01468 if (go->neg_magicnumber &&
01469 cilong == go->magicnumber) {
01470 cilong = magic();
01471 orc = CONFNAK;
01472 PUTCHAR(CI_MAGICNUMBER, nakp);
01473 PUTCHAR(CILEN_LONG, nakp);
01474 PUTLONG(cilong, nakp);
01475 break;
01476 }
01477 ho->neg_magicnumber = 1;
01478 ho->magicnumber = cilong;
01479 break;
01480
01481
01482 case CI_PCOMPRESSION:
01483 #if TRACELCP > 0
01484 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");
01485 traceNdx = strlen(traceBuf);
01486 #endif
01487 if (!ao->neg_pcompression ||
01488 cilen != CILEN_VOID) {
01489 orc = CONFREJ;
01490 break;
01491 }
01492 ho->neg_pcompression = 1;
01493 break;
01494
01495 case CI_ACCOMPRESSION:
01496 #if TRACELCP > 0
01497 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");
01498 traceNdx = strlen(traceBuf);
01499 #endif
01500 if (!ao->neg_accompression ||
01501 cilen != CILEN_VOID) {
01502 orc = CONFREJ;
01503 break;
01504 }
01505 ho->neg_accompression = 1;
01506 break;
01507
01508 case CI_MRRU:
01509 #if TRACELCP > 0
01510 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");
01511 traceNdx = strlen(traceBuf);
01512 #endif
01513 orc = CONFREJ;
01514 break;
01515
01516 case CI_SSNHF:
01517 #if TRACELCP > 0
01518 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");
01519 traceNdx = strlen(traceBuf);
01520 #endif
01521 orc = CONFREJ;
01522 break;
01523
01524 case CI_EPDISC:
01525 #if TRACELCP > 0
01526 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");
01527 traceNdx = strlen(traceBuf);
01528 #endif
01529 orc = CONFREJ;
01530 break;
01531
01532 default:
01533 #if TRACELCP
01534 snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);
01535 traceNdx = strlen(traceBuf);
01536 #endif
01537 orc = CONFREJ;
01538 break;
01539 }
01540
01541 endswitch:
01542 #if TRACELCP
01543 if (traceNdx >= 80 - 32) {
01544 LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf));
01545 traceNdx = 0;
01546 }
01547 #endif
01548 if (orc == CONFACK &&
01549 rc != CONFACK) {
01550 continue;
01551 }
01552
01553 if (orc == CONFNAK) {
01554 if (reject_if_disagree
01555 && citype != CI_MAGICNUMBER) {
01556 orc = CONFREJ;
01557 } else {
01558 if (rc == CONFREJ) {
01559 continue;
01560 }
01561 rc = CONFNAK;
01562 }
01563 }
01564 if (orc == CONFREJ) {
01565 rc = CONFREJ;
01566 if (cip != rejp) {
01567 BCOPY(cip, rejp, cilen);
01568 }
01569 INCPTR(cilen, rejp);
01570 }
01571 }
01572
01573
01574
01575
01576
01577
01578
01579
01580 switch (rc) {
01581 case CONFACK:
01582 *lenp = (int)(next - inp);
01583 break;
01584 case CONFNAK:
01585
01586
01587
01588 *lenp = (int)(nakp - nak_buffer);
01589 BCOPY(nak_buffer, inp, *lenp);
01590 break;
01591 case CONFREJ:
01592 *lenp = (int)(rejp - inp);
01593 break;
01594 }
01595
01596 #if TRACELCP > 0
01597 if (traceNdx > 0) {
01598 LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf));
01599 }
01600 #endif
01601 LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc)));
01602 return (rc);
01603 }
01604
01605
01606
01607
01608
01609 static void
01610 lcp_up(fsm *f)
01611 {
01612 lcp_options *wo = &lcp_wantoptions[f->unit];
01613 lcp_options *ho = &lcp_hisoptions[f->unit];
01614 lcp_options *go = &lcp_gotoptions[f->unit];
01615 lcp_options *ao = &lcp_allowoptions[f->unit];
01616
01617 if (!go->neg_magicnumber) {
01618 go->magicnumber = 0;
01619 }
01620 if (!ho->neg_magicnumber) {
01621 ho->magicnumber = 0;
01622 }
01623
01624
01625
01626
01627
01628
01629
01630 ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
01631 (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),
01632 ho->neg_pcompression, ho->neg_accompression);
01633
01634
01635
01636
01637
01638 ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),
01639 (go->neg_asyncmap? go->asyncmap: 0x00000000),
01640 go->neg_pcompression, go->neg_accompression);
01641
01642 if (ho->neg_mru) {
01643 peer_mru[f->unit] = ho->mru;
01644 }
01645
01646 lcp_echo_lowerup(f->unit);
01647
01648 link_established(f->unit);
01649 }
01650
01651
01652
01653
01654
01655
01656
01657 static void
01658 lcp_down(fsm *f)
01659 {
01660 lcp_options *go = &lcp_gotoptions[f->unit];
01661
01662 lcp_echo_lowerdown(f->unit);
01663
01664 link_down(f->unit);
01665
01666 ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);
01667 ppp_recv_config(f->unit, PPP_MRU,
01668 (go->neg_asyncmap? go->asyncmap: 0x00000000),
01669 go->neg_pcompression, go->neg_accompression);
01670 peer_mru[f->unit] = PPP_MRU;
01671 }
01672
01673
01674
01675
01676
01677 static void
01678 lcp_starting(fsm *f)
01679 {
01680 link_required(f->unit);
01681 }
01682
01683
01684
01685
01686
01687 static void
01688 lcp_finished(fsm *f)
01689 {
01690 link_terminated(f->unit);
01691 }
01692
01693
01694 #if 0
01695
01696
01697
01698
01699 static void
01700 print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg)
01701 {
01702 int c;
01703
01704 printer(arg, "\"");
01705 for (; len > 0; --len) {
01706 c = *p++;
01707 if (' ' <= c && c <= '~') {
01708 if (c == '\\' || c == '"') {
01709 printer(arg, "\\");
01710 }
01711 printer(arg, "%c", c);
01712 } else {
01713 switch (c) {
01714 case '\n':
01715 printer(arg, "\\n");
01716 break;
01717 case '\r':
01718 printer(arg, "\\r");
01719 break;
01720 case '\t':
01721 printer(arg, "\\t");
01722 break;
01723 default:
01724 printer(arg, "\\%.3o", c);
01725 }
01726 }
01727 }
01728 printer(arg, "\"");
01729 }
01730
01731
01732
01733
01734
01735 static char *lcp_codenames[] = {
01736 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
01737 "TermReq", "TermAck", "CodeRej", "ProtRej",
01738 "EchoReq", "EchoRep", "DiscReq"
01739 };
01740
01741 static int
01742 lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
01743 {
01744 int code, id, len, olen;
01745 u_char *pstart, *optend;
01746 u_short cishort;
01747 u32_t cilong;
01748
01749 if (plen < HEADERLEN) {
01750 return 0;
01751 }
01752 pstart = p;
01753 GETCHAR(code, p);
01754 GETCHAR(id, p);
01755 GETSHORT(len, p);
01756 if (len < HEADERLEN || len > plen) {
01757 return 0;
01758 }
01759
01760 if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) {
01761 printer(arg, " %s", lcp_codenames[code-1]);
01762 } else {
01763 printer(arg, " code=0x%x", code);
01764 }
01765 printer(arg, " id=0x%x", id);
01766 len -= HEADERLEN;
01767 switch (code) {
01768 case CONFREQ:
01769 case CONFACK:
01770 case CONFNAK:
01771 case CONFREJ:
01772
01773 while (len >= 2) {
01774 GETCHAR(code, p);
01775 GETCHAR(olen, p);
01776 p -= 2;
01777 if (olen < 2 || olen > len) {
01778 break;
01779 }
01780 printer(arg, " <");
01781 len -= olen;
01782 optend = p + olen;
01783 switch (code) {
01784 case CI_MRU:
01785 if (olen == CILEN_SHORT) {
01786 p += 2;
01787 GETSHORT(cishort, p);
01788 printer(arg, "mru %d", cishort);
01789 }
01790 break;
01791 case CI_ASYNCMAP:
01792 if (olen == CILEN_LONG) {
01793 p += 2;
01794 GETLONG(cilong, p);
01795 printer(arg, "asyncmap 0x%lx", cilong);
01796 }
01797 break;
01798 case CI_AUTHTYPE:
01799 if (olen >= CILEN_SHORT) {
01800 p += 2;
01801 printer(arg, "auth ");
01802 GETSHORT(cishort, p);
01803 switch (cishort) {
01804 case PPP_PAP:
01805 printer(arg, "pap");
01806 break;
01807 case PPP_CHAP:
01808 printer(arg, "chap");
01809 break;
01810 default:
01811 printer(arg, "0x%x", cishort);
01812 }
01813 }
01814 break;
01815 case CI_QUALITY:
01816 if (olen >= CILEN_SHORT) {
01817 p += 2;
01818 printer(arg, "quality ");
01819 GETSHORT(cishort, p);
01820 switch (cishort) {
01821 case PPP_LQR:
01822 printer(arg, "lqr");
01823 break;
01824 default:
01825 printer(arg, "0x%x", cishort);
01826 }
01827 }
01828 break;
01829 case CI_CALLBACK:
01830 if (olen >= CILEN_CHAR) {
01831 p += 2;
01832 printer(arg, "callback ");
01833 GETSHORT(cishort, p);
01834 switch (cishort) {
01835 case CBCP_OPT:
01836 printer(arg, "CBCP");
01837 break;
01838 default:
01839 printer(arg, "0x%x", cishort);
01840 }
01841 }
01842 break;
01843 case CI_MAGICNUMBER:
01844 if (olen == CILEN_LONG) {
01845 p += 2;
01846 GETLONG(cilong, p);
01847 printer(arg, "magic 0x%x", cilong);
01848 }
01849 break;
01850 case CI_PCOMPRESSION:
01851 if (olen == CILEN_VOID) {
01852 p += 2;
01853 printer(arg, "pcomp");
01854 }
01855 break;
01856 case CI_ACCOMPRESSION:
01857 if (olen == CILEN_VOID) {
01858 p += 2;
01859 printer(arg, "accomp");
01860 }
01861 break;
01862 }
01863 while (p < optend) {
01864 GETCHAR(code, p);
01865 printer(arg, " %.2x", code);
01866 }
01867 printer(arg, ">");
01868 }
01869 break;
01870
01871 case TERMACK:
01872 case TERMREQ:
01873 if (len > 0 && *p >= ' ' && *p < 0x7f) {
01874 printer(arg, " ");
01875 print_string((char*)p, len, printer, arg);
01876 p += len;
01877 len = 0;
01878 }
01879 break;
01880
01881 case ECHOREQ:
01882 case ECHOREP:
01883 case DISCREQ:
01884 if (len >= 4) {
01885 GETLONG(cilong, p);
01886 printer(arg, " magic=0x%x", cilong);
01887 p += 4;
01888 len -= 4;
01889 }
01890 break;
01891 }
01892
01893
01894 for (; len > 0; --len) {
01895 GETCHAR(code, p);
01896 printer(arg, " %.2x", code);
01897 }
01898
01899 return (int)(p - pstart);
01900 }
01901 #endif
01902
01903
01904
01905
01906 static void
01907 LcpLinkFailure (fsm *f)
01908 {
01909 if (f->state == LS_OPENED) {
01910 LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending));
01911 LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n"));
01912 lcp_close(f->unit, "Peer not responding");
01913 }
01914 }
01915
01916
01917
01918
01919 static void
01920 LcpEchoCheck (fsm *f)
01921 {
01922 LcpSendEchoRequest (f);
01923
01924
01925
01926
01927 LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);
01928
01929 TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
01930 lcp_echo_timer_running = 1;
01931 }
01932
01933
01934
01935
01936 static void
01937 LcpEchoTimeout (void *arg)
01938 {
01939 if (lcp_echo_timer_running != 0) {
01940 lcp_echo_timer_running = 0;
01941 LcpEchoCheck ((fsm *) arg);
01942 }
01943 }
01944
01945
01946
01947
01948 static void
01949 lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)
01950 {
01951 u32_t magic;
01952
01953 LWIP_UNUSED_ARG(id);
01954
01955
01956 if (len < 4) {
01957 LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len));
01958 return;
01959 }
01960 GETLONG(magic, inp);
01961 if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) {
01962 LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n"));
01963 return;
01964 }
01965
01966
01967 lcp_echos_pending = 0;
01968 }
01969
01970
01971
01972
01973 static void
01974 LcpSendEchoRequest (fsm *f)
01975 {
01976 u32_t lcp_magic;
01977 u_char pkt[4], *pktp;
01978
01979
01980
01981
01982 if (lcp_echo_fails != 0) {
01983 if (lcp_echos_pending++ >= lcp_echo_fails) {
01984 LcpLinkFailure(f);
01985 lcp_echos_pending = 0;
01986 }
01987 }
01988
01989
01990
01991
01992 if (f->state == LS_OPENED) {
01993 lcp_magic = lcp_gotoptions[f->unit].magicnumber;
01994 pktp = pkt;
01995 PUTLONG(lcp_magic, pktp);
01996 fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));
01997 }
01998 }
01999
02000
02001
02002
02003
02004 static void
02005 lcp_echo_lowerup (int unit)
02006 {
02007 fsm *f = &lcp_fsm[unit];
02008
02009
02010 lcp_echos_pending = 0;
02011 lcp_echo_number = 0;
02012 lcp_echo_timer_running = 0;
02013
02014
02015 if (lcp_echo_interval != 0) {
02016 LcpEchoCheck (f);
02017 }
02018 }
02019
02020
02021
02022
02023
02024 static void
02025 lcp_echo_lowerdown (int unit)
02026 {
02027 fsm *f = &lcp_fsm[unit];
02028
02029 if (lcp_echo_timer_running != 0) {
02030 UNTIMEOUT (LcpEchoTimeout, f);
02031 lcp_echo_timer_running = 0;
02032 }
02033 }
02034
02035 #endif