Annotation of embedaddon/mpd/src/ipcp.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * ipcp.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 "ipcp.h"
16: #include "fsm.h"
17: #include "ip.h"
18: #include "iface.h"
19: #include "msg.h"
20: #include "ngfunc.h"
21: #include "ippool.h"
22: #include "util.h"
23:
24: #include <netgraph.h>
25: #include <sys/mbuf.h>
26: #ifdef USE_NG_VJC
27: #include <net/slcompress.h>
28: #include <netgraph/ng_vjc.h>
29: #endif
30:
31: /*
32: * DEFINITIONS
33: */
34:
35: #define IPCP_KNOWN_CODES ( (1 << CODE_CONFIGREQ) \
36: | (1 << CODE_CONFIGACK) \
37: | (1 << CODE_CONFIGNAK) \
38: | (1 << CODE_CONFIGREJ) \
39: | (1 << CODE_TERMREQ) \
40: | (1 << CODE_TERMACK) \
41: | (1 << CODE_CODEREJ) )
42:
43: #define TY_IPADDRS 1
44: #define TY_COMPPROTO 2
45: #define TY_IPADDR 3
46: #define TY_PRIMARYDNS 129
47: #define TY_PRIMARYNBNS 130
48: #define TY_SECONDARYDNS 131
49: #define TY_SECONDARYNBNS 132
50:
51: /* Keep sync with above */
52: #define o2b(x) (((x)<128)?(x):(x)-128+3)
53:
54: #define IPCP_REJECTED(p,x) ((p)->peer_reject & (1<<o2b(x)))
55: #define IPCP_PEER_REJ(p,x) do{(p)->peer_reject |= (1<<o2b(x));}while(0)
56:
57: #ifdef USE_NG_VJC
58: #define IPCP_VJCOMP_MIN_MAXCHAN (NG_VJC_MIN_CHANNELS - 1)
59: #define IPCP_VJCOMP_MAX_MAXCHAN (NG_VJC_MAX_CHANNELS - 1)
60: #define IPCP_VJCOMP_DEFAULT_MAXCHAN IPCP_VJCOMP_MAX_MAXCHAN
61: #endif
62:
63: /* Set menu options */
64: enum {
65: SET_RANGES,
66: SET_ENABLE,
67: SET_DNS,
68: SET_NBNS,
69: SET_DISABLE,
70: SET_ACCEPT,
71: SET_DENY,
72: SET_YES,
73: SET_NO
74: };
75:
76: /*
77: * INTERNAL FUNCTIONS
78: */
79:
80: static void IpcpConfigure(Fsm fp);
81: static void IpcpUnConfigure(Fsm fp);
82:
83: static u_char *IpcpBuildConfigReq(Fsm fp, u_char *cp);
84: static void IpcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode);
85: static void IpcpLayerStart(Fsm fp);
86: static void IpcpLayerFinish(Fsm fp);
87: static void IpcpLayerUp(Fsm fp);
88: static void IpcpLayerDown(Fsm fp);
89: static void IpcpFailure(Fsm fp, enum fsmfail reason);
90:
91: #ifdef USE_NG_VJC
92: static int IpcpNgInitVJ(Bund b);
93: static void IpcpNgShutdownVJ(Bund b);
94: #endif
95:
96: static int IpcpSetCommand(Context ctx, int ac, char *av[], void *arg);
97:
98: /*
99: * GLOBAL VARIABLES
100: */
101:
102: const struct cmdtab IpcpSetCmds[] = {
103: { "ranges {self}[/{width}]|ippool {pool} {peer}[/{width}]|ippool {pool}", "Allowed IP address ranges",
104: IpcpSetCommand, NULL, 2, (void *) SET_RANGES },
105: { "enable [opt ...]", "Enable option",
106: IpcpSetCommand, NULL, 2, (void *) SET_ENABLE},
107: { "dns primary [secondary]", "Set peer DNS servers",
108: IpcpSetCommand, NULL, 2, (void *) SET_DNS},
109: { "nbns primary [secondary]", "Set peer NBNS servers",
110: IpcpSetCommand, NULL, 2, (void *) SET_NBNS},
111: { "disable [opt ...]", "Disable option",
112: IpcpSetCommand, NULL, 2, (void *) SET_DISABLE},
113: { "accept [opt ...]", "Accept option",
114: IpcpSetCommand, NULL, 2, (void *) SET_ACCEPT},
115: { "deny [opt ...]", "Deny option",
116: IpcpSetCommand, NULL, 2, (void *) SET_DENY},
117: { "yes [opt ...]", "Enable and accept option",
118: IpcpSetCommand, NULL, 2, (void *) SET_YES},
119: { "no [opt ...]", "Disable and deny option",
120: IpcpSetCommand, NULL, 2, (void *) SET_NO},
121: { NULL },
122: };
123:
124: /*
125: * INTERNAL VARIABLES
126: */
127:
128: static const struct fsmoptinfo gIpcpConfOpts[] = {
129: { "IPADDRS", TY_IPADDRS, 8, 8, FALSE },
130: #ifdef USE_NG_VJC
131: { "COMPPROTO", TY_COMPPROTO, 4, 4, TRUE },
132: #endif
133: { "IPADDR", TY_IPADDR, 4, 4, TRUE },
134: { "PRIDNS", TY_PRIMARYDNS, 4, 4, TRUE },
135: { "PRINBNS", TY_PRIMARYNBNS, 4, 4, TRUE },
136: { "SECDNS", TY_SECONDARYDNS, 4, 4, TRUE },
137: { "SECNBNS", TY_SECONDARYNBNS, 4, 4, TRUE },
138: { NULL }
139: };
140:
141: static const struct confinfo gConfList[] = {
142: #ifdef USE_NG_VJC
143: { 1, IPCP_CONF_VJCOMP, "vjcomp" },
144: #endif
145: { 0, IPCP_CONF_REQPRIDNS, "req-pri-dns" },
146: { 0, IPCP_CONF_REQSECDNS, "req-sec-dns" },
147: { 0, IPCP_CONF_REQPRINBNS, "req-pri-nbns" },
148: { 0, IPCP_CONF_REQSECNBNS, "req-sec-nbns" },
149: { 0, IPCP_CONF_PRETENDIP, "pretend-ip" },
150: { 0, 0, NULL },
151: };
152:
153: static const struct fsmtype gIpcpFsmType = {
154: "IPCP",
155: PROTO_IPCP,
156: IPCP_KNOWN_CODES,
157: FALSE,
158: LG_IPCP, LG_IPCP2,
159: NULL,
160: IpcpLayerUp,
161: IpcpLayerDown,
162: IpcpLayerStart,
163: IpcpLayerFinish,
164: IpcpBuildConfigReq,
165: IpcpDecodeConfig,
166: IpcpConfigure,
167: IpcpUnConfigure,
168: NULL,
169: NULL,
170: NULL,
171: NULL,
172: IpcpFailure,
173: NULL,
174: NULL,
175: NULL,
176: };
177:
178: /*
179: * IpcpStat()
180: */
181:
182: int
183: IpcpStat(Context ctx, int ac, char *av[], void *arg)
184: {
185: #ifdef USE_NG_VJC
186: char path[NG_PATHSIZ];
187: #endif
188: IpcpState const ipcp = &ctx->bund->ipcp;
189: Fsm fp = &ipcp->fsm;
190: #ifdef USE_NG_VJC
191: union {
192: u_char buf[sizeof(struct ng_mesg) + sizeof(struct slcompress)];
193: struct ng_mesg reply;
194: } u;
195: struct slcompress *const sls = (struct slcompress *)(void *)u.reply.data;
196: #endif
197: char buf[48];
198:
199: Printf("[%s] %s [%s]\r\n", Pref(fp), Fsm(fp), FsmStateName(fp->state));
200: Printf("Allowed IP address ranges:\r\n");
201: if (ipcp->conf.self_ippool[0]) {
202: Printf("\tPeer: ippool %s\r\n",
203: ipcp->conf.self_ippool);
204: } else {
205: Printf("\tSelf: %s\r\n",
206: u_rangetoa(&ipcp->conf.self_allow,buf,sizeof(buf)));
207: }
208: if (ipcp->conf.ippool[0]) {
209: Printf("\tPeer: ippool %s\r\n",
210: ipcp->conf.ippool);
211: } else {
212: Printf("\tPeer: %s\r\n",
213: u_rangetoa(&ipcp->conf.peer_allow,buf,sizeof(buf)));
214: }
215: Printf("IPCP Options:\r\n");
216: OptStat(ctx, &ipcp->conf.options, gConfList);
217: Printf("Current addressing:\r\n");
218: Printf("\tSelf: %s\r\n", inet_ntoa(ipcp->want_addr));
219: Printf("\tPeer: %s\r\n", inet_ntoa(ipcp->peer_addr));
220: #ifdef USE_NG_VJC
221: Printf("Compression:\r\n");
222: Printf("\tSelf: ");
223: if (ipcp->want_comp.proto != 0)
224: Printf("%s, %d compression channels, CID %scompressible\r\n",
225: ProtoName(ntohs(ipcp->want_comp.proto)),
226: ipcp->want_comp.maxchan + 1, ipcp->want_comp.compcid ? "" : "not ");
227: else
228: Printf("None\r\n");
229: Printf("\tPeer: ");
230: if (ipcp->peer_comp.proto != 0)
231: Printf("%s, %d compression channels, CID %scompressible\n",
232: ProtoName(ntohs(ipcp->peer_comp.proto)),
233: ipcp->peer_comp.maxchan + 1, ipcp->peer_comp.compcid ? "" : "not ");
234: else
235: Printf("None\r\n");
236: #endif /* USE_NG_VJC */
237: Printf("Server info we give to peer:\r\n");
238: Printf("DNS servers : %15s", inet_ntoa(ipcp->conf.peer_dns[0]));
239: Printf(" %15s\r\n", inet_ntoa(ipcp->conf.peer_dns[1]));
240: Printf("NBNS servers: %15s", inet_ntoa(ipcp->conf.peer_nbns[0]));
241: Printf(" %15s\r\n", inet_ntoa(ipcp->conf.peer_nbns[1]));
242: Printf("Server info peer gave to us:\r\n");
243: Printf("DNS servers : %15s", inet_ntoa(ipcp->want_dns[0]));
244: Printf(" %15s\r\n", inet_ntoa(ipcp->want_dns[1]));
245: Printf("NBNS servers: %15s", inet_ntoa(ipcp->want_nbns[0]));
246: Printf(" %15s\r\n", inet_ntoa(ipcp->want_nbns[1]));
247:
248: #ifdef USE_NG_VJC
249: /* Get VJC state */
250: snprintf(path, sizeof(path), "mpd%d-%s:%s", gPid, ctx->bund->name, NG_PPP_HOOK_VJC_IP);
251: if (NgFuncSendQuery(path, NGM_VJC_COOKIE, NGM_VJC_GET_STATE,
252: NULL, 0, &u.reply, sizeof(u), NULL) < 0)
253: return(0);
254:
255: Printf("VJ Compression:\r\n");
256: Printf("\tOut comp : %d\r\n", sls->sls_compressed);
257: Printf("\tOut total: %d\r\n", sls->sls_packets);
258: Printf("\tMissed : %d\r\n", sls->sls_misses);
259: Printf("\tSearched : %d\r\n", sls->sls_searches);
260: Printf("\tIn comp : %d\r\n", sls->sls_compressedin);
261: Printf("\tIn uncomp: %d\r\n", sls->sls_uncompressedin);
262: Printf("\tIn error : %d\r\n", sls->sls_errorin);
263: Printf("\tIn tossed: %d\r\n", sls->sls_tossed);
264: #endif /* USE_NG_VJC */
265: return(0);
266: }
267:
268: /*
269: * IpcpInit()
270: */
271:
272: void
273: IpcpInit(Bund b)
274: {
275: IpcpState const ipcp = &b->ipcp;
276:
277: /* Init state machine */
278: memset(ipcp, 0, sizeof(*ipcp));
279: FsmInit(&ipcp->fsm, &gIpcpFsmType, b);
280:
281: /* Come up with a default IP address for my side of the link */
282: u_rangeclear(&ipcp->conf.self_allow);
283: GetAnyIpAddress(&ipcp->conf.self_allow.addr, NULL);
284:
285: #ifdef USE_NG_VJC
286: /* Default we want VJ comp */
287: Enable(&ipcp->conf.options, IPCP_CONF_VJCOMP);
288: Accept(&ipcp->conf.options, IPCP_CONF_VJCOMP);
289: #endif
290: }
291:
292: /*
293: * IpcpInst()
294: */
295:
296: void
297: IpcpInst(Bund b, Bund bt)
298: {
299: IpcpState const ipcp = &b->ipcp;
300:
301: /* Init state machine */
302: memcpy(ipcp, &bt->ipcp, sizeof(*ipcp));
303: FsmInst(&ipcp->fsm, &bt->ipcp.fsm, b);
304: }
305:
306: /*
307: * IpcpConfigure()
308: */
309:
310: static void
311: IpcpConfigure(Fsm fp)
312: {
313: Bund b = (Bund)fp->arg;
314: IpcpState const ipcp = &b->ipcp;
315: char buf[48];
316:
317: /* FSM stuff */
318: ipcp->peer_reject = 0;
319:
320: /* Get allowed IP addresses from config and/or from current bundle */
321: if (ipcp->conf.self_ippool[0]) {
322: if (IPPoolGet(ipcp->conf.self_ippool, &ipcp->self_allow.addr)) {
323: Log(LG_IPCP, ("[%s] IPCP: Can't get IP from pool \"%s\" for self",
324: b->name, ipcp->conf.self_ippool));
325: } else {
326: Log(LG_IPCP, ("[%s] IPCP: Got IP %s from pool \"%s\" for self",
327: b->name,
328: u_addrtoa(&ipcp->self_allow.addr, buf, sizeof(buf)),
329: ipcp->conf.self_ippool));
330: ipcp->self_allow.width = 32;
331: ipcp->self_ippool_used = 1;
332: }
333: } else
334: ipcp->self_allow = ipcp->conf.self_allow;
335:
336: if ((b->params.range_valid) && (!u_rangeempty(&b->params.range)))
337: ipcp->peer_allow = b->params.range;
338: else if (b->params.ippool[0]) {
339: /* Get IP from pool if needed */
340: if (IPPoolGet(b->params.ippool, &ipcp->peer_allow.addr)) {
341: Log(LG_IPCP, ("[%s] IPCP: Can't get IP from pool \"%s\" for peer",
342: b->name, b->params.ippool));
343: } else {
344: Log(LG_IPCP, ("[%s] IPCP: Got IP %s from pool \"%s\" for peer",
345: b->name,
346: u_addrtoa(&ipcp->peer_allow.addr, buf, sizeof(buf)),
347: b->params.ippool));
348: ipcp->peer_allow.width = 32;
349: b->params.ippool_used = 1;
350: }
351: } else if (ipcp->conf.ippool[0]) {
352: if (IPPoolGet(ipcp->conf.ippool, &ipcp->peer_allow.addr)) {
353: Log(LG_IPCP, ("[%s] IPCP: Can't get IP from pool \"%s\"",
354: b->name, ipcp->conf.ippool));
355: } else {
356: Log(LG_IPCP, ("[%s] IPCP: Got IP %s from pool \"%s\" for peer",
357: b->name,
358: u_addrtoa(&ipcp->peer_allow.addr, buf, sizeof(buf)),
359: ipcp->conf.ippool));
360: ipcp->peer_allow.width = 32;
361: ipcp->ippool_used = 1;
362: }
363: } else
364: ipcp->peer_allow = ipcp->conf.peer_allow;
365:
366: /* Initially request addresses as specified by config */
367: u_addrtoin_addr(&ipcp->self_allow.addr, &ipcp->want_addr);
368: u_addrtoin_addr(&ipcp->peer_allow.addr, &ipcp->peer_addr);
369:
370: #ifdef USE_NG_VJC
371: /* Van Jacobson compression */
372: ipcp->peer_comp.proto = 0;
373: ipcp->peer_comp.maxchan = IPCP_VJCOMP_DEFAULT_MAXCHAN;
374: ipcp->peer_comp.compcid = 0;
375:
376: ipcp->want_comp.proto =
377: (b->params.vjc_enable || Enabled(&ipcp->conf.options, IPCP_CONF_VJCOMP)) ?
378: htons(PROTO_VJCOMP) : 0;
379: ipcp->want_comp.maxchan = IPCP_VJCOMP_MAX_MAXCHAN;
380:
381: /* If any of our links are unable to give receive error indications, we must
382: tell the peer not to compress the slot-id in VJCOMP packets (cf. RFC1144).
383: To be on the safe side, we always say this. */
384: ipcp->want_comp.compcid = 0;
385: #endif
386:
387: /* DNS and NBNS servers */
388: memset(&ipcp->want_dns, 0, sizeof(ipcp->want_dns));
389: memset(&ipcp->want_nbns, 0, sizeof(ipcp->want_nbns));
390: }
391:
392: /*
393: * IpcpUnConfigure()
394: */
395:
396: static void
397: IpcpUnConfigure(Fsm fp)
398: {
399: Bund b = (Bund)fp->arg;
400: IpcpState const ipcp = &b->ipcp;
401:
402: if (ipcp->self_ippool_used) {
403: struct u_addr ip;
404: in_addrtou_addr(&ipcp->want_addr, &ip);
405: IPPoolFree(ipcp->conf.self_ippool, &ip);
406: ipcp->self_ippool_used = 0;
407: }
408: if (b->params.ippool_used) {
409: struct u_addr ip;
410: in_addrtou_addr(&ipcp->peer_addr, &ip);
411: IPPoolFree(b->params.ippool, &ip);
412: b->params.ippool_used = 0;
413: } else if (ipcp->ippool_used) {
414: struct u_addr ip;
415: in_addrtou_addr(&ipcp->peer_addr, &ip);
416: IPPoolFree(ipcp->conf.ippool, &ip);
417: ipcp->ippool_used = 0;
418: }
419: }
420:
421: /*
422: * IpcpBuildConfigReq()
423: */
424:
425: static u_char *
426: IpcpBuildConfigReq(Fsm fp, u_char *cp)
427: {
428: Bund b = (Bund)fp->arg;
429: IpcpState const ipcp = &b->ipcp;
430:
431: /* Put in my desired IP address */
432: if (!IPCP_REJECTED(ipcp, TY_IPADDR) || ipcp->want_addr.s_addr == 0)
433: cp = FsmConfValue(cp, TY_IPADDR, 4, &ipcp->want_addr.s_addr);
434:
435: #ifdef USE_NG_VJC
436: /* Put in my requested compression protocol */
437: if (ipcp->want_comp.proto != 0 && !IPCP_REJECTED(ipcp, TY_COMPPROTO))
438: cp = FsmConfValue(cp, TY_COMPPROTO, 4, &ipcp->want_comp);
439: #endif
440:
441: /* Request peer's DNS and NBNS servers */
442: {
443: const int sopts[2][2] = { { IPCP_CONF_REQPRIDNS, IPCP_CONF_REQSECDNS },
444: { IPCP_CONF_REQPRINBNS, IPCP_CONF_REQSECNBNS }};
445: const int nopts[2][2] = { { TY_PRIMARYDNS, TY_SECONDARYDNS },
446: { TY_PRIMARYNBNS, TY_SECONDARYNBNS } };
447: struct in_addr *vals[2] = { ipcp->want_dns, ipcp->want_nbns };
448: int sopt, pri;
449:
450: for (sopt = 0; sopt < 2; sopt++) {
451: for (pri = 0; pri < 2; pri++) {
452: const int opt = nopts[sopt][pri];
453:
454: /* Add option if we desire it and it hasn't been rejected */
455: if (Enabled(&ipcp->conf.options, sopts[sopt][pri])
456: && !IPCP_REJECTED(ipcp, opt)) {
457: cp = FsmConfValue(cp, opt, 4, &vals[sopt][pri]);
458: }
459: }
460: }
461: }
462:
463: /* Done */
464:
465: return(cp);
466: }
467:
468: /*
469: * IpcpLayerStart()
470: *
471: * Tell the lower layer (the bundle) that we need it
472: */
473:
474: static void
475: IpcpLayerStart(Fsm fp)
476: {
477: BundNcpsStart((Bund)(fp->arg), NCP_IPCP);
478: }
479:
480: /*
481: * IpcpLayerFinish()
482: *
483: * Tell the lower layer (the bundle) that we no longer need it
484: */
485:
486: static void
487: IpcpLayerFinish(Fsm fp)
488: {
489: BundNcpsFinish((Bund)(fp->arg), NCP_IPCP);
490: }
491:
492: /*
493: * IpcpLayerUp()
494: *
495: * Called when IPCP has reached the OPEN state
496: */
497:
498: static void
499: IpcpLayerUp(Fsm fp)
500: {
501: Bund b = (Bund)fp->arg;
502: IpcpState const ipcp = &b->ipcp;
503: char ipbuf[20];
504: #ifdef USE_NG_VJC
505: char path[NG_PATHSIZ];
506: struct ngm_vjc_config vjc;
507: #endif
508: struct u_addr tmp;
509:
510: /* Determine actual address we'll use for ourselves */
511: in_addrtou_addr(&ipcp->want_addr, &tmp);
512: if (!IpAddrInRange(&ipcp->self_allow, &tmp)) {
513: Log(LG_IPCP, ("[%s] Note: ignoring negotiated %s IP %s,",
514: b->name, "self", inet_ntoa(ipcp->want_addr)));
515: u_addrtoin_addr(&ipcp->self_allow.addr, &ipcp->want_addr);
516: Log(LG_IPCP, ("[%s] using %s instead.",
517: b->name, inet_ntoa(ipcp->want_addr)));
518: }
519:
520: /* Determine actual address we'll use for peer */
521: in_addrtou_addr(&ipcp->peer_addr, &tmp);
522: if (!IpAddrInRange(&ipcp->peer_allow, &tmp)
523: && !u_addrempty(&ipcp->peer_allow.addr)) {
524: Log(LG_IPCP, ("[%s] Note: ignoring negotiated %s IP %s,",
525: b->name, "peer", inet_ntoa(ipcp->peer_addr)));
526: u_addrtoin_addr(&ipcp->peer_allow.addr, &ipcp->peer_addr);
527: Log(LG_IPCP, ("[%s] using %s instead.",
528: b->name, inet_ntoa(ipcp->peer_addr)));
529: }
530:
531: /* Report */
532: strlcpy(ipbuf, inet_ntoa(ipcp->peer_addr), sizeof(ipbuf));
533: Log(LG_IPCP, ("[%s] %s -> %s", b->name, inet_ntoa(ipcp->want_addr), ipbuf));
534:
535: #ifdef USE_NG_VJC
536: memset(&vjc, 0, sizeof(vjc));
537: if (ntohs(ipcp->peer_comp.proto) == PROTO_VJCOMP ||
538: ntohs(ipcp->want_comp.proto) == PROTO_VJCOMP) {
539:
540: IpcpNgInitVJ(b);
541:
542: /* Configure VJ compression node */
543: vjc.enableComp = ntohs(ipcp->peer_comp.proto) == PROTO_VJCOMP;
544: vjc.enableDecomp = ntohs(ipcp->want_comp.proto) == PROTO_VJCOMP;
545: vjc.maxChannel = ipcp->peer_comp.maxchan;
546: vjc.compressCID = ipcp->peer_comp.compcid;
547: snprintf(path, sizeof(path), "[%x]:%s", b->nodeID, NG_PPP_HOOK_VJC_IP);
548: if (NgSendMsg(gLinksCsock, path,
549: NGM_VJC_COOKIE, NGM_VJC_SET_CONFIG, &vjc, sizeof(vjc)) < 0) {
550: Perror("[%s] can't config %s node", b->name, NG_VJC_NODE_TYPE);
551: }
552: }
553: #endif /* USE_NG_VJC */
554:
555: /* Enable IP packets in the PPP node */
556: b->pppConfig.bund.enableIP = 1;
557: #ifdef USE_NG_VJC
558: b->pppConfig.bund.enableVJCompression = vjc.enableComp;
559: b->pppConfig.bund.enableVJDecompression = vjc.enableDecomp;
560: #endif
561: NgFuncSetConfig(b);
562:
563: BundNcpsJoin(b, NCP_IPCP);
564: }
565:
566: /*
567: * IpcpLayerDown()
568: *
569: * Called when IPCP leaves the OPEN state
570: */
571:
572: static void
573: IpcpLayerDown(Fsm fp)
574: {
575: Bund b = (Bund)fp->arg;
576: #ifdef USE_NG_VJC
577: IpcpState const ipcp = &b->ipcp;
578: #endif
579:
580: BundNcpsLeave(b, NCP_IPCP);
581:
582: /* Turn off IP packets */
583: b->pppConfig.bund.enableIP = 0;
584: #ifdef USE_NG_VJC
585: b->pppConfig.bund.enableVJCompression = 0;
586: b->pppConfig.bund.enableVJDecompression = 0;
587: #endif
588: NgFuncSetConfig(b);
589:
590: #ifdef USE_NG_VJC
591: if (ntohs(ipcp->peer_comp.proto) == PROTO_VJCOMP ||
592: ntohs(ipcp->want_comp.proto) == PROTO_VJCOMP) {
593: IpcpNgShutdownVJ(b);
594: }
595: #endif /* USE_NG_VJC */
596: }
597:
598: /*
599: * IpcpUp()
600: */
601:
602: void
603: IpcpUp(Bund b)
604: {
605: FsmUp(&b->ipcp.fsm);
606: }
607:
608: /*
609: * IpcpDown()
610: */
611:
612: void
613: IpcpDown(Bund b)
614: {
615: FsmDown(&b->ipcp.fsm);
616: }
617:
618: /*
619: * IpcpOpen()
620: */
621:
622: void
623: IpcpOpen(Bund b)
624: {
625: FsmOpen(&b->ipcp.fsm);
626: }
627:
628: /*
629: * IpcpClose()
630: */
631:
632: void
633: IpcpClose(Bund b)
634: {
635: FsmClose(&b->ipcp.fsm);
636: }
637:
638: /*
639: * IpcpOpenCmd()
640: */
641:
642: int
643: IpcpOpenCmd(Context ctx)
644: {
645: if (ctx->bund->tmpl)
646: Error("impossible to open template");
647: FsmOpen(&ctx->bund->ipcp.fsm);
648: return (0);
649: }
650:
651: /*
652: * IpcpCloseCmd()
653: */
654:
655: int
656: IpcpCloseCmd(Context ctx)
657: {
658: if (ctx->bund->tmpl)
659: Error("impossible to close template");
660: FsmClose(&ctx->bund->ipcp.fsm);
661: return (0);
662: }
663:
664: /*
665: * IpcpFailure()
666: */
667:
668: static void
669: IpcpFailure(Fsm fp, enum fsmfail reason)
670: {
671: Bund b = (Bund)fp->arg;
672: RecordLinkUpDownReason(b, NULL, 0, STR_PROTO_ERR, STR_IPCP_FAILED, FsmFailureStr(reason));
673: }
674:
675: /*
676: * IpcpDecodeConfig()
677: */
678:
679: static void
680: IpcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode)
681: {
682: Bund b = (Bund)fp->arg;
683: IpcpState const ipcp = &b->ipcp;
684: struct in_addr *wantip, *peerip;
685: int k;
686:
687: /* Decode each config option */
688: for (k = 0; k < num; k++) {
689: FsmOption const opt = &list[k];
690: FsmOptInfo const oi = FsmFindOptInfo(gIpcpConfOpts, opt->type);
691:
692: if (!oi) {
693: Log(LG_IPCP, ("[%s] UNKNOWN[%d] len=%d", b->name, opt->type, opt->len));
694: if (mode == MODE_REQ)
695: FsmRej(fp, opt);
696: continue;
697: }
698: if (!oi->supported) {
699: Log(LG_IPCP, ("[%s] %s", b->name, oi->name));
700: if (mode == MODE_REQ) {
701: Log(LG_IPCP, ("[%s] Not supported", b->name));
702: FsmRej(fp, opt);
703: }
704: continue;
705: }
706: if (opt->len < oi->minLen + 2 || opt->len > oi->maxLen + 2) {
707: Log(LG_IPCP, ("[%s] %s", b->name, oi->name));
708: if (mode == MODE_REQ) {
709: Log(LG_IPCP, ("[%s] bogus len=%d", b->name, opt->len));
710: FsmRej(fp, opt);
711: }
712: continue;
713: }
714: switch (opt->type) {
715: case TY_IPADDR:
716: {
717: struct in_addr ip;
718: struct u_addr tmp;
719:
720: memcpy(&ip, opt->data, 4);
721: in_addrtou_addr(&ip, &tmp);
722: Log(LG_IPCP, ("[%s] %s %s", b->name, oi->name, inet_ntoa(ip)));
723: switch (mode) {
724: case MODE_REQ:
725: if (!IpAddrInRange(&ipcp->peer_allow, &tmp) || !ip.s_addr) {
726: if (ipcp->peer_addr.s_addr == 0)
727: Log(LG_IPCP, ("[%s] no IP address available for peer!", b->name));
728: if (Enabled(&ipcp->conf.options, IPCP_CONF_PRETENDIP)) {
729: Log(LG_IPCP, ("[%s] pretending that %s is OK, will ignore",
730: b->name, inet_ntoa(ip)));
731: ipcp->peer_addr = ip;
732: FsmAck(fp, opt);
733: break;
734: }
735: memcpy(opt->data, &ipcp->peer_addr, 4);
736: Log(LG_IPCP, ("[%s] NAKing with %s", b->name, inet_ntoa(ipcp->peer_addr)));
737: FsmNak(fp, opt);
738: break;
739: }
740: Log(LG_IPCP, ("[%s] %s is OK", b->name, inet_ntoa(ip)));
741: ipcp->peer_addr = ip;
742: FsmAck(fp, opt);
743: break;
744: case MODE_NAK:
745: {
746: if (IpAddrInRange(&ipcp->self_allow, &tmp)) {
747: Log(LG_IPCP, ("[%s] %s is OK", b->name, inet_ntoa(ip)));
748: ipcp->want_addr = ip;
749: } else if (Enabled(&ipcp->conf.options, IPCP_CONF_PRETENDIP)) {
750: Log(LG_IPCP, ("[%s] pretending that %s is OK, will ignore",
751: b->name, inet_ntoa(ip)));
752: ipcp->want_addr = ip;
753: } else
754: Log(LG_IPCP, ("[%s] %s is unacceptable", b->name, inet_ntoa(ip)));
755: }
756: break;
757: case MODE_REJ:
758: IPCP_PEER_REJ(ipcp, opt->type);
759: if (ipcp->want_addr.s_addr == 0)
760: Log(LG_IPCP, ("[%s] Problem: I need an IP address!", b->name));
761: break;
762: }
763: }
764: break;
765:
766: #ifdef USE_NG_VJC
767: case TY_COMPPROTO:
768: {
769: struct ipcpvjcomp vj;
770:
771: memcpy(&vj, opt->data, sizeof(vj));
772: Log(LG_IPCP, ("[%s] %s %s, %d comp. channels, %s comp-cid",
773: b->name, oi->name, ProtoName(ntohs(vj.proto)),
774: vj.maxchan + 1, vj.compcid ? "allow" : "no"));
775: switch (mode) {
776: case MODE_REQ:
777: if (!Acceptable(&ipcp->conf.options, IPCP_CONF_VJCOMP) &&
778: !b->params.vjc_enable) {
779: FsmRej(fp, opt);
780: break;
781: }
782: if (ntohs(vj.proto) == PROTO_VJCOMP
783: && vj.maxchan <= IPCP_VJCOMP_MAX_MAXCHAN
784: && vj.maxchan >= IPCP_VJCOMP_MIN_MAXCHAN) {
785: ipcp->peer_comp = vj;
786: FsmAck(fp, opt);
787: break;
788: }
789: vj.proto = htons(PROTO_VJCOMP);
790: vj.maxchan = IPCP_VJCOMP_MAX_MAXCHAN;
791: vj.compcid = 0;
792: memcpy(opt->data, &vj, sizeof(vj));
793: FsmNak(fp, opt);
794: break;
795: case MODE_NAK:
796: if (ntohs(vj.proto) != PROTO_VJCOMP) {
797: Log(LG_IPCP, ("[%s] Can't accept proto 0x%04x",
798: b->name, (u_short) ntohs(vj.proto)));
799: break;
800: }
801: if (vj.maxchan != ipcp->want_comp.maxchan) {
802: if (vj.maxchan <= IPCP_VJCOMP_MAX_MAXCHAN
803: && vj.maxchan >= IPCP_VJCOMP_MIN_MAXCHAN) {
804: Log(LG_IPCP, ("[%s] Adjusting # compression channels", b->name));
805: ipcp->want_comp.maxchan = vj.maxchan;
806: } else {
807: Log(LG_IPCP, ("[%s] Can't handle %d maxchan", b->name, vj.maxchan));
808: }
809: }
810: if (vj.compcid) {
811: Log(LG_IPCP, ("[%s] Can't accept comp-cid", b->name));
812: break;
813: }
814: break;
815: case MODE_REJ:
816: IPCP_PEER_REJ(ipcp, opt->type);
817: ipcp->want_comp.proto = 0;
818: break;
819: }
820: }
821: break;
822: #endif /* USE_NG_VJC */
823:
824: case TY_PRIMARYDNS:
825: if (b->params.peer_dns[0].s_addr != 0)
826: peerip = &b->params.peer_dns[0];
827: else
828: peerip = &ipcp->conf.peer_dns[0];
829: wantip = &ipcp->want_dns[0];
830: goto doDnsNbns;
831: case TY_PRIMARYNBNS:
832: if (b->params.peer_nbns[0].s_addr != 0)
833: peerip = &b->params.peer_nbns[0];
834: else
835: peerip = &ipcp->conf.peer_nbns[0];
836: wantip = &ipcp->want_nbns[0];
837: goto doDnsNbns;
838: case TY_SECONDARYDNS:
839: if (b->params.peer_dns[1].s_addr != 0)
840: peerip = &b->params.peer_dns[1];
841: else
842: peerip = &ipcp->conf.peer_dns[1];
843: wantip = &ipcp->want_dns[1];
844: goto doDnsNbns;
845: case TY_SECONDARYNBNS:
846: if (b->params.peer_nbns[1].s_addr != 0)
847: peerip = &b->params.peer_nbns[1];
848: else
849: peerip = &ipcp->conf.peer_nbns[1];
850: wantip = &ipcp->want_nbns[1];
851: doDnsNbns:
852: {
853: struct in_addr hisip;
854:
855: memcpy(&hisip, opt->data, 4);
856: Log(LG_IPCP, ("[%s] %s %s", b->name, oi->name, inet_ntoa(hisip)));
857: switch (mode) {
858: case MODE_REQ:
859: if (hisip.s_addr == 0) { /* he's asking for one */
860: if (peerip->s_addr == 0) { /* we don't got one */
861: FsmRej(fp, opt);
862: break;
863: }
864: Log(LG_IPCP, ("[%s] NAKing with %s", b->name, inet_ntoa(*peerip)));
865: memcpy(opt->data, peerip, sizeof(*peerip));
866: FsmNak(fp, opt); /* we got one for him */
867: break;
868: }
869: FsmAck(fp, opt); /* he knows what he wants */
870: break;
871: case MODE_NAK: /* we asked for his server, he's telling us */
872: *wantip = hisip;
873: break;
874: case MODE_REJ: /* we asked for his server, he's ignorant */
875: IPCP_PEER_REJ(ipcp, opt->type);
876: break;
877: }
878: }
879: break;
880:
881: default:
882: assert(0);
883: }
884: }
885: }
886:
887: /*
888: * IpcpInput()
889: *
890: * Deal with an incoming IPCP packet
891: */
892:
893: void
894: IpcpInput(Bund b, Mbuf bp)
895: {
896: FsmInput(&b->ipcp.fsm, bp);
897: }
898:
899: #ifdef USE_NG_VJC
900: static int
901: IpcpNgInitVJ(Bund b)
902: {
903: struct ngm_mkpeer mp;
904: struct ngm_connect cn;
905: char path[NG_PATHSIZ];
906: struct ngm_name nm;
907:
908: /* Add a VJ compression node */
909: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
910: strcpy(mp.type, NG_VJC_NODE_TYPE);
911: strcpy(mp.ourhook, NG_PPP_HOOK_VJC_IP);
912: strcpy(mp.peerhook, NG_VJC_HOOK_IP);
913: if (NgSendMsg(gLinksCsock, path,
914: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
915: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
916: b->name, NG_VJC_NODE_TYPE, path, mp.ourhook);
917: goto fail;
918: }
919:
920: /* Give it a name */
921: strlcat(path, NG_PPP_HOOK_VJC_IP, sizeof(path));
922: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-vjc", gPid, b->name);
923: if (NgSendMsg(gLinksCsock, path,
924: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
925: Perror("[%s] can't name %s node", b->name, NG_VJC_NODE_TYPE);
926: goto fail;
927: }
928:
929: /* Connect the other three hooks between the ppp and vjc nodes */
930: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
931: strcpy(cn.path, NG_PPP_HOOK_VJC_IP);
932: strcpy(cn.ourhook, NG_PPP_HOOK_VJC_COMP);
933: strcpy(cn.peerhook, NG_VJC_HOOK_VJCOMP);
934: if (NgSendMsg(gLinksCsock, path,
935: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
936: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
937: b->name, path, cn.ourhook, cn.path, cn.peerhook);
938: goto fail;
939: }
940: strcpy(cn.ourhook, NG_PPP_HOOK_VJC_UNCOMP);
941: strcpy(cn.peerhook, NG_VJC_HOOK_VJUNCOMP);
942: if (NgSendMsg(gLinksCsock, path,
943: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
944: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
945: b->name, path, cn.ourhook, cn.path, cn.peerhook);
946: goto fail;
947: }
948: strcpy(cn.ourhook, NG_PPP_HOOK_VJC_VJIP);
949: strcpy(cn.peerhook, NG_VJC_HOOK_VJIP);
950: if (NgSendMsg(gLinksCsock, path,
951: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
952: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
953: b->name, path, cn.ourhook, cn.path, cn.peerhook);
954: goto fail;
955: }
956:
957: return 0;
958: fail:
959: return -1;
960: }
961:
962: static void
963: IpcpNgShutdownVJ(Bund b)
964: {
965: char path[NG_PATHSIZ];
966:
967: snprintf(path, sizeof(path), "[%x]:%s", b->nodeID, NG_PPP_HOOK_VJC_IP);
968: NgFuncShutdownNode(gLinksCsock, b->name, path);
969: }
970: #endif /* USE_NG_VJC */
971:
972: /*
973: * IpcpSetCommand()
974: */
975:
976: static int
977: IpcpSetCommand(Context ctx, int ac, char *av[], void *arg)
978: {
979: IpcpState const ipcp = &ctx->bund->ipcp;
980: struct in_addr *ips;
981:
982: if (ac == 0)
983: return(-1);
984: switch ((intptr_t)arg) {
985: case SET_RANGES:
986: {
987: struct u_range self_new_allow;
988: struct u_range peer_new_allow;
989: int pos = 0, self_new_pool = -1, peer_new_pool = -1;
990:
991: /* Parse args */
992: if (ac < 2)
993: return (-1);
994: if (strcmp(av[pos], "ippool") == 0) {
995: self_new_pool = pos+1;
996: pos+=2;
997: } else {
998: if (!ParseRange(av[pos], &self_new_allow, ALLOW_IPV4))
999: return(-1);
1000: pos++;
1001: }
1002: if (pos >= ac)
1003: return (-1);
1004: if (strcmp(av[pos], "ippool") == 0) {
1005: if ((pos + 1) >= ac)
1006: return (-1);
1007: peer_new_pool = pos+1;
1008: pos+=2;
1009: } else {
1010: if (!ParseRange(av[pos], &peer_new_allow, ALLOW_IPV4))
1011: return(-1);
1012: pos++;
1013: }
1014: if (pos != ac)
1015: return (-1);
1016:
1017: if (self_new_pool >= 0)
1018: strlcpy(ipcp->conf.self_ippool, av[self_new_pool], sizeof(ipcp->conf.self_ippool));
1019: else
1020: ipcp->conf.self_ippool[0] = 0;
1021: if (peer_new_pool >= 0)
1022: strlcpy(ipcp->conf.ippool, av[peer_new_pool], sizeof(ipcp->conf.ippool));
1023: else
1024: ipcp->conf.ippool[0] = 0;
1025: ipcp->conf.self_allow = self_new_allow;
1026: ipcp->conf.peer_allow = peer_new_allow;
1027:
1028: }
1029: break;
1030:
1031: case SET_DNS:
1032: ips = ipcp->conf.peer_dns;
1033: goto getPrimSec;
1034: break;
1035: case SET_NBNS:
1036: ips = ipcp->conf.peer_nbns;
1037: getPrimSec:
1038: if (!inet_aton(av[0], &ips[0]))
1039: Error("invalid IP address: \'%s\'", av[0]);
1040: ips[1].s_addr = 0;
1041: if (ac > 1 && !inet_aton(av[1], &ips[1]))
1042: Error("invalid IP address: \'%s\'", av[1]);
1043: break;
1044:
1045: case SET_ACCEPT:
1046: AcceptCommand(ac, av, &ipcp->conf.options, gConfList);
1047: break;
1048:
1049: case SET_DENY:
1050: DenyCommand(ac, av, &ipcp->conf.options, gConfList);
1051: break;
1052:
1053: case SET_ENABLE:
1054: EnableCommand(ac, av, &ipcp->conf.options, gConfList);
1055: break;
1056:
1057: case SET_DISABLE:
1058: DisableCommand(ac, av, &ipcp->conf.options, gConfList);
1059: break;
1060:
1061: case SET_YES:
1062: YesCommand(ac, av, &ipcp->conf.options, gConfList);
1063: break;
1064:
1065: case SET_NO:
1066: NoCommand(ac, av, &ipcp->conf.options, gConfList);
1067: break;
1068:
1069: default:
1070: assert(0);
1071: }
1072: return(0);
1073: }
1074:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>