Annotation of embedaddon/libpdel/ppp/ppp_ccp.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include "ppp/ppp_defs.h"
42: #include "ppp/ppp_log.h"
43: #include "ppp/ppp_fsm_option.h"
44: #include "ppp/ppp_fsm.h"
45: #include "ppp/ppp_auth.h"
46: #include "ppp/ppp_node.h"
47: #include "ppp/ppp_ccp.h"
48:
49: #include <netgraph/ng_mppc.h>
50:
51: #ifndef MPPE_56
52: #define MPPE_56 0x00000080
53: #undef MPPE_BITS
54: #define MPPE_BITS 0x000000e0
55: #endif
56:
57: /*
58: * CCP FSM
59: *
60: * XXX This is hard coded to only support MPPC/MPPE compression.
61: * XXX It should be generalized to support multiple PPP compression types.
62: */
63:
64: #define MPPC_SUPPORTED (MPPC_BIT | MPPE_BITS | MPPE_STATELESS)
65:
66: /* Memory type */
67: #define CCP_MTYPE "ccp"
68:
69: /* CCP compression types */
70: enum ccp_type {
71: CCP_OPT_OUI =0, /* oui */
72: CCP_OPT_PRED1 =1, /* predictor type 1 */
73: CCP_OPT_PRED2 =2, /* predictor type 2 */
74: CCP_OPT_PUDDLE =3, /* puddle jumper */
75: CCP_OPT_HWPPC =16, /* hewlett-packard ppc */
76: CCP_OPT_STAC =17, /* stac electronics lzs */
77: CCP_OPT_MPPC =18, /* microsoft mppc/mppe */
78: CCP_OPT_GAND =19, /* gandalf fza */
79: CCP_OPT_V42BIS =20, /* v.42bis compression */
80: CCP_OPT_BSD =21, /* bsd lzw compress */
81: CCP_OPT_DEFLATE =24, /* gzip "deflate" compression */
82: };
83:
84: /* Supported and required FSM codes */
85: #define CCP_SUPPORTED_CODES \
86: (1 << FSM_CODE_CONFIGREQ) \
87: | (1 << FSM_CODE_CONFIGACK) \
88: | (1 << FSM_CODE_CONFIGNAK) \
89: | (1 << FSM_CODE_CONFIGREJ) \
90: | (1 << FSM_CODE_TERMREQ) \
91: | (1 << FSM_CODE_TERMACK) \
92: | (1 << FSM_CODE_CODEREJ) \
93: | (1 << FSM_CODE_RESETREQ) \
94: | (1 << FSM_CODE_RESETACK)
95: #define CCP_REQUIRED_CODES \
96: (1 << FSM_CODE_CONFIGREQ) \
97: | (1 << FSM_CODE_CONFIGACK) \
98: | (1 << FSM_CODE_CONFIGNAK) \
99: | (1 << FSM_CODE_CONFIGREJ) \
100: | (1 << FSM_CODE_TERMREQ) \
101: | (1 << FSM_CODE_TERMACK) \
102: | (1 << FSM_CODE_CODEREJ) \
103: | (1 << FSM_CODE_RESETREQ) \
104: | (1 << FSM_CODE_RESETACK)
105:
106: /* FSM options descriptors */
107: static opt_pr_t ppp_cpp_pr_mppc;
108:
109: static const struct ppp_fsm_optdesc ccp_opt_desc[] = {
110: { "OUI", CCP_OPT_OUI, 0, 255, 0, NULL },
111: { "Predictor-1",CCP_OPT_PRED1, 0, 255, 0, NULL },
112: { "Predictor-2",CCP_OPT_PRED2, 0, 255, 0, NULL },
113: { "Puddle", CCP_OPT_PUDDLE, 0, 255, 0, NULL },
114: { "HWPPC", CCP_OPT_HWPPC, 0, 255, 0, NULL },
115: { "Stac", CCP_OPT_STAC, 0, 255, 0, NULL },
116: { "MPPC/MPPE", CCP_OPT_MPPC, 4, 4, 1, ppp_cpp_pr_mppc },
117: { "Gandalf", CCP_OPT_GAND, 0, 255, 0, NULL },
118: { "v.42bis", CCP_OPT_V42BIS, 0, 255, 0, NULL },
119: { "BSD-LZW", CCP_OPT_BSD, 0, 255, 0, NULL },
120: { "Deflate", CCP_OPT_DEFLATE,0, 255, 0, NULL },
121: { NULL, 0, 0, 0, 0, NULL }
122: };
123:
124: /* FSM type for CCP */
125: static ppp_fsm_type_destroy_t ppp_ccp_destroy;
126: static ppp_fsm_type_build_conf_req_t ppp_ccp_build_conf_req;
127: static ppp_fsm_type_recv_conf_req_t ppp_ccp_recv_conf_req;
128: static ppp_fsm_type_recv_conf_rej_t ppp_ccp_recv_conf_rej;
129: static ppp_fsm_type_recv_conf_nak_t ppp_ccp_recv_conf_nak;
130: static ppp_fsm_type_recv_reset_req_t ppp_ccp_recv_reset_req;
131: static ppp_fsm_type_recv_reset_ack_t ppp_ccp_recv_reset_ack;
132:
133: const struct ppp_fsm_type ppp_fsm_ccp = {
134: "CCP",
135: PPP_PROTO_CCP,
136: CCP_SUPPORTED_CODES,
137: CCP_REQUIRED_CODES,
138: ccp_opt_desc,
139: NULL,
140: ppp_ccp_destroy,
141: ppp_ccp_build_conf_req,
142: ppp_ccp_recv_conf_req,
143: ppp_ccp_recv_conf_rej,
144: ppp_ccp_recv_conf_nak,
145: NULL,
146: ppp_ccp_recv_reset_req,
147: ppp_ccp_recv_reset_ack,
148: NULL
149: };
150:
151: /* CCP instance state */
152: struct ccp {
153: struct ppp_fsm_instance *inst; /* backpointer to instance */
154: struct ppp_ccp_config conf; /* initial config */
155: struct ppp_ccp_req req; /* current request state */
156: struct ppp_node *node; /* ng_ppp(4) node */
157: };
158:
159: /* Internal functions */
160: static ppp_node_recvmsg_t ppp_ccp_send_reset_req;
161:
162: /***********************************************************************
163: PUBLIC FUNCTIONS
164: ***********************************************************************/
165:
166: struct ppp_fsm_instance *
167: ppp_ccp_create(struct ppp_ccp_config *conf, struct ppp_node *node)
168: {
169: struct ppp_fsm_instance *inst;
170: struct ppp_ccp_req *req;
171: struct ccp *ccp = NULL;
172:
173: /* Construct instance object */
174: if ((inst = MALLOC(CCP_MTYPE, sizeof(*inst))) == NULL)
175: return (NULL);
176: memset(inst, 0, sizeof(*inst));
177: inst->type = &ppp_fsm_ccp;
178:
179: /* Attach private data */
180: if ((ccp = MALLOC(CCP_MTYPE, sizeof(*ccp))) == NULL)
181: goto fail;
182: memset(ccp, 0, sizeof(*ccp));
183: ccp->conf = *conf;
184: ccp->node = node;
185: ccp->inst = inst;
186: inst->arg = ccp;
187:
188: /* Initialize local request state */
189: req = &ccp->req;
190: req->mppc[PPP_SELF] = conf->mppc[PPP_SELF];
191: req->mppe40[PPP_SELF] = conf->mppe40[PPP_SELF];
192: req->mppe56[PPP_SELF] = conf->mppe56[PPP_SELF];
193: req->mppe128[PPP_SELF] = conf->mppe128[PPP_SELF];
194: req->mppe_stateless[PPP_SELF] = conf->mppe_stateless[PPP_SELF];
195:
196: /* Register handler for reset-req control message from ng_mppc(4) */
197: if (ppp_node_set_recvmsg(ccp->node, NGM_MPPC_COOKIE,
198: NGM_MPPC_RESETREQ, ppp_ccp_send_reset_req, ccp) == -1)
199: goto fail;
200:
201: /* Done */
202: return (inst);
203:
204: fail:
205: /* Clean up after failure */
206: if (ccp != NULL)
207: FREE(CCP_MTYPE, ccp);
208: FREE(CCP_MTYPE, inst);
209: return (NULL);
210: }
211:
212: /*
213: * Get CCP request state.
214: */
215: void
216: ppp_ccp_get_req(struct ppp_fsm *fsm, struct ppp_ccp_req *req)
217: {
218: struct ppp_fsm_instance *const inst = ppp_fsm_get_instance(fsm);
219: struct ccp *const ccp = inst->arg;
220:
221: assert(inst->type == &ppp_fsm_ccp);
222: memcpy(req, &ccp->req, sizeof(*req));
223: }
224:
225: /***********************************************************************
226: FSM CALLBACKS
227: ***********************************************************************/
228:
229: static void
230: ppp_ccp_destroy(struct ppp_fsm_instance *inst)
231: {
232: struct ccp *const ccp = inst->arg;
233:
234: ppp_node_set_recvmsg(ccp->node,
235: NGM_MPPC_COOKIE, NGM_MPPC_RESETREQ, NULL, NULL);
236: FREE(CCP_MTYPE, ccp);
237: FREE(CCP_MTYPE, inst);
238: }
239:
240: static int
241: ppp_ccp_build_conf_req(struct ppp_fsm_instance *fsm,
242: struct ppp_fsm_options *opts)
243: {
244: struct ccp *const ccp = (struct ccp *)fsm->arg;
245: struct ppp_ccp_req *const req = &ccp->req;
246: u_int32_t mppo = 0;
247:
248: /* Add MPPC/MPPE requested config options */
249: if (req->mppc[PPP_SELF])
250: mppo |= MPPC_BIT;
251: if (req->mppe40[PPP_SELF])
252: mppo |= MPPE_40;
253: if (req->mppe56[PPP_SELF])
254: mppo |= MPPE_56;
255: if (req->mppe128[PPP_SELF])
256: mppo |= MPPE_128;
257: if (req->mppe_stateless[PPP_SELF])
258: mppo |= MPPE_STATELESS;
259:
260: /* If no options left to try, don't ask for anything */
261: if ((mppo & (MPPC_BIT | MPPE_BITS)) == 0) {
262: errno = EINVAL;
263: return (-1);
264: }
265:
266: /* Add option */
267: mppo = htonl(mppo);
268: if (ppp_fsm_option_add(opts, CCP_OPT_MPPC, 4, &mppo) == -1)
269: return (-1);
270:
271: /* Done */
272: return (0);
273: }
274:
275: static int
276: ppp_ccp_recv_conf_req(struct ppp_fsm_instance *fsm,
277: struct ppp_fsm_options *crq, struct ppp_fsm_options *nak,
278: struct ppp_fsm_options *rej)
279: {
280: struct ccp *const ccp = (struct ccp *)fsm->arg;
281: struct ppp_ccp_config *const conf = &ccp->conf;
282: struct ppp_ccp_req *const req = &ccp->req;
283: int i;
284:
285: /* Initialize peer's request state */
286: req->mppc[PPP_PEER] = 0;
287: req->mppe40[PPP_PEER] = 0;
288: req->mppe56[PPP_PEER] = 0;
289: req->mppe128[PPP_PEER] = 0;
290: req->mppe_stateless[PPP_PEER] = 0;
291:
292: /* Process options */
293: for (i = 0; i < crq->num; i++) {
294: const struct ppp_fsm_option *const opt = &crq->opts[i];
295:
296: switch (opt->type) {
297: case CCP_OPT_MPPC:
298: {
299: u_int32_t obits;
300: u_int32_t bits;
301:
302: /* Get requested bits */
303: memcpy(&obits, opt->data, 4);
304: obits = ntohl(obits);
305: bits = obits;
306:
307: /* Filter out bits we can't handle */
308: bits &= MPPC_SUPPORTED;
309: if ((bits & MPPC_BIT) != 0 && !conf->mppc[PPP_PEER])
310: bits &= ~MPPC_BIT;
311: if ((bits & MPPE_40) != 0 && !conf->mppe40[PPP_PEER])
312: bits &= ~MPPE_40;
313: if ((bits & MPPE_56) != 0 && !conf->mppe56[PPP_PEER])
314: bits &= ~MPPE_56;
315: if ((bits & MPPE_128) != 0 && !conf->mppe128[PPP_PEER])
316: bits &= ~MPPE_128;
317: if ((bits & MPPE_STATELESS) != 0
318: && !conf->mppe_stateless[PPP_PEER])
319: bits &= ~MPPE_STATELESS;
320:
321: /*
322: * It doesn't really make sense to do MPPE encryption
323: * in only one direction. Also, Win95/98 PPTP can't
324: * handle uni-directional encryption. So if the remote
325: * side doesn't request encryption, try to prompt it.
326: * This is broken wrt. normal PPP negotiation: typical
327: * Microsoft.
328: */
329: if ((bits & MPPE_BITS) == 0) {
330: if (req->mppe40[PPP_SELF])
331: bits |= MPPE_40;
332: if (req->mppe56[PPP_SELF])
333: bits |= MPPE_56;
334: if (req->mppe128[PPP_SELF])
335: bits |= MPPE_128;
336: }
337:
338: /* Make sure we're not left with no options */
339: if ((bits & MPPE_BITS) == 0) {
340: if (ccp->conf.mppe40[PPP_SELF])
341: bits |= MPPE_40;
342: if (ccp->conf.mppe56[PPP_SELF])
343: bits |= MPPE_56;
344: if (ccp->conf.mppe128[PPP_SELF])
345: bits |= MPPE_128;
346: }
347:
348: /* Now choose the strongest encryption available */
349: if ((bits & MPPE_128) != 0)
350: bits &= ~(MPPE_56|MPPE_40);
351: else if ((bits & MPPE_56) != 0)
352: bits &= ~(MPPE_128|MPPE_40);
353: else if ((bits & MPPE_40) != 0)
354: bits &= ~(MPPE_128|MPPE_56);
355:
356: /* Send back a nak if there were any changes */
357: if (bits != obits) {
358: bits = htonl(bits);
359: if (ppp_fsm_option_add(nak,
360: opt->type, 4, &bits) == -1)
361: return (-1);
362: break;
363: }
364:
365: /* Peer's request is accepted */
366: req->mppc[PPP_PEER] = (bits & MPPC_BIT) != 0;
367: req->mppe40[PPP_PEER] = (bits & MPPE_40) != 0;
368: req->mppe56[PPP_PEER] = (bits & MPPE_56) != 0;
369: req->mppe128[PPP_PEER] = (bits & MPPE_128) != 0;
370: req->mppe_stateless[PPP_PEER]
371: = (bits & MPPE_STATELESS) != 0;
372: break;
373: }
374: default:
375: goto reject;
376: }
377:
378: /* OK */
379: continue;
380:
381: reject:
382: /* Reject this requested option */
383: if (ppp_fsm_option_add(rej,
384: opt->type, opt->len, opt->data) == -1)
385: return (-1);
386: }
387:
388: /* If there were no options, shut down */
389: if (crq->num == 0) {
390: errno = EINVAL;
391: return (-1);
392: }
393:
394: /* Done */
395: return (0);
396: }
397:
398: static int
399: ppp_ccp_recv_conf_rej(struct ppp_fsm_instance *fsm,
400: struct ppp_fsm_options *rej)
401: {
402: int i;
403:
404: for (i = 0; i < rej->num; i++) {
405: const struct ppp_fsm_option *const opt = &rej->opts[i];
406:
407: switch (opt->type) {
408: case CCP_OPT_MPPC:
409: errno = EINVAL;
410: return (-1);
411: default:
412: break;
413: }
414: }
415:
416: /* Done */
417: return (0);
418: }
419:
420: static int
421: ppp_ccp_recv_conf_nak(struct ppp_fsm_instance *fsm,
422: struct ppp_fsm_options *nak)
423: {
424: struct ccp *const ccp = (struct ccp *)fsm->arg;
425: struct ppp_ccp_req *const req = &ccp->req;
426: int i;
427:
428: for (i = 0; i < nak->num; i++) {
429: const struct ppp_fsm_option *const opt = &nak->opts[i];
430:
431: switch (opt->type) {
432: case CCP_OPT_MPPC:
433: {
434: u_int32_t bits;
435:
436: memcpy(&bits, opt->data, 4);
437: bits = ntohl(bits);
438:
439: /* Mask away bits the client didn't like */
440: if ((bits & MPPC_BIT) == 0)
441: req->mppc[PPP_SELF] = 0;
442: if ((bits & MPPE_40) == 0)
443: req->mppe40[PPP_SELF] = 0;
444: if ((bits & MPPE_56) == 0)
445: req->mppe56[PPP_SELF] = 0;
446: if ((bits & MPPE_128) == 0)
447: req->mppe128[PPP_SELF] = 0;
448: if ((bits & MPPE_STATELESS) == 0)
449: req->mppe_stateless[PPP_SELF] = 0;
450:
451: /* Make sure we're not left with no options */
452: if ((bits & MPPE_BITS) == 0) {
453: if (ccp->conf.mppe40[PPP_SELF])
454: bits |= MPPE_40;
455: if (ccp->conf.mppe56[PPP_SELF])
456: bits |= MPPE_56;
457: if (ccp->conf.mppe128[PPP_SELF])
458: bits |= MPPE_128;
459: }
460: break;
461: }
462: default:
463: break;
464: }
465: }
466:
467: /* Done */
468: return (0);
469: }
470:
471: /*
472: * Receive a Reset-Req from peer. Relay request to the ng_mppc(4) node.
473: */
474: static void
475: ppp_ccp_recv_reset_req(struct ppp_fsm_instance *fsm,
476: const u_char *data, u_int len)
477: {
478: struct ccp *const ccp = (struct ccp *)fsm->arg;
479:
480: ppp_node_send_msg(ccp->node, NG_PPP_HOOK_COMPRESS,
481: NGM_MPPC_COOKIE, NGM_MPPC_RESETREQ, NULL, 0);
482: }
483:
484: /*
485: * Receive a Reset-Ack.
486: */
487: static void
488: ppp_ccp_recv_reset_ack(struct ppp_fsm_instance *fsm,
489: const u_char *data, u_int len)
490: {
491: return; /* not used by MPPC/MPPE, just ignore it */
492: }
493:
494: /***********************************************************************
495: INTERNAL FUNCTIONS
496: ***********************************************************************/
497:
498: static void
499: ppp_ccp_send_reset_req(void *arg, struct ng_mesg *msg)
500: {
501: struct ccp *const ccp = arg;
502: struct ppp_fsm *const fsm = ccp->inst->fsm;
503:
504: ppp_fsm_send_reset_req(fsm, NULL, 0);
505: }
506:
507: static void
508: ppp_cpp_pr_mppc(const struct ppp_fsm_optdesc *desc,
509: const struct ppp_fsm_option *opt, char *buf, size_t bmax)
510: {
511: static const struct {
512: u_int32_t bit;
513: const char *name;
514: } mppe_bits[] = {
515: { MPPC_BIT, "MPPC" },
516: { MPPE_BITS, "MPPE" },
517: { MPPE_40, "40 bit" },
518: { MPPE_56, "56 bit" },
519: { MPPE_128, "128 bit" },
520: { MPPE_STATELESS, "stateless" },
521: { 0 }
522: };
523: u_int32_t mppo;
524: int first;
525: int i;
526:
527: if (opt->len < 4) {
528: snprintf(buf, bmax, "<truncated>");
529: return;
530: }
531: memcpy(&mppo, opt->data, 4);
532: mppo = ntohl(mppo);
533: *buf = '\0';
534: for (first = 1, i = 0; mppe_bits[i].bit != 0; i++) {
535: if ((mppo & mppe_bits[i].bit) != 0) {
536: snprintf(buf + strlen(buf), bmax - strlen(buf),
537: "%s%s", first ? "" : ", ", mppe_bits[i].name);
538: first = 0;
539: }
540: }
541: }
542:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>