Annotation of embedaddon/mpd/src/lcp.c, revision 1.1.1.2
1.1 misho 1:
2: /*
3: * lcp.c
4: *
5: * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
6: * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
7: * See ``COPYRIGHT.iij''
8: *
9: * Rewritten by Archie Cobbs <archie@freebsd.org>
10: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
11: * See ``COPYRIGHT.whistle''
12: */
13:
14: #include "ppp.h"
15: #include "lcp.h"
16: #include "fsm.h"
17: #include "mp.h"
18: #include "phys.h"
19: #include "link.h"
20: #include "msg.h"
21: #include "util.h"
22:
23: /*
24: * DEFINITIONS
25: */
26:
27: #define LCP_ECHO_INTERVAL 5 /* Enable keep alive by default */
28: #define LCP_ECHO_TIMEOUT 40
29:
30: #define LCP_KNOWN_CODES ( (1 << CODE_CONFIGREQ) \
31: | (1 << CODE_CONFIGACK) \
32: | (1 << CODE_CONFIGNAK) \
33: | (1 << CODE_CONFIGREJ) \
34: | (1 << CODE_TERMREQ) \
35: | (1 << CODE_TERMACK) \
36: | (1 << CODE_CODEREJ) \
37: | (1 << CODE_PROTOREJ) \
38: | (1 << CODE_ECHOREQ) \
39: | (1 << CODE_ECHOREP) \
40: | (1 << CODE_DISCREQ) \
41: | (1 << CODE_IDENT) \
42: | (1 << CODE_TIMEREM) )
43:
44: #define LCP_PEER_REJECTED(p,x) ((p)->peer_reject & (1<<x))
45: #define LCP_PEER_REJ(p,x) do{(p)->peer_reject |= (1<<(x));}while(0)
46: #define LCP_PEER_UNREJ(p,x) do{(p)->peer_reject &= ~(1<<(x));}while(0)
47:
48: /*
49: * INTERNAL FUNCTIONS
50: */
51:
52: static void LcpConfigure(Fsm fp);
53: static void LcpNewState(Fsm fp, enum fsm_state old, enum fsm_state new);
54: static void LcpNewPhase(Link l, enum lcp_phase new);
55:
56: static u_char *LcpBuildConfigReq(Fsm fp, u_char *cp);
57: static void LcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode);
58: static void LcpLayerDown(Fsm fp);
59: static void LcpLayerStart(Fsm fp);
60: static void LcpLayerFinish(Fsm fp);
61: static int LcpRecvProtoRej(Fsm fp, int proto, Mbuf bp);
62: static void LcpFailure(Fsm fp, enum fsmfail reason);
63: static const struct fsmoption *LcpAuthProtoNak(ushort proto, u_char alg);
64: static short LcpFindAuthProto(ushort proto, u_char alg);
65: static void LcpRecvIdent(Fsm fp, Mbuf bp);
66: static void LcpStopActivity(Link l);
67:
68: /*
69: * INTERNAL VARIABLES
70: */
71:
72: static const struct fsmoptinfo gLcpConfOpts[] = {
73: { "VENDOR", TY_VENDOR, 4, 255, TRUE },
74: { "MRU", TY_MRU, 2, 2, TRUE },
75: { "ACCMAP", TY_ACCMAP, 4, 4, TRUE },
76: { "AUTHPROTO", TY_AUTHPROTO, 2, 255, TRUE },
77: { "QUALPROTO", TY_QUALPROTO, 0, 0, FALSE },
78: { "MAGICNUM", TY_MAGICNUM, 4, 4, TRUE },
79: { "RESERVED", TY_RESERVED, 0, 0, FALSE }, /* DEPRECATED */
80: { "PROTOCOMP", TY_PROTOCOMP, 0, 0, TRUE },
81: { "ACFCOMP", TY_ACFCOMP, 0, 0, TRUE },
82: { "FCSALT", TY_FCSALT, 0, 0, FALSE },
83: { "SDP", TY_SDP, 0, 0, FALSE },
84: { "NUMMODE", TY_NUMMODE, 0, 0, FALSE },
85: { "MULTILINK", TY_MULTILINK, 0, 0, FALSE }, /* DEPRECATED */
86: { "CALLBACK", TY_CALLBACK, 1, 255, TRUE },
87: { "CONNECTTIME", TY_CONNECTTIME, 0, 0, FALSE }, /* DEPRECATED */
88: { "COMPFRAME", TY_COMPFRAME, 0, 0, FALSE }, /* DEPRECATED */
89: { "NDS", TY_NDS, 0, 0, FALSE }, /* DEPRECATED */
90: { "MP MRRU", TY_MRRU, 2, 2, TRUE },
91: { "MP SHORTSEQ", TY_SHORTSEQNUM, 0, 0, TRUE },
92: { "ENDPOINTDISC", TY_ENDPOINTDISC, 1, 255, TRUE },
93: { "PROPRIETARY", TY_PROPRIETARY, 0, 0, FALSE },
94: { "DCEIDENTIFIER", TY_DCEIDENTIFIER, 0, 0, FALSE },
95: { "MULTILINKPLUS", TY_MULTILINKPLUS, 0, 0, FALSE },
96: { "BACP", TY_BACP, 0, 0, FALSE },
97: { "LCPAUTHOPT", TY_LCPAUTHOPT, 0, 0, FALSE },
98: { "COBS", TY_COBS, 0, 0, FALSE },
99: { "PREFIXELISION", TY_PREFIXELISION, 0, 0, FALSE },
100: { "MULTILINKHEADERFMT", TY_MULTILINKHEADERFMT, 0, 0, FALSE },
101: { "INTERNAT", TY_INTERNAT, 0, 0, FALSE },
102: { "SDATALINKSONET", TY_SDATALINKSONET, 0, 0, FALSE },
103: { NULL }
104: };
105:
106: static struct fsmtype gLcpFsmType = {
107: "LCP", /* Name of protocol */
108: PROTO_LCP, /* Protocol Number */
109: LCP_KNOWN_CODES,
110: TRUE,
111: LG_LCP, LG_LCP2,
112: LcpNewState,
113: NULL,
114: LcpLayerDown,
115: LcpLayerStart,
116: LcpLayerFinish,
117: LcpBuildConfigReq,
118: LcpDecodeConfig,
119: LcpConfigure,
120: NULL,
121: NULL,
122: NULL,
123: NULL,
124: LcpRecvProtoRej,
125: LcpFailure,
126: NULL,
127: NULL,
128: LcpRecvIdent,
129: };
130:
131: /* List of possible Authentication Protocols */
132: static struct lcpauthproto gLcpAuthProtos[] = {
133: {
134: PROTO_PAP,
135: 0,
136: LINK_CONF_PAP,
137: },
138: {
139: PROTO_CHAP,
140: CHAP_ALG_MD5,
141: LINK_CONF_CHAPMD5
142: },
143: {
144: PROTO_CHAP,
145: CHAP_ALG_MSOFT,
146: LINK_CONF_CHAPMSv1
147: },
148: {
149: PROTO_CHAP,
150: CHAP_ALG_MSOFTv2,
151: LINK_CONF_CHAPMSv2
152: },
153: {
154: PROTO_EAP,
155: 0,
156: LINK_CONF_EAP
157: }
158:
159: };
160:
161: static const char *PhaseNames[] = {
162: "DEAD",
163: "ESTABLISH",
164: "AUTHENTICATE",
165: "NETWORK",
166: "TERMINATE",
167: };
168:
169: /*
170: * LcpInit()
171: */
172:
173: void
174: LcpInit(Link l)
175: {
176: LcpState const lcp = &l->lcp;
177:
178: memset(lcp, 0, sizeof(*lcp));
179: FsmInit(&lcp->fsm, &gLcpFsmType, l);
180: lcp->fsm.conf.echo_int = LCP_ECHO_INTERVAL;
181: lcp->fsm.conf.echo_max = LCP_ECHO_TIMEOUT;
182: lcp->phase = PHASE_DEAD;
183:
184: AuthInit(l);
185: }
186:
187: /*
188: * LcpInst()
189: */
190:
191: void
192: LcpInst(Link l, Link lt)
193: {
194: LcpState const lcp = &l->lcp;
195:
196: memcpy(lcp, <->lcp, sizeof(*lcp));
197: FsmInst(&lcp->fsm, <->lcp.fsm, l);
198: AuthInst(&lcp->auth, <->lcp.auth);
199: }
200:
201: /*
202: * LcpShutdown()
203: */
204:
205: void
206: LcpShutdown(Link l)
207: {
208: AuthShutdown(l);
209: }
210:
211: /*
212: * LcpConfigure()
213: */
214:
215: static void
216: LcpConfigure(Fsm fp)
217: {
218: Link l = (Link)fp->arg;
219: LcpState const lcp = &l->lcp;
220: short i;
221:
222: /* FSM stuff */
223: lcp->fsm.conf.passive = Enabled(&l->conf.options, LINK_CONF_PASSIVE);
224: lcp->fsm.conf.check_magic =
225: Enabled(&l->conf.options, LINK_CONF_CHECK_MAGIC);
226: lcp->peer_reject = 0;
227:
228: /* Initialize normal LCP stuff */
1.1.1.2 ! misho 229: lcp->peer_mru = PhysGetMtu(l, 1);
! 230: lcp->want_mru = PhysGetMru(l, 1);
! 231: if (l->type && (lcp->want_mru > PhysGetMru(l, 0)))
! 232: lcp->want_mru = PhysGetMru(l, 0);
1.1 misho 233: lcp->peer_accmap = 0xffffffff;
234: lcp->want_accmap = l->conf.accmap;
235: lcp->peer_acfcomp = FALSE;
236: lcp->want_acfcomp = Enabled(&l->conf.options, LINK_CONF_ACFCOMP);
237: lcp->peer_protocomp = FALSE;
238: lcp->want_protocomp = Enabled(&l->conf.options, LINK_CONF_PROTOCOMP);
239: lcp->peer_magic = 0;
240: lcp->want_magic = Enabled(&l->conf.options,
241: LINK_CONF_MAGICNUM) ? GenerateMagic() : 0;
242: if (l->originate == LINK_ORIGINATE_LOCAL)
243: lcp->want_callback = Enabled(&l->conf.options, LINK_CONF_CALLBACK);
244: else
245: lcp->want_callback = FALSE;
246:
247: /* Authentication stuff */
248: lcp->peer_auth = 0;
249: lcp->want_auth = 0;
250: lcp->peer_alg = 0;
251: lcp->want_alg = 0;
252: lcp->peer_ident[0] = 0;
253:
254: memset(lcp->want_protos, 0, sizeof(lcp->want_protos));
255: /* fill my list of possible auth-protos, most to least secure */
256: /* prefer MS-CHAP to others to get encryption keys */
257: lcp->want_protos[0] = &gLcpAuthProtos[LINK_CONF_CHAPMSv2];
258: lcp->want_protos[1] = &gLcpAuthProtos[LINK_CONF_CHAPMSv1];
259: lcp->want_protos[2] = &gLcpAuthProtos[LINK_CONF_CHAPMD5];
260: lcp->want_protos[3] = &gLcpAuthProtos[LINK_CONF_PAP];
261: lcp->want_protos[4] = &gLcpAuthProtos[LINK_CONF_EAP];
262:
263: /* Use the same list for the MODE_REQ */
264: memcpy(lcp->peer_protos, lcp->want_protos, sizeof(lcp->peer_protos));
265:
266: for (i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
267: if (Enabled(&l->conf.options, lcp->want_protos[i]->conf) && lcp->want_auth == 0) {
268: lcp->want_auth = lcp->want_protos[i]->proto;
269: lcp->want_alg = lcp->want_protos[i]->alg;
270: /* avoid re-requesting this proto, if it was nak'd by the peer */
271: lcp->want_protos[i] = NULL;
272: } else if (!Enabled(&l->conf.options, lcp->want_protos[i]->conf)) {
273: /* don't request disabled Protos */
274: lcp->want_protos[i] = NULL;
275: }
276:
277: /* remove all denied protos */
278: if (!Acceptable(&l->conf.options, lcp->peer_protos[i]->conf))
279: lcp->peer_protos[i] = NULL;
280: }
281:
282: /* Multi-link stuff */
283: lcp->peer_mrru = 0;
284: lcp->peer_shortseq = FALSE;
285: if (Enabled(&l->conf.options, LINK_CONF_MULTILINK)) {
286: lcp->want_mrru = l->conf.mrru;
287: lcp->want_shortseq = Enabled(&l->conf.options, LINK_CONF_SHORTSEQ);
288: } else {
289: lcp->want_mrru = 0;
290: lcp->want_shortseq = FALSE;
291: }
292:
293: /* Peer discriminator */
294: lcp->peer_discrim.class = DISCRIM_CLASS_NULL;
295: lcp->peer_discrim.len = 0;
296: }
297:
298: /*
299: * LcpNewState()
300: *
301: * Keep track of phase shifts
302: */
303:
304: static void
305: LcpNewState(Fsm fp, enum fsm_state old, enum fsm_state new)
306: {
307: Link l = (Link)fp->arg;
308:
309: switch (old) {
310: case ST_INITIAL: /* DEAD */
311: case ST_STARTING:
312: switch (new) {
313: case ST_INITIAL:
314: /* fall through */
315: case ST_STARTING:
316: break;
317: default:
318: LcpNewPhase(l, PHASE_ESTABLISH);
319: break;
320: }
321: break;
322:
323: case ST_CLOSED: /* ESTABLISH */
324: case ST_STOPPED:
325: switch (new) {
326: case ST_INITIAL:
327: case ST_STARTING:
328: LcpNewPhase(l, PHASE_DEAD);
329: break;
330: default:
331: break;
332: }
333: break;
334:
335: case ST_CLOSING: /* TERMINATE */
336: case ST_STOPPING:
337: switch (new) {
338: case ST_INITIAL:
339: case ST_STARTING:
340: LcpNewPhase(l, PHASE_DEAD);
341: break;
342: case ST_CLOSED:
343: case ST_STOPPED:
344: LcpNewPhase(l, PHASE_ESTABLISH);
345: break;
346: default:
347: break;
348: }
349: break;
350:
351: case ST_REQSENT: /* ESTABLISH */
352: case ST_ACKRCVD:
353: case ST_ACKSENT:
354: switch (new) {
355: case ST_INITIAL:
356: case ST_STARTING:
357: LcpNewPhase(l, PHASE_DEAD);
358: break;
359: case ST_CLOSING:
360: case ST_STOPPING:
361: LcpNewPhase(l, PHASE_TERMINATE);
362: break;
363: case ST_OPENED:
364: LcpNewPhase(l, PHASE_AUTHENTICATE);
365: break;
366: default:
367: break;
368: }
369: break;
370:
371: case ST_OPENED: /* AUTHENTICATE, NETWORK */
372: switch (new) {
373: case ST_STARTING:
374: LcpNewPhase(l, PHASE_DEAD);
375: break;
376: case ST_REQSENT:
377: case ST_ACKSENT:
378: LcpNewPhase(l, PHASE_ESTABLISH);
379: break;
380: case ST_CLOSING:
381: case ST_STOPPING:
382: LcpNewPhase(l, PHASE_TERMINATE);
383: break;
384: default:
385: assert(0);
386: }
387: break;
388:
389: default:
390: assert(0);
391: }
392:
393: LinkShutdownCheck(l, new);
394: }
395:
396: /*
397: * LcpNewPhase()
398: */
399:
400: static void
401: LcpNewPhase(Link l, enum lcp_phase new)
402: {
403: LcpState const lcp = &l->lcp;
404: enum lcp_phase old = lcp->phase;
405:
406: /* Logit */
407: Log(LG_LCP2, ("[%s] %s: phase shift %s --> %s",
408: Pref(&lcp->fsm), Fsm(&lcp->fsm), PhaseNames[old], PhaseNames[new]));
409:
410: /* Sanity check transition (The picture on RFC 1661 p. 6 is incomplete) */
411: switch (old) {
412: case PHASE_DEAD:
413: assert(new == PHASE_ESTABLISH);
414: break;
415: case PHASE_ESTABLISH:
416: assert(new == PHASE_DEAD
417: || new == PHASE_TERMINATE
418: || new == PHASE_AUTHENTICATE);
419: break;
420: case PHASE_AUTHENTICATE:
421: assert(new == PHASE_TERMINATE
422: || new == PHASE_ESTABLISH
423: || new == PHASE_NETWORK
424: || new == PHASE_DEAD);
425: break;
426: case PHASE_NETWORK:
427: assert(new == PHASE_TERMINATE
428: || new == PHASE_ESTABLISH
429: || new == PHASE_DEAD);
430: break;
431: case PHASE_TERMINATE:
432: assert(new == PHASE_ESTABLISH
433: || new == PHASE_DEAD);
434: break;
435: default:
436: assert(0);
437: }
438:
439: /* Change phase now */
440: lcp->phase = new;
441:
442: /* Do whatever for leaving old phase */
443: switch (old) {
444: case PHASE_AUTHENTICATE:
445: if (new != PHASE_NETWORK)
446: AuthCleanup(l);
447: break;
448:
449: case PHASE_NETWORK:
450: if (l->joined_bund)
451: BundLeave(l);
452: AuthCleanup(l);
453: break;
454:
455: default:
456: break;
457: }
458:
459: /* Do whatever for entering new phase */
460: switch (new) {
461: case PHASE_ESTABLISH:
462: break;
463:
464: case PHASE_AUTHENTICATE:
465: if (!PhysIsSync(l))
466: PhysSetAccm(l, lcp->peer_accmap, lcp->want_accmap);
467: AuthStart(l);
468: break;
469:
470: case PHASE_NETWORK:
471: /* Send ident string, if configured */
472: if (l->conf.ident != NULL)
473: FsmSendIdent(&lcp->fsm, l->conf.ident);
474:
475: /* Send Time-Remaining if known */
476: if (Enabled(&l->conf.options, LINK_CONF_TIMEREMAIN) &&
477: lcp->auth.params.session_timeout != 0)
478: FsmSendTimeRemaining(&lcp->fsm, lcp->auth.params.session_timeout);
479:
480: /* Join my bundle */
481: if (!BundJoin(l)) {
482: Log(LG_LINK|LG_BUND,
483: ("[%s] link did not validate in bundle",
484: l->name));
485: RecordLinkUpDownReason(NULL, l,
486: 0, STR_PROTO_ERR, "%s", STR_MULTI_FAIL);
487: FsmFailure(&l->lcp.fsm, FAIL_NEGOT_FAILURE);
488: } else {
489: /* If link connection complete, reset redial counter */
490: l->num_redial = 0;
491: }
492: break;
493:
494: case PHASE_TERMINATE:
495: break;
496:
497: case PHASE_DEAD:
498: break;
499:
500: default:
501: assert(0);
502: }
503: }
504:
505: /*
506: * LcpAuthResult()
507: */
508:
509: void
510: LcpAuthResult(Link l, int success)
511: {
512: Log(LG_AUTH|LG_LCP, ("[%s] %s: authorization %s",
513: Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm), success ? "successful" : "failed"));
514: if (success) {
515: if (l->lcp.phase != PHASE_NETWORK)
516: LcpNewPhase(l, PHASE_NETWORK);
517: } else {
518: RecordLinkUpDownReason(NULL, l, 0, STR_LOGIN_FAIL,
519: "%s", STR_PPP_AUTH_FAILURE);
520: FsmFailure(&l->lcp.fsm, FAIL_NEGOT_FAILURE);
521: }
522: }
523:
524: /*
525: * LcpStat()
526: */
527:
528: int
529: LcpStat(Context ctx, int ac, char *av[], void *arg)
530: {
531: Link const l = ctx->lnk;
532: LcpState const lcp = &l->lcp;
533: char buf[64];
534:
535: Printf("%s [%s]\r\n", lcp->fsm.type->name, FsmStateName(lcp->fsm.state));
536:
537: Printf("Self:\r\n");
538: Printf( "\tMRU : %d bytes\r\n"
539: "\tMAGIC : 0x%08x\r\n"
540: "\tACCMAP : 0x%08x\r\n"
541: "\tACFCOMP : %s\r\n"
542: "\tPROTOCOMP: %s\r\n"
543: "\tAUTHTYPE : %s\r\n",
544: (int) lcp->want_mru,
545: (int) lcp->want_magic,
546: (int) lcp->want_accmap,
547: lcp->want_acfcomp ? "Yes" : "No",
548: lcp->want_protocomp ? "Yes" : "No",
549: (lcp->want_auth)?ProtoName(lcp->want_auth):"none");
550:
551: if (lcp->want_mrru) {
552: Printf( "\tMRRU : %d bytes\r\n", (int) lcp->want_mrru);
553: Printf( "\tSHORTSEQ : %s\r\n", lcp->want_shortseq ? "Yes" : "No");
554: Printf( "\tENDPOINTDISC: %s\r\n", MpDiscrimText(&self_discrim, buf, sizeof(buf)));
555: }
556: if (l->conf.ident)
557: Printf( "\tIDENT : %s\r\n", l->conf.ident);
558:
559: Printf("Peer:\r\n");
560: Printf( "\tMRU : %d bytes\r\n"
561: "\tMAGIC : 0x%08x\r\n"
562: "\tACCMAP : 0x%08x\r\n"
563: "\tACFCOMP : %s\r\n"
564: "\tPROTOCOMP: %s\r\n"
565: "\tAUTHTYPE : %s\r\n",
566: (int) lcp->peer_mru,
567: (int) lcp->peer_magic,
568: (int) lcp->peer_accmap,
569: lcp->peer_acfcomp ? "Yes" : "No",
570: lcp->peer_protocomp ? "Yes" : "No",
571: (lcp->peer_auth)?ProtoName(lcp->peer_auth):"none");
572:
573: if (lcp->peer_mrru) {
574: Printf( "\tMRRU : %d bytes\r\n", (int) lcp->peer_mrru);
575: Printf( "\tSHORTSEQ : %s\r\n", lcp->peer_shortseq ? "Yes" : "No");
576: Printf( "\tENDPOINTDISC: %s\r\n", MpDiscrimText(&lcp->peer_discrim, buf, sizeof(buf)));
577: }
578: if (lcp->peer_ident[0])
579: Printf( "\tIDENT : %s\r\n", lcp->peer_ident);
580:
581: return(0);
582: }
583:
584: /*
585: * LcpBuildConfigReq()
586: */
587:
588: static u_char *
589: LcpBuildConfigReq(Fsm fp, u_char *cp)
590: {
591: Link l = (Link)fp->arg;
592: LcpState const lcp = &l->lcp;
593:
594: /* Standard stuff */
595: if (lcp->want_acfcomp && !LCP_PEER_REJECTED(lcp, TY_ACFCOMP))
596: cp = FsmConfValue(cp, TY_ACFCOMP, 0, NULL);
597: if (lcp->want_protocomp && !LCP_PEER_REJECTED(lcp, TY_PROTOCOMP))
598: cp = FsmConfValue(cp, TY_PROTOCOMP, 0, NULL);
599: if ((!PhysIsSync(l)) && (!LCP_PEER_REJECTED(lcp, TY_ACCMAP)))
600: cp = FsmConfValue(cp, TY_ACCMAP, -4, &lcp->want_accmap);
601: if (!LCP_PEER_REJECTED(lcp, TY_MRU))
602: cp = FsmConfValue(cp, TY_MRU, -2, &lcp->want_mru);
603: if (lcp->want_magic && !LCP_PEER_REJECTED(lcp, TY_MAGICNUM))
604: cp = FsmConfValue(cp, TY_MAGICNUM, -4, &lcp->want_magic);
605: if (lcp->want_callback && !LCP_PEER_REJECTED(lcp, TY_CALLBACK)) {
606: struct {
607: u_char op;
608: u_char data[0];
609: } s_callback;
610:
611: s_callback.op = 0;
612: cp = FsmConfValue(cp, TY_CALLBACK, 1, &s_callback);
613: }
614:
615: /* Authorization stuff */
616: switch (lcp->want_auth) {
617: case PROTO_PAP:
618: case PROTO_EAP:
619: cp = FsmConfValue(cp, TY_AUTHPROTO, -2, &lcp->want_auth);
620: break;
621: case PROTO_CHAP: {
622: struct {
623: u_short want_auth;
624: u_char alg;
625: } s_mdx;
626:
627: s_mdx.want_auth = htons(PROTO_CHAP);
628: s_mdx.alg = lcp->want_alg;
629: cp = FsmConfValue(cp, TY_AUTHPROTO, 3, &s_mdx);
630: }
631: break;
632: }
633:
634: /* Multi-link stuff */
635: if (Enabled(&l->conf.options, LINK_CONF_MULTILINK)
636: && !LCP_PEER_REJECTED(lcp, TY_MRRU)) {
637: cp = FsmConfValue(cp, TY_MRRU, -2, &lcp->want_mrru);
638: if (lcp->want_shortseq && !LCP_PEER_REJECTED(lcp, TY_SHORTSEQNUM))
639: cp = FsmConfValue(cp, TY_SHORTSEQNUM, 0, NULL);
640: if (!LCP_PEER_REJECTED(lcp, TY_ENDPOINTDISC))
641: cp = FsmConfValue(cp, TY_ENDPOINTDISC, 1 + self_discrim.len, &self_discrim.class);
642: }
643:
644: /* Done */
645: return(cp);
646: }
647:
648: static void
649: LcpLayerStart(Fsm fp)
650: {
651: Link l = (Link)fp->arg;
652:
653: LinkNgInit(l);
654: if (!TimerStarted(&l->openTimer))
655: PhysOpen(l);
656: }
657:
658: static void
659: LcpStopActivity(Link l)
660: {
661: AuthStop(l);
662: }
663:
664: static void
665: LcpLayerFinish(Fsm fp)
666: {
667: Link l = (Link)fp->arg;
668:
669: LcpStopActivity(l);
670: if (!l->rep) {
671: PhysClose(l);
672: LinkNgShutdown(l);
673: }
674: }
675:
676: /*
677: * LcpLayerDown()
678: */
679:
680: static void
681: LcpLayerDown(Fsm fp)
682: {
683: Link l = (Link)fp->arg;
684: LcpStopActivity(l);
685: }
686:
687: void LcpOpen(Link l)
688: {
689: FsmOpen(&l->lcp.fsm);
690: }
691:
692: void LcpClose(Link l)
693: {
694: FsmClose(&l->lcp.fsm);
695: }
696:
697: void LcpUp(Link l)
698: {
699: FsmUp(&l->lcp.fsm);
700: }
701:
702: void LcpDown(Link l)
703: {
704: FsmDown(&l->lcp.fsm);
705: }
706:
707: /*
708: * LcpRecvProtoRej()
709: */
710:
711: static int
712: LcpRecvProtoRej(Fsm fp, int proto, Mbuf bp)
713: {
714: Link l = (Link)fp->arg;
715: int fatal = FALSE;
716: Fsm rej = NULL;
717:
718: /* Which protocol? */
719: switch (proto) {
720: case PROTO_CCP:
721: case PROTO_COMPD:
722: rej = l->bund ? &l->bund->ccp.fsm : NULL;
723: break;
724: case PROTO_ECP:
725: case PROTO_CRYPT:
726: rej = l->bund ? &l->bund->ecp.fsm : NULL;
727: break;
728: case PROTO_IPCP:
729: rej = l->bund ? &l->bund->ipcp.fsm : NULL;
730: break;
731: case PROTO_IPV6CP:
732: rej = l->bund ? &l->bund->ipv6cp.fsm : NULL;
733: break;
734: default:
735: break;
736: }
737:
738: /* Turn off whatever protocol got rejected */
739: if (rej)
740: FsmFailure(rej, FAIL_WAS_PROTREJ);
741: return(fatal);
742: }
743:
744: /*
745: * LcpRecvIdent()
746: */
747:
748: static void
749: LcpRecvIdent(Fsm fp, Mbuf bp)
750: {
751: Link l = (Link)fp->arg;
752: int len, clen;
753:
754: if (bp == NULL)
755: return;
756:
757: if (l->lcp.peer_ident[0] != 0)
758: strlcat(l->lcp.peer_ident, " ", sizeof(l->lcp.peer_ident));
759:
760: len = strlen(l->lcp.peer_ident);
761: clen = sizeof(l->lcp.peer_ident) - len - 1;
762: if (clen > MBLEN(bp))
763: clen = MBLEN(bp);
764: memcpy(l->lcp.peer_ident + len, (char *) MBDATAU(bp), clen);
765: l->lcp.peer_ident[len + clen] = 0;
766: }
767:
768: /*
769: * LcpFailure()
770: */
771:
772: static void
773: LcpFailure(Fsm fp, enum fsmfail reason)
774: {
775: Link l = (Link)fp->arg;
776: char buf[100];
777:
778: snprintf(buf, sizeof(buf), STR_LCP_FAILED, FsmFailureStr(reason));
779: RecordLinkUpDownReason(NULL, l, 0, reason == FAIL_ECHO_TIMEOUT ?
780: STR_ECHO_TIMEOUT : STR_PROTO_ERR, "%s", buf);
781: }
782:
783: /*
784: * LcpDecodeConfig()
785: */
786:
787: static void
788: LcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode)
789: {
790: Link l = (Link)fp->arg;
791: LcpState const lcp = &l->lcp;
792: int k;
793:
794: /* If we have got request, forget the previous values */
795: if (mode == MODE_REQ) {
1.1.1.2 ! misho 796: lcp->peer_mru = PhysGetMtu(l, 1);
1.1 misho 797: lcp->peer_accmap = 0xffffffff;
798: lcp->peer_acfcomp = FALSE;
799: lcp->peer_protocomp = FALSE;
800: lcp->peer_magic = 0;
801: lcp->peer_auth = 0;
802: lcp->peer_alg = 0;
803: lcp->peer_mrru = 0;
804: lcp->peer_shortseq = FALSE;
805: }
806:
807: /* Decode each config option */
808: for (k = 0; k < num; k++) {
809: FsmOption const opt = &list[k];
810: FsmOptInfo const oi = FsmFindOptInfo(gLcpConfOpts, opt->type);
811:
812: /* Check option */
813: if (!oi) {
814: Log(LG_LCP, ("[%s] UNKNOWN[%d] len=%d", l->name, opt->type, opt->len));
815: if (mode == MODE_REQ)
816: FsmRej(fp, opt);
817: continue;
818: }
819: if (!oi->supported) {
820: Log(LG_LCP, ("[%s] %s", l->name, oi->name));
821: if (mode == MODE_REQ) {
822: Log(LG_LCP, ("[%s] Not supported", l->name));
823: FsmRej(fp, opt);
824: }
825: continue;
826: }
827: if (opt->len < oi->minLen + 2 || opt->len > oi->maxLen + 2) {
828: Log(LG_LCP, ("[%s] %s", l->name, oi->name));
829: if (mode == MODE_REQ) {
830: Log(LG_LCP, ("[%s] Bogus length=%d", l->name, opt->len));
831: FsmRej(fp, opt);
832: }
833: continue;
834: }
835:
836: /* Do whatever */
837: switch (opt->type) {
838: case TY_MRU: /* link MRU */
839: {
840: u_int16_t mru;
841:
842: memcpy(&mru, opt->data, 2);
843: mru = ntohs(mru);
844: Log(LG_LCP, ("[%s] %s %d", l->name, oi->name, mru));
845: switch (mode) {
846: case MODE_REQ:
847: if (mru < LCP_MIN_MRU) {
848: mru = htons(LCP_MIN_MRU);
849: memcpy(opt->data, &mru, 2);
850: FsmNak(fp, opt);
851: break;
852: }
853: if (mru < lcp->peer_mru)
854: lcp->peer_mru = mru;
855: FsmAck(fp, opt);
856: break;
857: case MODE_NAK:
858: /* Windows 2000 PPPoE bug workaround */
859: if (mru == lcp->want_mru) {
860: LCP_PEER_REJ(lcp, opt->type);
861: break;
862: }
863: if (mru >= LCP_MIN_MRU
864: && (mru <= l->type->mru || mru < lcp->want_mru))
865: lcp->want_mru = mru;
866: break;
867: case MODE_REJ:
868: LCP_PEER_REJ(lcp, opt->type);
869: break;
870: }
871: }
872: break;
873:
874: case TY_ACCMAP: /* async control character escape map */
875: {
876: u_int32_t accm;
877:
878: memcpy(&accm, opt->data, 4);
879: accm = ntohl(accm);
880: Log(LG_LCP, ("[%s] %s 0x%08x", l->name, oi->name, accm));
881: switch (mode) {
882: case MODE_REQ:
883: lcp->peer_accmap = accm;
884: FsmAck(fp, opt);
885: break;
886: case MODE_NAK:
887: lcp->want_accmap = accm;
888: break;
889: case MODE_REJ:
890: LCP_PEER_REJ(lcp, opt->type);
891: break;
892: }
893: }
894: break;
895:
896: case TY_AUTHPROTO: /* authentication protocol */
897: {
898: u_int16_t proto;
899: int bogus = 0, i, protoPos = -1;
900: LcpAuthProto authProto = NULL;
901:
902: memcpy(&proto, opt->data, 2);
903: proto = ntohs(proto);
904:
905: /* Display it */
906: switch (proto) {
907: case PROTO_CHAP:
908: if (opt->len >= 5) {
909: char buf[20];
910: const char *ts;
911:
912: switch (opt->data[2]) {
913: case CHAP_ALG_MD5:
914: ts = "MD5";
915: break;
916: case CHAP_ALG_MSOFT:
917: ts = "MSOFT";
918: break;
919: case CHAP_ALG_MSOFTv2:
920: ts = "MSOFTv2";
921: break;
922: default:
923: snprintf(buf, sizeof(buf), "0x%02x", opt->data[2]);
924: ts = buf;
925: break;
926: }
927: Log(LG_LCP, ("[%s] %s %s %s", l->name, oi->name, ProtoName(proto), ts));
928: break;
929: }
930: break;
931: default:
932: Log(LG_LCP, ("[%s] %s %s", l->name, oi->name, ProtoName(proto)));
933: break;
934: }
935:
936: /* Sanity check */
937: switch (proto) {
938: case PROTO_PAP:
939: if (opt->len != 4) {
940: Log(LG_LCP, ("[%s] Bad len=%d", l->name, opt->len));
941: bogus = 1;
942: }
943: break;
944: case PROTO_CHAP:
945: if (opt->len != 5) {
946: Log(LG_LCP, ("[%s] Bad len=%d", l->name, opt->len));
947: bogus = 1;
948: }
949: break;
950: }
951: if (!bogus) {
952: protoPos = LcpFindAuthProto(proto, proto == PROTO_CHAP ? opt->data[2] : 0);
953: authProto = (protoPos == -1) ? NULL : &gLcpAuthProtos[protoPos];
954: }
955:
956: /* Deal with it */
957: switch (mode) {
958: case MODE_REQ:
959:
960: /* let us check, whether the requested auth-proto is acceptable */
961: if ((authProto != NULL) && Acceptable(&l->conf.options, authProto->conf)) {
962: lcp->peer_auth = proto;
963: if (proto == PROTO_CHAP)
964: lcp->peer_alg = opt->data[2];
965: FsmAck(fp, opt);
966: break;
967: }
968:
969: /* search an acceptable proto */
970: for(i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
971: if (lcp->peer_protos[i] != NULL) {
972: FsmNak(fp, LcpAuthProtoNak(lcp->peer_protos[i]->proto, lcp->peer_protos[i]->alg));
973: break;
974: }
975: }
976:
977: /* no other acceptable auth-proto found */
978: if (i == LCP_NUM_AUTH_PROTOS)
979: FsmRej(fp, opt);
980: break;
981:
982: case MODE_NAK:
983: /* this should never happen */
984: if (authProto == NULL)
985: break;
986:
987: /* let us check, whether the requested auth-proto is enabled */
988: if (Enabled(&l->conf.options, authProto->conf)) {
989: lcp->want_auth = proto;
990: if (proto == PROTO_CHAP)
991: lcp->want_alg = opt->data[2];
992: break;
993: }
994:
995: /* Remove the disabled proto from my list */
996: lcp->want_protos[protoPos] = NULL;
997:
998: /* Search the next enabled proto */
999: for(i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
1000: if (lcp->want_protos[i] != NULL) {
1001: lcp->want_auth = lcp->want_protos[i]->proto;
1002: lcp->want_alg = lcp->want_protos[i]->alg;
1003: break;
1004: }
1005: }
1006: break;
1007:
1008: case MODE_REJ:
1009: LCP_PEER_REJ(lcp, opt->type);
1010: if (l->originate == LINK_ORIGINATE_LOCAL
1011: && Enabled(&l->conf.options, LINK_CONF_NO_ORIG_AUTH)) {
1012: lcp->want_auth = 0;
1013: }
1014: break;
1015: }
1016: }
1017: break;
1018:
1019: case TY_MRRU: /* multi-link MRRU */
1020: {
1021: u_int16_t mrru;
1022:
1023: memcpy(&mrru, opt->data, 2);
1024: mrru = ntohs(mrru);
1025: Log(LG_LCP, ("[%s] %s %d", l->name, oi->name, mrru));
1026: switch (mode) {
1027: case MODE_REQ:
1028: if (!Enabled(&l->conf.options, LINK_CONF_MULTILINK)) {
1029: FsmRej(fp, opt);
1030: break;
1031: }
1032: if (mrru < MP_MIN_MRRU) {
1033: mrru = htons(MP_MIN_MRRU);
1034: memcpy(opt->data, &mrru, 2);
1035: FsmNak(fp, opt);
1036: break;
1037: }
1038: lcp->peer_mrru = mrru;
1039: FsmAck(fp, opt);
1040: break;
1041: case MODE_NAK:
1042: {
1043: /* Let the peer to change it's mind. */
1044: if (LCP_PEER_REJECTED(lcp, opt->type)) {
1045: LCP_PEER_UNREJ(lcp, opt->type);
1046: if (Enabled(&l->conf.options, LINK_CONF_MULTILINK))
1047: lcp->want_mrru = l->conf.mrru;
1048: }
1049: /* Make sure we don't violate any rules by changing MRRU now */
1050: if (mrru > lcp->want_mrru) /* too big */
1051: break;
1052: if (mrru < MP_MIN_MRRU) /* too small; clip */
1053: mrru = MP_MIN_MRRU;
1054:
1055: /* Update our links */
1056: lcp->want_mrru = mrru;
1057: }
1058: break;
1059: case MODE_REJ:
1060: lcp->want_mrru = 0;
1061: LCP_PEER_REJ(lcp, opt->type);
1062: break;
1063: }
1064: }
1065: break;
1066:
1067: case TY_SHORTSEQNUM: /* multi-link short sequence numbers */
1068: Log(LG_LCP, ("[%s] %s", l->name, oi->name));
1069: switch (mode) {
1070: case MODE_REQ:
1071: if (!Enabled(&l->conf.options, LINK_CONF_MULTILINK) ||
1072: !Acceptable(&l->conf.options, LINK_CONF_SHORTSEQ)) {
1073: FsmRej(fp, opt);
1074: break;
1075: }
1076: lcp->peer_shortseq = TRUE;
1077: FsmAck(fp, opt);
1078: break;
1079: case MODE_NAK:
1080: /* Let the peer to change it's mind. */
1081: if (LCP_PEER_REJECTED(lcp, opt->type)) {
1082: LCP_PEER_UNREJ(lcp, opt->type);
1083: if (Enabled(&l->conf.options, LINK_CONF_MULTILINK))
1084: lcp->want_shortseq = Enabled(&l->conf.options, LINK_CONF_SHORTSEQ);
1085: }
1086: break;
1087: case MODE_REJ:
1088: lcp->want_shortseq = FALSE;
1089: LCP_PEER_REJ(lcp, opt->type);
1090: break;
1091: }
1092: break;
1093:
1094: case TY_ENDPOINTDISC: /* multi-link endpoint discriminator */
1095: {
1096: struct discrim dis;
1097: char buf[64];
1098:
1099: if (opt->len < 3 || opt->len > sizeof(dis.bytes)) {
1100: Log(LG_LCP, ("[%s] %s bad len=%d", l->name, oi->name, opt->len));
1101: if (mode == MODE_REQ)
1102: FsmRej(fp, opt);
1103: break;
1104: }
1105: memcpy(&dis.class, opt->data, opt->len - 2);
1106: dis.len = opt->len - 3;
1107: Log(LG_LCP, ("[%s] %s %s", l->name, oi->name, MpDiscrimText(&dis, buf, sizeof(buf))));
1108: switch (mode) {
1109: case MODE_REQ:
1110: lcp->peer_discrim = dis;
1111: FsmAck(fp, opt);
1112: break;
1113: case MODE_NAK:
1114: /* Let the peer to change it's mind. */
1115: LCP_PEER_UNREJ(lcp, opt->type);
1116: break;
1117: case MODE_REJ:
1118: LCP_PEER_REJ(lcp, opt->type);
1119: break;
1120: }
1121: }
1122: break;
1123:
1124: case TY_MAGICNUM: /* magic number */
1125: {
1126: u_int32_t magic;
1127:
1128: memcpy(&magic, opt->data, 4);
1129: magic = ntohl(magic);
1.1.1.2 ! misho 1130: Log(LG_LCP, ("[%s] %s 0x%08x", l->name, oi->name, magic));
1.1 misho 1131: switch (mode) {
1132: case MODE_REQ:
1133: if (lcp->want_magic) {
1134: if (magic == lcp->want_magic) {
1135: Log(LG_LCP, ("[%s] Same magic! Detected loopback condition", l->name));
1136: magic = htonl(~magic);
1137: memcpy(opt->data, &magic, 4);
1138: FsmNak(fp, opt);
1139: break;
1140: }
1141: lcp->peer_magic = magic;
1142: FsmAck(fp, opt);
1143: break;
1144: }
1145: FsmRej(fp, opt);
1146: break;
1147: case MODE_NAK:
1148: lcp->want_magic = GenerateMagic();
1149: break;
1150: case MODE_REJ:
1151: lcp->want_magic = 0;
1152: LCP_PEER_REJ(lcp, opt->type);
1153: break;
1154: }
1155: }
1156: break;
1157:
1158: case TY_PROTOCOMP: /* Protocol field compression */
1159: Log(LG_LCP, ("[%s] %s", l->name, oi->name));
1160: switch (mode) {
1161: case MODE_REQ:
1162: if (Acceptable(&l->conf.options, LINK_CONF_PROTOCOMP)) {
1163: lcp->peer_protocomp = TRUE;
1164: FsmAck(fp, opt);
1165: break;
1166: }
1167: FsmRej(fp, opt);
1168: break;
1169: case MODE_NAK: /* a NAK here doesn't make sense */
1170: case MODE_REJ:
1171: lcp->want_protocomp = FALSE;
1172: LCP_PEER_REJ(lcp, opt->type);
1173: break;
1174: }
1175: break;
1176:
1177: case TY_ACFCOMP: /* Address field compression */
1178: Log(LG_LCP, ("[%s] %s", l->name, oi->name));
1179: switch (mode) {
1180: case MODE_REQ:
1181: if (Acceptable(&l->conf.options, LINK_CONF_ACFCOMP)) {
1182: lcp->peer_acfcomp = TRUE;
1183: FsmAck(fp, opt);
1184: break;
1185: }
1186: FsmRej(fp, opt);
1187: break;
1188: case MODE_NAK: /* a NAK here doesn't make sense */
1189: case MODE_REJ:
1190: lcp->want_acfcomp = FALSE;
1191: LCP_PEER_REJ(lcp, opt->type);
1192: break;
1193: }
1194: break;
1195:
1196: case TY_CALLBACK: /* Callback */
1197: Log(LG_LCP, ("[%s] %s %d", l->name, oi->name, opt->data[0]));
1198: switch (mode) {
1199: case MODE_REQ: /* we only support peer calling us back */
1200: FsmRej(fp, opt);
1201: break;
1202: case MODE_NAK: /* we only know one way to do it */
1203: /* fall through */
1204: case MODE_REJ:
1205: lcp->want_callback = FALSE;
1206: LCP_PEER_REJ(lcp, opt->type);
1207: break;
1208: }
1209: break;
1210:
1211: case TY_VENDOR:
1212: {
1213: Log(LG_LCP, ("[%s] %s %02x%02x%02x:%d", l->name, oi->name,
1214: opt->data[0], opt->data[1], opt->data[2], opt->data[3]));
1215: switch (mode) {
1216: case MODE_REQ:
1217: FsmRej(fp, opt);
1218: break;
1219: case MODE_NAK:
1220: /* fall through */
1221: case MODE_REJ:
1222: LCP_PEER_REJ(lcp, opt->type);
1223: break;
1224: }
1225: break;
1226: }
1227: break;
1228:
1229: default:
1230: assert(0);
1231: }
1232: }
1233: }
1234:
1235: /*
1236: * LcpInput()
1237: */
1238:
1239: void
1240: LcpInput(Link l, Mbuf bp)
1241: {
1242: FsmInput(&l->lcp.fsm, bp);
1243: }
1244:
1245: static const struct fsmoption *
1246: LcpAuthProtoNak(ushort proto, u_char alg)
1247: {
1248: static const u_char chapmd5cf[] =
1249: { PROTO_CHAP >> 8, PROTO_CHAP & 0xff, CHAP_ALG_MD5 };
1250: static const struct fsmoption chapmd5Nak =
1251: { TY_AUTHPROTO, 2 + sizeof(chapmd5cf), (u_char *) chapmd5cf };
1252:
1253: static const u_char chapmsv1cf[] =
1254: { PROTO_CHAP >> 8, PROTO_CHAP & 0xff, CHAP_ALG_MSOFT };
1255: static const struct fsmoption chapmsv1Nak =
1256: { TY_AUTHPROTO, 2 + sizeof(chapmsv1cf), (u_char *) chapmsv1cf };
1257:
1258: static const u_char chapmsv2cf[] =
1259: { PROTO_CHAP >> 8, PROTO_CHAP & 0xff, CHAP_ALG_MSOFTv2 };
1260: static const struct fsmoption chapmsv2Nak =
1261: { TY_AUTHPROTO, 2 + sizeof(chapmsv2cf), (u_char *) chapmsv2cf };
1262:
1263: static const u_char papcf[] =
1264: { PROTO_PAP >> 8, PROTO_PAP & 0xff };
1265: static const struct fsmoption papNak =
1266: { TY_AUTHPROTO, 2 + sizeof(papcf), (u_char *) papcf };
1267:
1268: static const u_char eapcf[] =
1269: { PROTO_EAP >> 8, PROTO_EAP & 0xff };
1270: static const struct fsmoption eapNak =
1271: { TY_AUTHPROTO, 2 + sizeof(eapcf), (u_char *) eapcf };
1272:
1273: if (proto == PROTO_PAP) {
1274: return &papNak;
1275: } else if (proto == PROTO_EAP) {
1276: return &eapNak;
1277: } else {
1278: switch (alg) {
1279: case CHAP_ALG_MSOFTv2:
1280: return &chapmsv2Nak;
1281:
1282: case CHAP_ALG_MSOFT:
1283: return &chapmsv1Nak;
1284:
1285: case CHAP_ALG_MD5:
1286: return &chapmd5Nak;
1287:
1288: default:
1289: return NULL;
1290: }
1291: }
1292:
1293: }
1294:
1295: /*
1296: * LcpFindAuthProto()
1297: *
1298: */
1299: static short
1300: LcpFindAuthProto(ushort proto, u_char alg)
1301: {
1302: int i;
1303:
1304: for(i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
1305: if (gLcpAuthProtos[i].proto == proto && gLcpAuthProtos[i].alg == alg) {
1306: return i;
1307: }
1308: }
1309:
1310: return -1;
1311:
1312: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>