Annotation of embedaddon/libpdel/ppp/ppp_ipcp.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_ipcp.h"
47:
48: /* Whether to do VJC compressed CID's */
49: #define IPCP_ALLOW_SELF_COMPCID 0 /* whether we allow to recv */
50: #define IPCP_ALLOW_PEER_COMPCID 1 /* whether we allow to send */
51:
52: /* Memory type */
53: #define IPCP_MTYPE "ipcp"
54:
55: /* IPCP configuration options */
56: enum ipcp_option {
57: IPCP_OPT_IP =3, /* ip address */
58: IPCP_OPT_COMP =2, /* compression */
59: IPCP_OPT_DNS1 =129, /* primary dns */
60: IPCP_OPT_DNS2 =131, /* secondary dns */
61: IPCP_OPT_NBNS1 =130, /* primary nbns */
62: IPCP_OPT_NBNS2 =132, /* secondary nbns */
63: };
64:
65: static const u_char ipcp_dns_opts[2] = { IPCP_OPT_DNS1, IPCP_OPT_DNS2 };
66: static const u_char ipcp_nbns_opts[2] = { IPCP_OPT_NBNS1, IPCP_OPT_NBNS2 };
67:
68: /* Supported and required FSM codes */
69: #define IPCP_SUPPORTED_CODES \
70: (1 << FSM_CODE_CONFIGREQ) \
71: | (1 << FSM_CODE_CONFIGACK) \
72: | (1 << FSM_CODE_CONFIGNAK) \
73: | (1 << FSM_CODE_CONFIGREJ) \
74: | (1 << FSM_CODE_TERMREQ) \
75: | (1 << FSM_CODE_TERMACK) \
76: | (1 << FSM_CODE_CODEREJ)
77: #define IPCP_REQUIRED_CODES \
78: (1 << FSM_CODE_CONFIGREQ) \
79: | (1 << FSM_CODE_CONFIGACK) \
80: | (1 << FSM_CODE_CONFIGNAK) \
81: | (1 << FSM_CODE_CONFIGREJ) \
82: | (1 << FSM_CODE_TERMREQ) \
83: | (1 << FSM_CODE_TERMACK) \
84: | (1 << FSM_CODE_CODEREJ)
85:
86: /* FSM options descriptors */
87: static opt_pr_t ppp_ipcp_pr_ip;
88: static opt_pr_t ppp_ipcp_pr_ipcomp;
89:
90: static const struct ppp_fsm_optdesc ipcp_opt_desc[] = {
91: { "IP-Addr", IPCP_OPT_IP, 4, 4, 1, ppp_ipcp_pr_ip },
92: { "IP-Comp", IPCP_OPT_COMP, 4, 4, 1, ppp_ipcp_pr_ipcomp },
93: { "DNS1", IPCP_OPT_DNS1, 4, 4, 1, ppp_ipcp_pr_ip },
94: { "DNS2", IPCP_OPT_DNS2, 4, 4, 1, ppp_ipcp_pr_ip },
95: { "NBNS1", IPCP_OPT_NBNS1, 4, 4, 1, ppp_ipcp_pr_ip },
96: { "NBNS2", IPCP_OPT_NBNS2, 4, 4, 1, ppp_ipcp_pr_ip },
97: { NULL, 0, 0, 0, 0, NULL }
98: };
99:
100: /* FSM type for IPCP */
101: static ppp_fsm_type_destroy_t ppp_ipcp_destroy;
102: static ppp_fsm_type_build_conf_req_t ppp_ipcp_build_conf_req;
103: static ppp_fsm_type_recv_conf_req_t ppp_ipcp_recv_conf_req;
104: static ppp_fsm_type_recv_conf_rej_t ppp_ipcp_recv_conf_rej;
105: static ppp_fsm_type_recv_conf_nak_t ppp_ipcp_recv_conf_nak;
106:
107: const struct ppp_fsm_type ppp_fsm_ipcp = {
108: "IPCP",
109: PPP_PROTO_IPCP,
110: IPCP_SUPPORTED_CODES,
111: IPCP_REQUIRED_CODES,
112: ipcp_opt_desc,
113: NULL,
114: ppp_ipcp_destroy,
115: ppp_ipcp_build_conf_req,
116: ppp_ipcp_recv_conf_req,
117: ppp_ipcp_recv_conf_rej,
118: ppp_ipcp_recv_conf_nak,
119: NULL,
120: NULL,
121: NULL,
122: NULL
123: };
124:
125: /* IPCP instance state */
126: struct ipcp {
127: struct ppp_ipcp_config conf; /* initial config */
128: struct ppp_ipcp_req req; /* current request state */
129: struct ppp_node *node; /* ng_ppp(4) node */
130: };
131:
132: /* VJC compression header */
133: struct ipcp_vjc {
134: u_int16_t proto;
135: u_char maxchan;
136: u_char compcid;
137: };
138:
139: /***********************************************************************
140: PUBLIC FUNCTIONS
141: ***********************************************************************/
142:
143: struct ppp_fsm_instance *
144: ppp_ipcp_create(struct ppp_ipcp_config *conf, struct ppp_node *node)
145: {
146: struct ppp_fsm_instance *inst;
147: struct ppp_ipcp_req *req;
148: struct ipcp *ipcp = NULL;
149:
150: /* Construct instance object */
151: if ((inst = MALLOC(IPCP_MTYPE, sizeof(*inst))) == NULL)
152: return (NULL);
153: memset(inst, 0, sizeof(*inst));
154: inst->type = &ppp_fsm_ipcp;
155:
156: /* Attach private data */
157: if ((ipcp = MALLOC(IPCP_MTYPE, sizeof(*ipcp))) == NULL)
158: goto fail;
159: memset(ipcp, 0, sizeof(*ipcp));
160: ipcp->conf = *conf;
161: ipcp->node = node;
162: inst->arg = ipcp;
163:
164: /* Initialize local request state */
165: req = &ipcp->req;
166: req->ip[PPP_SELF] = conf->ip[PPP_SELF];
167: req->vjc[PPP_SELF].enabled = 1;
168: req->vjc[PPP_SELF].maxchan = NG_VJC_MAX_CHANNELS - 1;
169: req->vjc[PPP_SELF].compcid = IPCP_ALLOW_SELF_COMPCID;
170: req->ask_dns = conf->do_dns[PPP_SELF];
171: req->ask_nbns = conf->do_nbns[PPP_SELF];
172:
173: /* Done */
174: return (inst);
175:
176: fail:
177: /* Clean up after failure */
178: if (ipcp != NULL)
179: FREE(IPCP_MTYPE, ipcp);
180: FREE(IPCP_MTYPE, inst);
181: return (NULL);
182: }
183:
184: /*
185: * Get IPCP request state.
186: */
187: void
188: ppp_ipcp_get_req(struct ppp_fsm *fsm, struct ppp_ipcp_req *req)
189: {
190: struct ppp_fsm_instance *const inst = ppp_fsm_get_instance(fsm);
191: struct ipcp *const ipcp = inst->arg;
192:
193: assert(inst->type == &ppp_fsm_ipcp);
194: memcpy(req, &ipcp->req, sizeof(*req));
195: }
196:
197: /***********************************************************************
198: FSM CALLBACKS
199: ***********************************************************************/
200:
201: static void
202: ppp_ipcp_destroy(struct ppp_fsm_instance *inst)
203: {
204: struct ipcp *const ipcp = inst->arg;
205:
206: FREE(IPCP_MTYPE, ipcp);
207: FREE(IPCP_MTYPE, inst);
208: }
209:
210: static int
211: ppp_ipcp_build_conf_req(struct ppp_fsm_instance *fsm,
212: struct ppp_fsm_options *opts)
213: {
214: struct ipcp *const ipcp = (struct ipcp *)fsm->arg;
215: struct ppp_ipcp_req *const req = &ipcp->req;
216: int i;
217:
218: /* Add requested config options */
219: if (ppp_fsm_option_add(opts, IPCP_OPT_IP, 4, &req->ip[PPP_SELF]) == -1)
220: return (-1);
221: if (req->vjc[PPP_SELF].enabled) {
222: struct ipcp_vjc vjc;
223:
224: vjc.proto = htons(PPP_PROTO_VJCOMP);
225: vjc.maxchan = req->vjc[PPP_SELF].maxchan;
226: vjc.compcid = req->vjc[PPP_SELF].compcid;
227: if (ppp_fsm_option_add(opts,
228: IPCP_OPT_COMP, sizeof(vjc), &vjc) == -1)
229: return (-1);
230: }
231: if (req->ask_dns) {
232: for (i = 0; i < 2; i++) {
233: if (ppp_fsm_option_add(opts,
234: ipcp_dns_opts[i], 4, &req->dns[i]) == -1)
235: return (-1);
236: }
237: }
238: if (req->ask_nbns) {
239: for (i = 0; i < 2; i++) {
240: if (ppp_fsm_option_add(opts,
241: ipcp_nbns_opts[i], 4, &req->nbns[i]) == -1)
242: return (-1);
243: }
244: }
245:
246: /* Done */
247: return (0);
248: }
249:
250: static int
251: ppp_ipcp_recv_conf_req(struct ppp_fsm_instance *fsm,
252: struct ppp_fsm_options *crq, struct ppp_fsm_options *nak,
253: struct ppp_fsm_options *rej)
254: {
255: struct ipcp *const ipcp = (struct ipcp *)fsm->arg;
256: struct ppp_ipcp_config *const conf = &ipcp->conf;
257: struct ppp_ipcp_req *const req = &ipcp->req;
258: int saw_ip = 0;
259: int i;
260:
261: /* Initialize peer's request state */
262: req->ip[PPP_PEER].s_addr = 0;
263: memset(&req->vjc[PPP_PEER], 0, sizeof(req->vjc[PPP_PEER]));
264:
265: /* Process options */
266: for (i = 0; i < crq->num; i++) {
267: const struct ppp_fsm_option *const opt = &crq->opts[i];
268:
269: switch (opt->type) {
270: case IPCP_OPT_IP:
271: {
272: struct in_addr ip;
273:
274: saw_ip = 1;
275: memcpy(&ip, opt->data, 4);
276: if ((ip.s_addr & conf->mask[PPP_PEER].s_addr)
277: != (conf->ip[PPP_PEER].s_addr
278: & conf->mask[PPP_PEER].s_addr)) {
279: if (ppp_fsm_option_add(nak, opt->type,
280: 4, &conf->ip[PPP_PEER]) == -1)
281: return (-1);
282: break;
283: }
284: req->ip[PPP_PEER] = ip;
285: break;
286: }
287: case IPCP_OPT_COMP:
288: {
289: struct ipcp_vjc vjc;
290: int nakit = 0;
291:
292: memcpy(&vjc, opt->data, sizeof(vjc));
293: if (ntohs(vjc.proto) != PPP_PROTO_VJCOMP)
294: goto reject;
295: if (vjc.maxchan < NG_VJC_MIN_CHANNELS - 1) {
296: vjc.maxchan = NG_VJC_MIN_CHANNELS - 1;
297: nakit = 1;
298: }
299: if (vjc.maxchan > NG_VJC_MAX_CHANNELS - 1) {
300: vjc.maxchan = NG_VJC_MAX_CHANNELS - 1;
301: nakit = 1;
302: }
303: #if !IPCP_ALLOW_PEER_COMPCID
304: if (vjc.compcid) {
305: vjc.compcid = 0;
306: nakit = 1;
307: }
308: #endif
309: if (nakit) {
310: if (ppp_fsm_option_add(nak,
311: opt->type, sizeof(vjc), &vjc) == -1)
312: return (-1);
313: break;
314: }
315: req->vjc[PPP_PEER].enabled = 1;
316: req->vjc[PPP_PEER].maxchan = vjc.maxchan;
317: req->vjc[PPP_PEER].compcid = vjc.compcid;
318: break;
319: }
320: case IPCP_OPT_DNS1:
321: case IPCP_OPT_DNS2:
322: {
323: const int i = (opt->type == IPCP_OPT_DNS2);
324: struct in_addr ip;
325:
326: if (!conf->do_dns[PPP_PEER]
327: || conf->dns[i].s_addr == 0)
328: goto reject;
329: memcpy(&ip, opt->data, 4);
330: if (ip.s_addr != conf->dns[i].s_addr) {
331: if (ppp_fsm_option_add(nak, opt->type,
332: 4, &conf->dns[i]) == -1)
333: return (-1);
334: break;
335: }
336: break;
337: }
338: case IPCP_OPT_NBNS1:
339: case IPCP_OPT_NBNS2:
340: {
341: const int i = (opt->type == IPCP_OPT_NBNS2);
342: struct in_addr ip;
343:
344: if (!conf->do_nbns[PPP_PEER]
345: || conf->nbns[i].s_addr == 0)
346: goto reject;
347: memcpy(&ip, opt->data, 4);
348: if (ip.s_addr != conf->nbns[i].s_addr) {
349: if (ppp_fsm_option_add(nak, opt->type,
350: 4, &conf->nbns[i]) == -1)
351: return (-1);
352: break;
353: }
354: break;
355: }
356: default:
357: goto reject;
358: }
359:
360: /* OK */
361: continue;
362:
363: reject:
364: /* Reject this requested option */
365: if (ppp_fsm_option_add(rej,
366: opt->type, opt->len, opt->data) == -1)
367: return (-1);
368: }
369:
370: /* Make sure we saw an IP address option */
371: if (!saw_ip) {
372: errno = EINVAL;
373: return (-1);
374: }
375:
376: /* Done */
377: return (0);
378: }
379:
380: static int
381: ppp_ipcp_recv_conf_rej(struct ppp_fsm_instance *fsm,
382: struct ppp_fsm_options *rej)
383: {
384: struct ipcp *const ipcp = (struct ipcp *)fsm->arg;
385: struct ppp_ipcp_req *const req = &ipcp->req;
386: int i;
387:
388: for (i = 0; i < rej->num; i++) {
389: const struct ppp_fsm_option *const opt = &rej->opts[i];
390:
391: switch (opt->type) {
392: case IPCP_OPT_IP:
393: errno = EINVAL;
394: return (-1);
395: case IPCP_OPT_COMP:
396: req->vjc[PPP_SELF].enabled = 0;
397: break;
398: case IPCP_OPT_DNS1:
399: case IPCP_OPT_DNS2:
400: req->ask_dns = 0;
401: break;
402: case IPCP_OPT_NBNS1:
403: case IPCP_OPT_NBNS2:
404: req->ask_nbns = 0;
405: break;
406: default:
407: break;
408: }
409: }
410:
411: /* Done */
412: return (0);
413: }
414:
415: static int
416: ppp_ipcp_recv_conf_nak(struct ppp_fsm_instance *fsm,
417: struct ppp_fsm_options *nak)
418: {
419: struct ipcp *const ipcp = (struct ipcp *)fsm->arg;
420: struct ppp_ipcp_config *const conf = &ipcp->conf;
421: struct ppp_ipcp_req *const req = &ipcp->req;
422: int i;
423:
424: for (i = 0; i < nak->num; i++) {
425: const struct ppp_fsm_option *const opt = &nak->opts[i];
426:
427: switch (opt->type) {
428: case IPCP_OPT_IP:
429: {
430: struct in_addr ip;
431:
432: memcpy(&ip, opt->data, 4);
433: if ((ip.s_addr & conf->mask[PPP_SELF].s_addr)
434: != (conf->ip[PPP_SELF].s_addr
435: & conf->mask[PPP_SELF].s_addr))
436: break;
437: req->ip[PPP_SELF] = ip;
438: break;
439: }
440: case IPCP_OPT_COMP:
441: {
442: struct ipcp_vjc vjc;
443:
444: memcpy(&vjc, opt->data, sizeof(vjc));
445: if (ntohs(vjc.proto) != PPP_PROTO_VJCOMP)
446: break;
447: if (vjc.maxchan < NG_VJC_MIN_CHANNELS - 1)
448: vjc.maxchan = NG_VJC_MIN_CHANNELS - 1;
449: if (vjc.maxchan > NG_VJC_MAX_CHANNELS - 1)
450: vjc.maxchan = NG_VJC_MAX_CHANNELS - 1;
451: req->vjc[PPP_SELF].maxchan = vjc.maxchan;
452: #if IPCP_ALLOW_SELF_COMPCID
453: if (vjc.compcid)
454: req->vjc[PPP_SELF].compcid = 1;
455: #endif
456: break;
457: }
458: case IPCP_OPT_DNS1:
459: case IPCP_OPT_DNS2:
460: {
461: const int i = (opt->type == IPCP_OPT_DNS2);
462:
463: memcpy(&req->dns[i], opt->data, 4);
464: break;
465: }
466: case IPCP_OPT_NBNS1:
467: case IPCP_OPT_NBNS2:
468: {
469: const int i = (opt->type == IPCP_OPT_NBNS2);
470:
471: memcpy(&req->nbns[i], opt->data, 4);
472: break;
473: }
474: default:
475: break;
476: }
477: }
478:
479: /* Done */
480: return (0);
481: }
482:
483: /***********************************************************************
484: INTERNAL FUNCTIONS
485: ***********************************************************************/
486:
487: static void
488: ppp_ipcp_pr_ip(const struct ppp_fsm_optdesc *desc,
489: const struct ppp_fsm_option *opt, char *buf, size_t bmax)
490: {
491: struct in_addr ip;
492:
493: if (opt->len < 4) {
494: snprintf(buf, bmax, "<truncated>");
495: return;
496: }
497: memcpy(&ip, opt->data, 4);
498: snprintf(buf, bmax, "%s", inet_ntoa(ip));
499: }
500:
501: static void
502: ppp_ipcp_pr_ipcomp(const struct ppp_fsm_optdesc *desc,
503: const struct ppp_fsm_option *opt, char *buf, size_t bmax)
504: {
505: struct ipcp_vjc vjc;
506:
507: if (opt->len < 2) {
508: snprintf(buf, bmax, "<truncated>");
509: return;
510: }
511: memcpy(&vjc, opt->data, 2);
512: if (ntohs(vjc.proto) != PPP_PROTO_VJCOMP) {
513: snprintf(buf, bmax, "?0x%04x", ntohs(vjc.proto));
514: return;
515: }
516: if (opt->len < sizeof(vjc)) {
517: snprintf(buf, bmax, "VJCOMP %s", "<truncated>");
518: return;
519: }
520: memcpy(&vjc, opt->data, sizeof(vjc));
521: snprintf(buf, bmax, "VJCOMP %d channels, %s comp-cid",
522: vjc.maxchan + 1, vjc.compcid ? "allow" : "no");
523: }
524:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>