Annotation of embedaddon/mpd/src/ccp.c, revision 1.1.1.3
1.1 misho 1:
2: /*
3: * ccp.c
4: *
5: * Written by Archie Cobbs <archie@freebsd.org>
6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
7: * See ``COPYRIGHT.whistle''
8: */
9:
10: #include "defs.h"
11: #include "ppp.h"
12: #include "ccp.h"
13: #include "fsm.h"
14: #include "ngfunc.h"
15:
16: #include <netgraph/ng_message.h>
17: #include <netgraph/ng_socket.h>
18: #include <netgraph.h>
19:
20: /*
21: * DEFINITIONS
22: */
23:
24: #define CCP_MAXFAILURE 7
25:
26: #define CCP_KNOWN_CODES ( (1 << CODE_CONFIGREQ) \
27: | (1 << CODE_CONFIGACK) \
28: | (1 << CODE_CONFIGNAK) \
29: | (1 << CODE_CONFIGREJ) \
30: | (1 << CODE_TERMREQ) \
31: | (1 << CODE_TERMACK) \
32: | (1 << CODE_CODEREJ) \
33: | (1 << CODE_RESETREQ) \
34: | (1 << CODE_RESETACK) )
35:
36: /* Set menu options */
37: enum {
38: SET_ACCEPT,
39: SET_DENY,
40: SET_ENABLE,
41: SET_DISABLE,
42: SET_YES,
43: SET_NO
44: };
45:
46: /*
47: * INTERNAL FUNCTIONS
48: */
49:
50: static void CcpConfigure(Fsm fp);
51: static void CcpUnConfigure(Fsm fp);
52: static u_char *CcpBuildConfigReq(Fsm fp, u_char *cp);
53: static void CcpDecodeConfig(Fsm f, FsmOption a, int num, int mode);
54: static void CcpLayerUp(Fsm fp);
55: static void CcpLayerDown(Fsm fp);
56: static void CcpFailure(Fsm f, enum fsmfail reason);
57: static void CcpRecvResetReq(Fsm fp, int id, Mbuf bp);
58: static void CcpRecvResetAck(Fsm fp, int id, Mbuf bp);
59:
60: static int CcpCheckEncryption(Bund b);
1.1.1.3 ! misho 61: static int CcpSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
1.1 misho 62: static CompType CcpFindComp(int type, int *indexp);
63: static const char *CcpTypeName(int type, char *buf, size_t len);
64:
65: static void CcpNgCtrlEvent(int type, void *cookie);
66: static void CcpNgDataEvent(int type, void *cookie);
67:
68: /*
69: * GLOBAL VARIABLES
70: */
71:
72: const struct cmdtab CcpSetCmds[] = {
73: { "accept [opt ...]", "Accept option",
74: CcpSetCommand, NULL, 2, (void *) SET_ACCEPT },
75: { "deny [opt ...]", "Deny option",
76: CcpSetCommand, NULL, 2, (void *) SET_DENY },
77: { "enable [opt ...]", "Enable option",
78: CcpSetCommand, NULL, 2, (void *) SET_ENABLE },
79: { "disable [opt ...]", "Disable option",
80: CcpSetCommand, NULL, 2, (void *) SET_DISABLE },
81: { "yes [opt ...]", "Enable and accept option",
82: CcpSetCommand, NULL, 2, (void *) SET_YES },
83: { "no [opt ...]", "Disable and deny option",
84: CcpSetCommand, NULL, 2, (void *) SET_NO },
1.1.1.3 ! misho 85: { NULL, NULL, NULL, NULL, 0, NULL },
1.1 misho 86: };
87:
88: /*
89: * INTERNAL VARIABLES
90: */
91:
92: /* These should be listed in order of preference */
93: static const CompType gCompTypes[] = {
94: #ifdef CCP_MPPC
95: &gCompMppcInfo,
96: #endif
97: #ifdef CCP_DEFLATE
98: &gCompDeflateInfo,
99: #endif
100: #ifdef CCP_PRED1
101: &gCompPred1Info,
102: #endif
103: };
104: #define CCP_NUM_PROTOS (sizeof(gCompTypes) / sizeof(*gCompTypes))
105:
106: /* Corresponding option list */
107: static const struct confinfo *gConfList;
108:
109: /* FSM Initializer */
110: static const struct fsmtype gCcpFsmType = {
111: "CCP",
112: PROTO_CCP,
113: CCP_KNOWN_CODES,
114: FALSE,
115: LG_CCP, LG_CCP2,
116: NULL,
117: CcpLayerUp,
118: CcpLayerDown,
119: NULL,
120: NULL,
121: CcpBuildConfigReq,
122: CcpDecodeConfig,
123: CcpConfigure,
124: CcpUnConfigure,
125: NULL,
126: NULL,
127: NULL,
128: NULL,
129: CcpFailure,
130: CcpRecvResetReq,
131: CcpRecvResetAck,
1.1.1.3 ! misho 132: NULL, NULL, NULL, NULL
1.1 misho 133: };
134:
135: /* Names for different types of compression */
136: static const struct ccpname {
137: u_char type;
138: const char *name;
139: } gCcpTypeNames[] = {
140: { CCP_TY_OUI, "OUI" },
141: { CCP_TY_PRED1, "PRED1" },
142: { CCP_TY_PRED2, "PRED2" },
143: { CCP_TY_PUDDLE, "PUDDLE" },
144: { CCP_TY_HWPPC, "HWPPC" },
145: { CCP_TY_STAC, "STAC" },
146: { CCP_TY_MPPC, "MPPC" },
147: { CCP_TY_GAND, "GAND" },
148: { CCP_TY_V42BIS, "V42BIS" },
149: { CCP_TY_BSD, "BSD" },
150: { CCP_TY_LZS_DCP, "LZS-DCP" },
1.1.1.3 ! misho 151: { CCP_TY_MVRCA, "MVRCA" },
1.1 misho 152: { CCP_TY_DCE, "DCE" },
153: { CCP_TY_DEFLATE, "DEFLATE" },
154: { CCP_TY_V44, "V.44/LZJH" },
155: { 0, NULL },
156: };
157:
1.1.1.3 ! misho 158: int gCcpCsock = -1; /* Socket node control socket */
! 159: int gCcpDsock = -1; /* Socket node data socket */
! 160: static EventRef gCcpCtrlEvent;
! 161: static EventRef gCcpDataEvent;
1.1 misho 162:
163: int
164: CcpsInit(void)
165: {
166: char name[NG_NODESIZ];
167:
168: /* Create a netgraph socket node */
169: snprintf(name, sizeof(name), "mpd%d-cso", gPid);
170: if (NgMkSockNode(name, &gCcpCsock, &gCcpDsock) < 0) {
171: Perror("CcpsInit(): can't create %s node", NG_SOCKET_NODE_TYPE);
172: return(-1);
173: }
174: (void) fcntl(gCcpCsock, F_SETFD, 1);
175: (void) fcntl(gCcpDsock, F_SETFD, 1);
176:
177: /* Listen for happenings on our node */
178: EventRegister(&gCcpCtrlEvent, EVENT_READ,
179: gCcpCsock, EVENT_RECURRING, CcpNgCtrlEvent, NULL);
180: EventRegister(&gCcpDataEvent, EVENT_READ,
181: gCcpDsock, EVENT_RECURRING, CcpNgDataEvent, NULL);
182:
183: return (0);
184: }
185:
186: void
187: CcpsShutdown(void)
188: {
189: EventUnRegister(&gCcpCtrlEvent);
190: close(gCcpCsock);
191: gCcpCsock = -1;
192: EventUnRegister(&gCcpDataEvent);
193: close(gCcpDsock);
194: gCcpDsock = -1;
195: }
196:
197: /*
198: * CcpInit()
199: */
200:
201: void
202: CcpInit(Bund b)
203: {
204: CcpState ccp = &b->ccp;
205:
206: /* Init CCP state for this bundle */
207: memset(ccp, 0, sizeof(*ccp));
208: FsmInit(&ccp->fsm, &gCcpFsmType, b);
209: ccp->fsm.conf.maxfailure = CCP_MAXFAILURE;
210:
211: /* Construct options list if we haven't done so already */
212: if (gConfList == NULL) {
213: struct confinfo *ci;
1.1.1.3 ! misho 214: unsigned k;
1.1 misho 215:
216: ci = Malloc(MB_COMP, (CCP_NUM_PROTOS + 1) * sizeof(*ci));
217: for (k = 0; k < CCP_NUM_PROTOS; k++) {
218: ci[k].option = k;
219: ci[k].peered = TRUE;
220: ci[k].name = gCompTypes[k]->name;
221: }
222:
223: /* Terminate list */
224: ci[k].name = NULL;
225: gConfList = (const struct confinfo *) ci;
226: }
227: }
228:
229: /*
230: * CcpInst()
231: */
232:
233: void
234: CcpInst(Bund b, Bund bt)
235: {
236: CcpState ccp = &b->ccp;
237:
238: /* Init CCP state for this bundle */
239: memcpy(ccp, &bt->ccp, sizeof(*ccp));
240: FsmInst(&ccp->fsm, &bt->ccp.fsm, b);
241: }
242:
243: /*
244: * CcpConfigure()
245: */
246:
247: static void
248: CcpConfigure(Fsm fp)
249: {
250: Bund b = (Bund)fp->arg;
251: CcpState const ccp = &b->ccp;
1.1.1.3 ! misho 252: unsigned k;
1.1 misho 253:
254: /* Reset state */
255: ccp->self_reject = 0;
256: ccp->peer_reject = 0;
257: ccp->crypt_check = 0;
258: ccp->xmit = NULL;
259: ccp->recv = NULL;
260: for (k = 0; k < CCP_NUM_PROTOS; k++) {
261: CompType const ct = gCompTypes[k];
262:
263: if (ct->Configure) {
264: if ((*ct->Configure)(b)) {
265: if (Enabled(&ccp->options, k)) {
266: Log(LG_CCP, ("[%s] CCP: Protocol %s disabled "
267: "as useless for this setup",
268: b->name, ct->name));
269: }
270: CCP_SELF_REJ(ccp, k);
271: };
272: }
273: }
274: }
275:
276: /*
277: * CcpUnConfigure()
278: */
279:
280: static void
281: CcpUnConfigure(Fsm fp)
282: {
283: Bund b = (Bund)fp->arg;
284: CcpState const ccp = &b->ccp;
1.1.1.3 ! misho 285: unsigned k;
1.1 misho 286:
287: /* Reset state */
288: ccp->self_reject = 0;
289: ccp->peer_reject = 0;
290: ccp->crypt_check = 0;
291: ccp->xmit = NULL;
292: ccp->recv = NULL;
293: for (k = 0; k < CCP_NUM_PROTOS; k++) {
294: CompType const ct = gCompTypes[k];
295:
296: if (ct->UnConfigure)
297: (*ct->UnConfigure)(b);
298: }
299: }
300:
301: /*
302: * CcpNgCtrlEvent()
303: *
304: */
305:
306: void
307: CcpNgCtrlEvent(int type, void *cookie)
308: {
309: Bund b = NULL;
310: union {
311: u_char buf[2048];
312: struct ng_mesg msg;
313: } u;
314: char raddr[NG_PATHSIZ];
315: int i, len;
316: ng_ID_t id;
317:
1.1.1.3 ! misho 318: (void)cookie;
! 319: (void)type;
! 320:
1.1 misho 321: /* Read message */
322: if ((len = NgRecvMsg(gCcpCsock, &u.msg, sizeof(u), raddr)) < 0) {
323: Perror("CcpNgCtrlEvent: can't read message");
324: return;
325: }
326:
327: if (sscanf(raddr, "[%x]:", &id) != 1) {
328: Log(LG_ERR, ("CcpNgCtrlEvent: can't decode sender id: '%s'",
329: raddr));
330: return;
331: }
332:
333: for (i = 0; i < gNumBundles; i++) {
334: if (gBundles[i] && !gBundles[i]->dead &&
335: gBundles[i]->ccp.decomp_node_id == id) {
336: b = gBundles[i];
337: break;
338: }
339: }
340: if (!b)
341: return;
342:
343: /* Examine message */
344: switch (u.msg.header.typecookie) {
345:
346: #ifdef USE_NG_MPPC
347: case NGM_MPPC_COOKIE:
348: #endif
349: #ifdef USE_NG_DEFLATE
350: case NGM_DEFLATE_COOKIE:
351: #endif
352: #ifdef USE_NG_PRED1
353: case NGM_PRED1_COOKIE:
354: #endif
355: CcpRecvMsg(b, &u.msg, len);
356: return;
357:
358: default:
359: /* Unknown message */
360: Log(LG_ERR, ("CcpNgCtrlEvent: rec'd unknown ctrl message, cookie=%d cmd=%d",
361: u.msg.header.typecookie, u.msg.header.cmd));
362: break;
363: }
364:
365: }
366:
367: /*
368: * CcpNgDataEvent()
369: */
370:
371: static void
372: CcpNgDataEvent(int type, void *cookie)
373: {
374: Bund b;
375: struct sockaddr_ng naddr;
376: socklen_t nsize;
377: Mbuf bp;
378: int num = 0;
379: char *bundname, *rest;
380: int id;
381:
1.1.1.3 ! misho 382: (void)cookie;
! 383: (void)type;
! 384:
1.1 misho 385: while (1) {
386: /* Protect from bundle shutdown and DoS */
387: if (num > 100)
388: return;
389:
390: bp = mballoc(4096);
391:
392: /* Read data */
393: nsize = sizeof(naddr);
394: if ((bp->cnt = recvfrom(gCcpDsock, MBDATA(bp), MBSPACE(bp),
395: MSG_DONTWAIT, (struct sockaddr *)&naddr, &nsize)) < 0) {
396: mbfree(bp);
397: if (errno == EAGAIN)
398: return;
399: Log(LG_BUND|LG_ERR, ("CcpNgDataEvent: socket read: %s", strerror(errno)));
400: return;
401: }
402: num++;
403:
404: /* Debugging */
405: LogDumpBp(LG_FRAME, bp,
1.1.1.2 misho 406: "CcpNgDataEvent: rec'd %zu bytes frame on %s hook", MBLEN(bp), naddr.sg_data);
1.1 misho 407:
408: bundname = ((struct sockaddr_ng *)&naddr)->sg_data;
409: if (bundname[0] != 'c' && bundname[0] != 'd') {
410: Log(LG_ERR, ("CCP: Packet from unknown hook \"%s\"",
411: bundname));
412: mbfree(bp);
413: continue;
414: }
415: bundname++;
416: id = strtol(bundname, &rest, 10);
417: if (rest[0] != 0 || !gBundles[id] || gBundles[id]->dead) {
418: Log(LG_ERR, ("CCP: Packet from unexisting bundle \"%s\"",
419: bundname));
420: mbfree(bp);
421: continue;
422: }
423:
424: b = gBundles[id];
425:
426: /* Packet requiring compression */
427: if (bundname[0] == 'c') {
428: bp = CcpDataOutput(b, bp);
429: } else {
430: /* Packet requiring decompression */
431: bp = CcpDataInput(b, bp);
432: }
433: if (bp)
434: NgFuncWriteFrame(gCcpDsock, naddr.sg_data, b->name, bp);
435: }
436: }
437:
438: /*
439: * CcpRecvMsg()
440: */
441:
442: void
443: CcpRecvMsg(Bund b, struct ng_mesg *msg, int len)
444: {
445: CcpState const ccp = &b->ccp;
446: Fsm const fp = &ccp->fsm;
447:
1.1.1.3 ! misho 448: (void)len;
! 449:
1.1 misho 450: switch (msg->header.typecookie) {
451: #ifdef USE_NG_MPPC
452: case NGM_MPPC_COOKIE:
453: switch (msg->header.cmd) {
454: case NGM_MPPC_RESETREQ: {
455: CcpSendResetReq(b);
456: return;
457: }
458: default:
459: break;
460: }
461: break;
462: #endif
463: #ifdef USE_NG_DEFLATE
464: case NGM_DEFLATE_COOKIE:
465: switch (msg->header.cmd) {
466: case NGM_DEFLATE_RESETREQ: {
467: CcpSendResetReq(b);
468: return;
469: }
470: default:
471: break;
472: }
473: break;
474: #endif
475: #ifdef USE_NG_PRED1
476: case NGM_PRED1_COOKIE:
477: switch (msg->header.cmd) {
478: case NGM_PRED1_RESETREQ: {
479: CcpSendResetReq(b);
480: return;
481: }
482: default:
483: break;
484: }
485: break;
486: #endif
487: default:
488: break;
489: }
490:
491: /* Unknown! */
492: Log(LG_ERR, ("[%s] %s: rec'd unknown netgraph message: cookie=%d, cmd=%d",
493: Pref(fp), Fsm(fp), msg->header.typecookie, msg->header.cmd));
494: }
495:
496: /*
497: * CcpUp()
498: */
499:
500: void
501: CcpUp(Bund b)
502: {
503: FsmUp(&b->ccp.fsm);
504: }
505:
506: /*
507: * CcpDown()
508: */
509:
510: void
511: CcpDown(Bund b)
512: {
513: FsmDown(&b->ccp.fsm);
514: }
515:
516: /*
517: * CcpOpen()
518: */
519:
520: void
521: CcpOpen(Bund b)
522: {
523: FsmOpen(&b->ccp.fsm);
524: }
525:
526: /*
527: * CcpClose()
528: */
529:
530: void
531: CcpClose(Bund b)
532: {
533: FsmClose(&b->ccp.fsm);
534: }
535:
536: /*
537: * CcpOpenCmd()
538: */
539:
540: int
541: CcpOpenCmd(Context ctx)
542: {
543: if (ctx->bund->tmpl)
544: Error("impossible to open template");
545: FsmOpen(&ctx->bund->ccp.fsm);
546: return (0);
547: }
548:
549: /*
550: * CcpCloseCmd()
551: */
552:
553: int
554: CcpCloseCmd(Context ctx)
555: {
556: if (ctx->bund->tmpl)
557: Error("impossible to close template");
558: FsmClose(&ctx->bund->ccp.fsm);
559: return (0);
560: }
561:
562: /*
563: * CcpFailure()
564: *
565: * If we fail, just shut down and stop trying. However, if encryption
566: * was required and MPPE encryption was enabled, then die here as well.
567: */
568:
569: static void
570: CcpFailure(Fsm fp, enum fsmfail reason)
571: {
572: Bund b = (Bund)fp->arg;
1.1.1.3 ! misho 573:
! 574: (void)reason;
1.1 misho 575: CcpCheckEncryption(b);
576: }
577:
578: /*
579: * CcpStat()
580: */
581:
582: int
1.1.1.3 ! misho 583: CcpStat(Context ctx, int ac, const char *const av[], const void *arg)
1.1 misho 584: {
585: CcpState const ccp = &ctx->bund->ccp;
586: char buf[64];
587:
588: Printf("[%s] %s [%s]\r\n", Pref(&ccp->fsm), Fsm(&ccp->fsm), FsmStateName(ccp->fsm.state));
589: Printf("Enabled protocols:\r\n");
590: OptStat(ctx, &ccp->options, gConfList);
591:
592: #ifdef CCP_MPPC
593: MppcStat(ctx, ac, av, arg);
594: #endif
595: Printf("Outgoing compression:\r\n");
596: Printf("\tProto\t: %s (%s)\r\n", !ccp->xmit ? "none" : ccp->xmit->name,
597: (ccp->xmit && ccp->xmit->Describe) ? (*ccp->xmit->Describe)(ctx->bund, COMP_DIR_XMIT, buf, sizeof(buf)) : "");
598: if (ccp->xmit && ccp->xmit->Stat)
599: ccp->xmit->Stat(ctx, COMP_DIR_XMIT);
600: Printf("\tResets\t: %d\r\n", ccp->xmit_resets);
601:
602: Printf("Incoming decompression:\r\n");
603: Printf("\tProto\t: %s (%s)\r\n", !ccp->recv ? "none" : ccp->recv->name,
604: (ccp->recv && ccp->recv->Describe) ? (*ccp->recv->Describe)(ctx->bund, COMP_DIR_RECV, buf, sizeof(buf)) : "");
605: if (ccp->recv && ccp->recv->Stat)
606: ccp->recv->Stat(ctx, COMP_DIR_RECV);
607: Printf("\tResets\t: %d\r\n", ccp->recv_resets);
608:
609: return(0);
610: }
611:
612: /*
613: * CcpSendResetReq()
614: */
615:
616: void
617: CcpSendResetReq(Bund b)
618: {
619: CcpState const ccp = &b->ccp;
620: CompType const ct = ccp->recv;
621: Fsm const fp = &ccp->fsm;
622: Mbuf bp = NULL;
623:
624: if (ct == NULL) {
625: Log(LG_ERR, ("[%s] %s: CcpSendResetReq() call from undefined decompressor!",
626: Pref(fp), Fsm(fp)));
627: return;
628: }
629:
630: ccp->recv_resets++;
631: if (ct->SendResetReq)
632: bp = (*ct->SendResetReq)(b);
633: Log(LG_CCP, ("[%s] %s: SendResetReq #%d link %d (%s)",
634: Pref(fp), Fsm(fp), fp->reqid, 0, FsmStateName(fp->state)));
635: FsmOutputMbuf(fp, CODE_RESETREQ, fp->reqid++, bp);
636: }
637:
638: /*
639: * CcpRecvResetReq()
640: */
641:
642: static void
643: CcpRecvResetReq(Fsm fp, int id, Mbuf bp)
644: {
645: Bund b = (Bund)fp->arg;
646: CcpState const ccp = &b->ccp;
647: CompType const ct = ccp->xmit;
648: int noAck = 0;
649:
650: ccp->xmit_resets++;
651: bp = (ct && ct->RecvResetReq) ? (*ct->RecvResetReq)(b, id, bp, &noAck) : NULL;
652: if (!noAck) {
653: Log(LG_CCP, ("[%s] %s: SendResetAck #%d link %d (%s)",
654: Pref(fp), Fsm(fp), id, 0, FsmStateName(fp->state)));
655: FsmOutputMbuf(fp, CODE_RESETACK, id, bp);
656: }
657: }
658:
659: /*
660: * CcpRecvResetAck()
661: */
662:
663: static void
664: CcpRecvResetAck(Fsm fp, int id, Mbuf bp)
665: {
666: Bund b = (Bund)fp->arg;
667: CcpState const ccp = &b->ccp;
668: CompType const ct = ccp->recv;
669:
670: if (ct && ct->RecvResetAck)
671: (*ct->RecvResetAck)(b, id, bp);
672: }
673:
674: /*
675: * CcpInput()
676: */
677:
678: void
679: CcpInput(Bund b, Mbuf bp)
680: {
681: FsmInput(&b->ccp.fsm, bp);
682: }
683:
684: /*
685: * CcpDataOutput()
686: *
687: * Compress a frame. Consumes the original packet.
688: */
689:
690: Mbuf
691: CcpDataOutput(Bund b, Mbuf plain)
692: {
693: CcpState const ccp = &b->ccp;
694: Mbuf comp;
695:
696: LogDumpBp(LG_FRAME, plain, "[%s] %s: xmit plain", Pref(&ccp->fsm), Fsm(&ccp->fsm));
697:
698: /* Compress packet */
699:
700: if ((!ccp->xmit) || (!ccp->xmit->Compress))
701: {
702: Log(LG_ERR, ("[%s] %s: no encryption for xmit", Pref(&ccp->fsm), Fsm(&ccp->fsm)));
703: mbfree(plain);
704: return(NULL);
705: }
706: comp = (*ccp->xmit->Compress)(b, plain);
707: LogDumpBp(LG_FRAME, comp, "[%s] %s: xmit comp", Pref(&ccp->fsm), Fsm(&ccp->fsm));
708:
709: return(comp);
710: }
711:
712: /*
713: * CcpDataInput()
714: *
715: * Decompress incoming packet. If packet got garbled, return NULL.
716: * In any case, we consume the packet passed to us.
717: */
718:
719: Mbuf
720: CcpDataInput(Bund b, Mbuf comp)
721: {
722: CcpState const ccp = &b->ccp;
723: Mbuf plain;
724:
725: LogDumpBp(LG_FRAME, comp, "[%s] %s: recv comp", Pref(&ccp->fsm), Fsm(&ccp->fsm));
726:
727: /* Decompress packet */
728:
729: if ((!ccp->recv) || (!ccp->recv->Decompress))
730: {
731: Log(LG_ERR, ("[%s] %s: no compression for recv", Pref(&ccp->fsm), Fsm(&ccp->fsm)));
732: mbfree(comp);
733: return(NULL);
734: }
735:
736: plain = (*ccp->recv->Decompress)(b, comp);
737:
738: /* Encrypted ok? */
739:
740: if (plain == NULL)
741: {
742: Log(LG_CCP, ("[%s] %s: decompression failed", Pref(&ccp->fsm), Fsm(&ccp->fsm)));
743: return(NULL);
744: }
745: LogDumpBp(LG_FRAME, plain, "[%s] %s: recv plain", Pref(&ccp->fsm), Fsm(&ccp->fsm));
746:
747: return(plain);
748: }
749:
750: /*
751: * CcpBuildConfigReq()
752: */
753:
754: static u_char *
755: CcpBuildConfigReq(Fsm fp, u_char *cp)
756: {
757: Bund b = (Bund)fp->arg;
758: CcpState const ccp = &b->ccp;
1.1.1.3 ! misho 759: unsigned type;
1.1 misho 760: int ok;
761:
762: /* Put in all options that peer hasn't rejected in preferred order */
763: ccp->xmit = NULL;
764: for (type = 0; type < CCP_NUM_PROTOS; type++) {
765: CompType const ct = gCompTypes[type];
766:
767: if (Enabled(&ccp->options, type) && !CCP_PEER_REJECTED(ccp, type)) {
768: cp = (*ct->BuildConfigReq)(b, cp, &ok);
769: if (ok && (!ccp->xmit))
770: ccp->xmit = ct;
771: }
772: }
773: return(cp);
774: }
775:
776: /*
777: * CcpLayerUp()
778: */
779:
780: static void
781: CcpLayerUp(Fsm fp)
782: {
783: Bund b = (Bund)fp->arg;
784: CcpState const ccp = &b->ccp;
785: struct ngm_connect cn;
786: char buf[64];
787:
788: /* If nothing was negotiated in either direction, close CCP */
789: if ((!ccp->recv || !(*ccp->recv->Negotiated)(b, COMP_DIR_RECV))
790: && (!ccp->xmit || !(*ccp->xmit->Negotiated)(b, COMP_DIR_XMIT))) {
791: Log(LG_CCP, ("[%s] %s: No compression negotiated", Pref(fp), Fsm(fp)));
792: FsmFailure(fp, FAIL_NEGOT_FAILURE);
793: return;
794: }
795:
796: /* Check for required encryption */
797: if (CcpCheckEncryption(b) < 0) {
798: return;
799: }
800:
801: /* Initialize each direction */
802: if (ccp->xmit != NULL && ccp->xmit->Init != NULL
803: && (*ccp->xmit->Init)(b, COMP_DIR_XMIT) < 0) {
804: Log(LG_CCP, ("[%s] %s: compression init failed", Pref(fp), Fsm(fp)));
805: FsmFailure(fp, FAIL_NEGOT_FAILURE); /* XXX */
806: return;
807: }
808: if (ccp->recv != NULL && ccp->recv->Init != NULL
809: && (*ccp->recv->Init)(b, COMP_DIR_RECV) < 0) {
810: Log(LG_CCP, ("[%s] %s: decompression init failed", Pref(fp), Fsm(fp)));
811: FsmFailure(fp, FAIL_NEGOT_FAILURE); /* XXX */
812: return;
813: }
814:
815: if (ccp->xmit != NULL && ccp->xmit->Compress != NULL) {
816: /* Connect a hook from the ppp node to our socket node */
817: snprintf(cn.path, sizeof(cn.path), "[%x]:", b->nodeID);
818: snprintf(cn.ourhook, sizeof(cn.ourhook), "c%d", b->id);
819: strcpy(cn.peerhook, NG_PPP_HOOK_COMPRESS);
820: if (NgSendMsg(gCcpCsock, ".:",
821: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
822: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
823: b->name, ".:", cn.ourhook, cn.path, cn.peerhook);
824: }
825: }
826:
827: if (ccp->recv != NULL && ccp->recv->Decompress != NULL) {
828: /* Connect a hook from the ppp node to our socket node */
829: snprintf(cn.path, sizeof(cn.path), "[%x]:", b->nodeID);
830: snprintf(cn.ourhook, sizeof(cn.ourhook), "d%d", b->id);
831: strcpy(cn.peerhook, NG_PPP_HOOK_DECOMPRESS);
832: if (NgSendMsg(gCcpCsock, ".:",
833: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
834: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
835: b->name, ".:", cn.ourhook, cn.path, cn.peerhook);
836: }
837: }
838:
839: /* Report what we're doing */
840: Log(LG_CCP, ("[%s] CCP: Compress using: %s (%s)", b->name, !ccp->xmit ? "none" : ccp->xmit->name,
841: (ccp->xmit && ccp->xmit->Describe) ? (*ccp->xmit->Describe)(b, COMP_DIR_XMIT, buf, sizeof(buf)) : ""));
842: Log(LG_CCP, ("[%s] CCP: Decompress using: %s (%s)", b->name, !ccp->recv ? "none" : ccp->recv->name,
843: (ccp->recv && ccp->recv->Describe) ? (*ccp->recv->Describe)(b, COMP_DIR_RECV, buf, sizeof(buf)) : ""));
844:
845: /* Update PPP node config */
846: b->pppConfig.bund.enableCompression = (ccp->xmit != NULL)?ccp->xmit->mode:0;
847: b->pppConfig.bund.enableDecompression = (ccp->recv != NULL)?ccp->recv->mode:0;
848: NgFuncSetConfig(b);
849:
850: /* Update interface MTU */
851: BundUpdateParams(b);
852: }
853:
854: /*
855: * CcpLayerDown()
856: */
857:
858: static void
859: CcpLayerDown(Fsm fp)
860: {
861: Bund b = (Bund)fp->arg;
862: CcpState const ccp = &b->ccp;
863:
864: /* Update PPP node config */
865: b->pppConfig.bund.enableCompression = 0;
866: b->pppConfig.bund.enableDecompression = 0;
867: NgFuncSetConfig(b);
868:
869: /* Update interface MTU */
870: BundUpdateParams(b);
871:
872: if (ccp->xmit != NULL && ccp->xmit->Compress != NULL) {
873: char hook[NG_HOOKSIZ];
874: /* Disconnect hook. */
875: snprintf(hook, sizeof(hook), "c%d", b->id);
876: NgFuncDisconnect(gCcpCsock, b->name, ".:", hook);
877: }
878:
879: if (ccp->recv != NULL && ccp->recv->Decompress != NULL) {
880: char hook[NG_HOOKSIZ];
881: /* Disconnect hook. */
882: snprintf(hook, sizeof(hook), "d%d", b->id);
883: NgFuncDisconnect(gCcpCsock, b->name, ".:", hook);
884: }
885: if (ccp->recv && ccp->recv->Cleanup)
886: (*ccp->recv->Cleanup)(b, COMP_DIR_RECV);
887: if (ccp->xmit && ccp->xmit->Cleanup)
888: (*ccp->xmit->Cleanup)(b, COMP_DIR_XMIT);
889:
890: ccp->xmit_resets = 0;
891: ccp->recv_resets = 0;
892: }
893:
894: /*
895: * CcpDecodeConfig()
896: */
897:
898: static void
899: CcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode)
900: {
901: Bund b = (Bund)fp->arg;
902: CcpState const ccp = &b->ccp;
903: u_int ackSizeSave, rejSizeSave;
904: int k, rej;
905:
906: /* Forget our previous choice on new request */
907: if (mode == MODE_REQ)
908: ccp->recv = NULL;
909:
910: /* Decode each config option */
911: for (k = 0; k < num; k++) {
912: FsmOption const opt = &list[k];
913: int index;
914: CompType ct;
915: char buf[32];
916:
917: Log(LG_CCP, ("[%s] %s", b->name, CcpTypeName(opt->type, buf, sizeof(buf))));
918: if ((ct = CcpFindComp(opt->type, &index)) == NULL) {
919: if (mode == MODE_REQ) {
920: Log(LG_CCP, ("[%s] Not supported", b->name));
921: FsmRej(fp, opt);
922: }
923: continue;
924: }
925: switch (mode) {
926: case MODE_REQ:
927: ackSizeSave = gAckSize;
928: rejSizeSave = gRejSize;
929: rej = (!Acceptable(&ccp->options, index)
930: || CCP_SELF_REJECTED(ccp, index)
931: || (ccp->recv && ccp->recv != ct));
932: if (rej) {
933: (*ct->DecodeConfig)(fp, opt, MODE_NOP);
934: FsmRej(fp, opt);
935: break;
936: }
937: (*ct->DecodeConfig)(fp, opt, mode);
938: if (gRejSize != rejSizeSave) { /* we rejected it */
939: CCP_SELF_REJ(ccp, index);
940: break;
941: }
942: if (gAckSize != ackSizeSave) /* we accepted it */
943: ccp->recv = ct;
944: break;
945:
946: case MODE_REJ:
947: (*ct->DecodeConfig)(fp, opt, mode);
948: CCP_PEER_REJ(ccp, index);
949: break;
950:
951: case MODE_NAK:
952: case MODE_NOP:
953: (*ct->DecodeConfig)(fp, opt, mode);
954: break;
955: }
956: }
957: }
958:
959: /*
960: * CcpSubtractBloat()
961: *
962: * Given that "size" is our MTU, return the maximum length frame
963: * we can compress without the result being longer than "size".
964: */
965:
966: int
967: CcpSubtractBloat(Bund b, int size)
968: {
969: CcpState const ccp = &b->ccp;
970:
971: /* Account for transmit compression overhead */
972: if (OPEN_STATE(ccp->fsm.state) && ccp->xmit && ccp->xmit->SubtractBloat)
973: size = (*ccp->xmit->SubtractBloat)(b, size);
974:
975: /* Account for CCP's protocol number overhead */
976: if (OPEN_STATE(ccp->fsm.state))
977: size -= CCP_OVERHEAD;
978:
979: /* Done */
980: return(size);
981: }
982:
983: /*
984: * CcpCheckEncryption()
985: *
986: * Because MPPE is negotiated as an option to MPPC compression,
987: * we have to check for encryption required when CCP comes up.
988: */
989:
990: static int
991: CcpCheckEncryption(Bund b)
992: {
993: #if 0
994: CcpState const ccp = &b->ccp;
995:
996: /* Already checked? */
997: if (ccp->crypt_check)
998: return(0);
999: ccp->crypt_check = 1;
1000:
1001: /* Is encryption required? */
1002: if (Enabled(&ccp->options, gMppePolicy)) {
1003: if (b->params.msoft.policy != MPPE_POLICY_REQUIRED)
1004: return(0);
1005: } else {
1006: if (!Enabled(&b->conf.options, BUND_CONF_CRYPT_REQD))
1007: return(0);
1008: }
1009:
1010: /* Was MPPE encryption enabled? If not, ignore requirement */
1011: if (!Enabled(&ccp->options, gMppe40)
1012: && !Enabled(&ccp->options, gMppe56)
1013: && !Enabled(&ccp->options, gMppe128)
1014: && !Enabled(&ccp->options, gMppePolicy))
1015: return(0);
1016:
1017: /* Make sure MPPE was negotiated in both directions */
1018: if (!OPEN_STATE(ccp->fsm.state)
1019: || !ccp->xmit || ccp->xmit->type != CCP_TY_MPPC
1020: || !ccp->recv || ccp->recv->type != CCP_TY_MPPC
1021: #ifdef CCP_MPPC
1022: || !(ccp->mppc.recv_bits & MPPE_BITS)
1023: || !(ccp->mppc.xmit_bits & MPPE_BITS)
1024: #endif
1025: )
1026: goto fail;
1027:
1028: /* Looks OK */
1029: return(0);
1030:
1031: fail:
1032: Log(LG_ERR, ("[%s] %s: encryption required, but MPPE was not"
1033: " negotiated in both directions", Pref(&ccp->fsm), Fsm(&ccp->fsm)));
1034: FsmFailure(&ccp->fsm, FAIL_CANT_ENCRYPT);
1035: FsmFailure(&b->ipcp.fsm, FAIL_CANT_ENCRYPT);
1036: FsmFailure(&b->ipv6cp.fsm, FAIL_CANT_ENCRYPT);
1037: return(-1);
1.1.1.3 ! misho 1038: #else
! 1039: (void)b;
1.1 misho 1040: #endif
1041: return (0);
1042: }
1043:
1044: /*
1045: * CcpSetCommand()
1046: */
1047:
1048: static int
1.1.1.3 ! misho 1049: CcpSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
1.1 misho 1050: {
1051: CcpState const ccp = &ctx->bund->ccp;
1052:
1053: if (ac == 0)
1054: return(-1);
1055: switch ((intptr_t)arg) {
1056: case SET_ACCEPT:
1057: AcceptCommand(ac, av, &ccp->options, gConfList);
1058: break;
1059:
1060: case SET_DENY:
1061: DenyCommand(ac, av, &ccp->options, gConfList);
1062: break;
1063:
1064: case SET_ENABLE:
1065: EnableCommand(ac, av, &ccp->options, gConfList);
1066: break;
1067:
1068: case SET_DISABLE:
1069: DisableCommand(ac, av, &ccp->options, gConfList);
1070: break;
1071:
1072: case SET_YES:
1073: YesCommand(ac, av, &ccp->options, gConfList);
1074: break;
1075:
1076: case SET_NO:
1077: NoCommand(ac, av, &ccp->options, gConfList);
1078: break;
1079:
1080: default:
1081: assert(0);
1082: }
1083: return(0);
1084: }
1085:
1086: /*
1087: * CcpFindComp()
1088: */
1089:
1090: static CompType
1091: CcpFindComp(int type, int *indexp)
1092: {
1.1.1.3 ! misho 1093: unsigned k;
1.1 misho 1094:
1095: for (k = 0; k < CCP_NUM_PROTOS; k++) {
1096: if (gCompTypes[k]->type == type) {
1097: if (indexp)
1098: *indexp = k;
1099: return(gCompTypes[k]);
1100: }
1101: }
1102: return(NULL);
1103: }
1104:
1105: /*
1106: * CcpTypeName()
1107: */
1108:
1109: static const char *
1110: CcpTypeName(int type, char *buf, size_t len)
1111: {
1112: const struct ccpname *p;
1113:
1114: for (p = gCcpTypeNames; p->name; p++) {
1115: if (p->type == type) {
1116: strlcpy(buf, p->name, len);
1117: return (buf);
1118: }
1119: }
1120: snprintf(buf, sizeof(buf), "UNKNOWN[%d]", type);
1121: return(buf);
1122: }
1123:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>