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