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