Annotation of embedaddon/libpdel/ppp/ppp_bundle.c, revision 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_engine.h"
! 48: #include "ppp/ppp_link.h"
! 49: #include "ppp/ppp_lcp.h"
! 50: #include "ppp/ppp_ipcp.h"
! 51: #include "ppp/ppp_ccp.h"
! 52: #include "ppp/ppp_bundle.h"
! 53: #include "ppp/ppp_channel.h"
! 54: #include "ppp/ppp_msoft.h"
! 55:
! 56: #include <netgraph/ng_mppc.h>
! 57:
! 58: #ifndef MPPE_56
! 59: #define MPPE_56 0x00000080
! 60: #define MPPE_56_UNSUPPORTED
! 61: #endif
! 62:
! 63: #define BUNDLE_MTYPE "ppp_bundle"
! 64:
! 65: /* Bundle structure */
! 66: struct ppp_bundle {
! 67: struct ppp_engine *engine; /* engine that owns me */
! 68: struct ppp_bundle_config conf; /* bundle configuration */
! 69: struct ppp_node *node; /* ng_ppp(4) node */
! 70: struct ppp_log *log; /* log */
! 71: struct ng_ppp_node_conf node_conf; /* ng_ppp(4) node config */
! 72: struct paction *action; /* configuration action */
! 73: struct ppp_fsm *lcp; /* lcp fsm (for bundle only) */
! 74: struct ppp_fsm *ipcp; /* ipcp fsm */
! 75: struct ppp_fsm *ccp; /* ccp fsm */
! 76: struct pevent_ctx *ev_ctx; /* event context */
! 77: pthread_mutex_t *mutex; /* mutex */
! 78: struct pevent *lcp_event; /* lcp fsm event */
! 79: struct pevent *ipcp_event; /* ipcp fsm event */
! 80: struct pevent *ccp_event; /* ccp fsm event */
! 81: struct pevent *config_timeout;/* timer for config operation */
! 82: void *cookie; /* client bundle cookie */
! 83: void *plumb_arg; /* client plumbing arg */
! 84: union ppp_auth_mppe mppe; /* mppe from first link auth */
! 85: enum ppp_auth_index mppe_auth; /* type of auth on first link */
! 86: u_char mppe_server; /* which side is mppe server */
! 87: u_char mppe_64[2][8]; /* 64 bit mppe keys */
! 88: u_char mppe_128[2][16];/* 128 bit mppe keys */
! 89: u_char multilink; /* multilink active */
! 90: u_char shutdown; /* bundle shutting down */
! 91: u_char ipcp_up; /* ipcp is up */
! 92: u_char ccp_up; /* ccp is up */
! 93: struct ppp_eid eid[2]; /* endpoint id */
! 94: u_int nlinks; /* number of links */
! 95: struct ppp_link *links[NG_PPP_MAX_LINKS]; /* links */
! 96: char authname[2][PPP_MAX_AUTHNAME]; /* authname's */
! 97: };
! 98:
! 99: /* Internal functions */
! 100: static int ppp_bundle_configure(struct ppp_bundle *bundle);
! 101: static void ppp_bundle_shutdown(struct ppp_bundle *bundle);
! 102: static void ppp_bundle_fsm_dead(struct ppp_bundle *bundle);
! 103:
! 104: static ppp_node_recv_t ppp_bundle_node_recv;
! 105:
! 106: /* Event handlers */
! 107: static pevent_handler_t ppp_bundle_lcp_event;
! 108: static pevent_handler_t ppp_bundle_ipcp_event;
! 109: static pevent_handler_t ppp_bundle_ccp_event;
! 110:
! 111: /* Internal variables */
! 112: static const u_char ppp_bundle_zero[16]; /* all zeros */
! 113:
! 114: /* Macro for logging */
! 115: #define LOG(sev, fmt, args...) PPP_LOG(bundle->log, sev, fmt , ## args)
! 116:
! 117: /***********************************************************************
! 118: PUBLIC FUNCTIONS
! 119: ***********************************************************************/
! 120:
! 121: /*
! 122: * Create a new bundle from a newly opened link.
! 123: *
! 124: * We 'steal' the link's ng_ppp(4) node for the bundle's use.
! 125: * We assume the link's device is already connected as link #0.
! 126: *
! 127: * The "log" is destroyed when the bundle is destroyed.
! 128: */
! 129: struct ppp_bundle *
! 130: ppp_bundle_create(struct ppp_engine *engine,
! 131: struct ppp_link *link, struct ppp_node *node)
! 132: {
! 133: struct ppp_lcp_req lcp_req;
! 134: struct ppp_bundle *bundle;
! 135: int i;
! 136:
! 137: /* Create bundle */
! 138: if ((bundle = MALLOC(BUNDLE_MTYPE, sizeof(*bundle))) == NULL)
! 139: return (NULL);
! 140: memset(bundle, 0, sizeof(*bundle));
! 141: bundle->engine = engine;
! 142: bundle->ev_ctx = ppp_engine_get_ev_ctx(engine);
! 143: bundle->mutex = ppp_engine_get_mutex(engine);
! 144: bundle->node = node;
! 145: bundle->links[0] = link;
! 146: bundle->nlinks = 1;
! 147:
! 148: /* Make bundle known to engine */
! 149: if (ppp_engine_add_bundle(bundle->engine, bundle) == -1)
! 150: goto fail;
! 151:
! 152: /* Get link's negotiated LCP config and inherit from it */
! 153: ppp_link_get_lcp_req(link, &lcp_req);
! 154: for (i = 0; i < 2; i++) {
! 155: strlcpy(bundle->authname[i], ppp_link_get_authname(link, i),
! 156: sizeof(bundle->authname[i]));
! 157: bundle->eid[i] = lcp_req.eid[i];
! 158: }
! 159: bundle->multilink = lcp_req.multilink[PPP_SELF];
! 160: bundle->mppe_server = !ppp_link_get_origination(link);
! 161: bundle->mppe_auth = lcp_req.auth[bundle->mppe_server];
! 162: ppp_link_get_mppe(link, bundle->mppe_server, &bundle->mppe);
! 163:
! 164: /* Initialize ng_ppp(4) node configuration, enabling the first link */
! 165: if (ppp_node_get_config(bundle->node, &bundle->node_conf) == -1)
! 166: goto fail;
! 167: bundle->node_conf.links[0].enableLink = 1;
! 168: bundle->node_conf.bund.mrru = lcp_req.mrru[PPP_PEER];
! 169: bundle->node_conf.bund.enableMultilink = bundle->multilink;
! 170: bundle->node_conf.bund.xmitShortSeq = lcp_req.shortseq[PPP_PEER];
! 171: bundle->node_conf.bund.recvShortSeq = lcp_req.shortseq[PPP_SELF];
! 172:
! 173: /* Update ng_ppp(4) node configuration */
! 174: if (ppp_node_set_config(bundle->node, &bundle->node_conf) == -1)
! 175: goto fail;
! 176:
! 177: /* Acquire bundle configuration */
! 178: if (ppp_bundle_configure(bundle) == -1) {
! 179: ppp_log_put(ppp_link_get_log(link), LOG_ERR,
! 180: "%s: %m", "error configuring bundle");
! 181: goto fail;
! 182: }
! 183:
! 184: /* Receive all node bypass packets */
! 185: ppp_node_set_recv(node, ppp_bundle_node_recv, bundle);
! 186:
! 187: /* Done */
! 188: return (bundle);
! 189:
! 190: fail:
! 191: /* Clean up after failure */
! 192: paction_cancel(&bundle->action);
! 193: pevent_unregister(&bundle->lcp_event);
! 194: ppp_fsm_destroy(&bundle->lcp);
! 195: ppp_engine_del_bundle(bundle->engine, bundle);
! 196: FREE(BUNDLE_MTYPE, bundle);
! 197: return (NULL);
! 198: }
! 199:
! 200: /*
! 201: * Close a bundle.
! 202: */
! 203: void
! 204: ppp_bundle_close(struct ppp_bundle *bundle)
! 205: {
! 206: int i;
! 207:
! 208: if (bundle->ipcp != NULL)
! 209: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 210: if (bundle->ccp != NULL)
! 211: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 212: for (i = 0; i < bundle->nlinks; i++)
! 213: ppp_link_close(bundle->links[i]);
! 214: }
! 215:
! 216: /*
! 217: * Destroy a bundle.
! 218: */
! 219: void
! 220: ppp_bundle_destroy(struct ppp_bundle **bundlep)
! 221: {
! 222: struct ppp_bundle *const bundle = *bundlep;
! 223:
! 224: /* Avoid recursion */
! 225: if (bundle == NULL)
! 226: return;
! 227: *bundlep = NULL;
! 228: if (bundle->shutdown)
! 229: return;
! 230: bundle->shutdown = 1;
! 231:
! 232: /* XXX disable traffic on node first? */
! 233:
! 234: /* Unplumb bundle and release IP address */
! 235: if (bundle->plumb_arg != NULL) {
! 236: ppp_engine_bundle_unplumb(bundle->engine,
! 237: bundle->plumb_arg, bundle);
! 238: }
! 239: if (bundle->conf.ip[PPP_PEER].s_addr != 0) {
! 240: ppp_engine_release_ip(bundle->engine,
! 241: bundle, bundle->conf.ip[PPP_PEER]);
! 242: }
! 243:
! 244: /* Destroy all links */
! 245: while (bundle->nlinks > 0) {
! 246: struct ppp_link *link = bundle->links[0];
! 247:
! 248: ppp_link_destroy(&link);
! 249: }
! 250:
! 251: /* Destroy bundle */
! 252: paction_cancel(&bundle->action);
! 253: ppp_engine_del_bundle(bundle->engine, bundle);
! 254: pevent_unregister(&bundle->config_timeout);
! 255: pevent_unregister(&bundle->lcp_event);
! 256: pevent_unregister(&bundle->ipcp_event);
! 257: pevent_unregister(&bundle->ccp_event);
! 258: ppp_fsm_destroy(&bundle->lcp);
! 259: ppp_fsm_destroy(&bundle->ipcp);
! 260: ppp_fsm_destroy(&bundle->ccp);
! 261: ppp_node_destroy(&bundle->node);
! 262: ppp_log_close(&bundle->log);
! 263: FREE(BUNDLE_MTYPE, bundle);
! 264: }
! 265:
! 266: const char *
! 267: ppp_bundle_get_authname(struct ppp_bundle *bundle, int dir)
! 268: {
! 269: dir &= 1;
! 270: return (bundle->authname[dir]);
! 271: }
! 272:
! 273: void
! 274: ppp_bundle_get_eid(struct ppp_bundle *bundle, int dir, struct ppp_eid *eid)
! 275: {
! 276: dir &= 1;
! 277: *eid = bundle->eid[dir];
! 278: }
! 279:
! 280: int
! 281: ppp_bundle_get_multilink(struct ppp_bundle *bundle)
! 282: {
! 283: return (bundle->multilink);
! 284: }
! 285:
! 286: int
! 287: ppp_bundle_get_links(struct ppp_bundle *bundle, struct ppp_link **list, int max)
! 288: {
! 289: int num;
! 290: int i;
! 291:
! 292: num = MIN(bundle->nlinks, max);
! 293: for (i = 0; i < num; i++)
! 294: list[i] = bundle->links[i];
! 295: return (num);
! 296: }
! 297:
! 298: int
! 299: ppp_bundle_get_ipcp(struct ppp_bundle *bundle,
! 300: struct ppp_ipcp_req *ipcp, int *is_up)
! 301: {
! 302: if (bundle->ipcp == NULL) {
! 303: errno = ENXIO;
! 304: return (-1);
! 305: }
! 306: if (ipcp != NULL)
! 307: ppp_ipcp_get_req(bundle->ipcp, ipcp);
! 308: if (is_up != NULL)
! 309: *is_up = (ppp_fsm_get_state(bundle->ipcp) == FSM_STATE_OPENED);
! 310: return (0);
! 311: }
! 312:
! 313: int
! 314: ppp_bundle_get_ccp(struct ppp_bundle *bundle,
! 315: struct ppp_ccp_req *ccp, int *is_up)
! 316: {
! 317: if (bundle->ccp == NULL) {
! 318: errno = ENXIO;
! 319: return (-1);
! 320: }
! 321: if (ccp != NULL)
! 322: ppp_ccp_get_req(bundle->ccp, ccp);
! 323: if (is_up != NULL)
! 324: *is_up = (ppp_fsm_get_state(bundle->ccp) == FSM_STATE_OPENED);
! 325: return (0);
! 326: }
! 327:
! 328: void *
! 329: ppp_bundle_get_cookie(struct ppp_bundle *bundle)
! 330: {
! 331: return (bundle->cookie);
! 332: }
! 333:
! 334: /*
! 335: * Join a new link into a bundle that already has one or more links.
! 336: */
! 337: int
! 338: ppp_bundle_join(struct ppp_bundle *bundle, struct ppp_link *link,
! 339: struct ppp_node *node, u_int16_t *link_num)
! 340: {
! 341: struct ppp_channel *const device = ppp_link_get_device(link);
! 342: struct ng_ppp_node_conf bconf;
! 343: const char *path;
! 344: const char *hook;
! 345:
! 346: /* Sanity check */
! 347: if (!bundle->multilink) {
! 348: LOG(LOG_ERR, "multilink disabled on this bundle");
! 349: errno = EINVAL;
! 350: return (-1);
! 351: }
! 352: if (bundle->nlinks == NG_PPP_MAX_LINKS) {
! 353: LOG(LOG_ERR, "too many links in this bundle");
! 354: errno = ENOSPC;
! 355: return (-1);
! 356: }
! 357:
! 358: /* Disconnect device from link's node */
! 359: if (ppp_node_disconnect(bundle->node, 0) == -1) {
! 360: LOG(LOG_ERR, "can't disconnect link device: %m");
! 361: return (-1);
! 362: }
! 363:
! 364: /* Connect link's device to our node */
! 365: if ((path = ppp_channel_get_node(device)) == NULL
! 366: || (hook = ppp_channel_get_hook(device)) == NULL) {
! 367: LOG(LOG_ERR, "link's channel is not a device");
! 368: return (-1);
! 369: }
! 370: if (ppp_node_connect(bundle->node, bundle->nlinks, path, hook) == -1) {
! 371: LOG(LOG_ERR, "%s: %m", "connecting device to node");
! 372: return (-1);
! 373: }
! 374:
! 375: /* Copy over link's configuration from link node to bundle node */
! 376: if (ppp_node_get_config(node, &bconf) == -1) {
! 377: LOG(LOG_ERR, "can't get link's node configuration: %m");
! 378: return (-1);
! 379: }
! 380: bundle->node_conf.links[bundle->nlinks] = bconf.links[0];
! 381: bundle->node_conf.links[bundle->nlinks].enableLink = 1;
! 382:
! 383: /* Update node configuration */
! 384: if (ppp_node_set_config(bundle->node, &bundle->node_conf) == -1)
! 385: goto fail;
! 386:
! 387: /* Done */
! 388: *link_num = bundle->nlinks;
! 389: bundle->links[bundle->nlinks++] = link;
! 390: return (0);
! 391:
! 392: fail:
! 393: /* Clean up after failure */
! 394: bundle->node_conf.links[bundle->nlinks].enableLink = 0;
! 395: (void)ppp_node_set_config(bundle->node, &bundle->node_conf);
! 396: return (-1);
! 397: }
! 398:
! 399: /*
! 400: * Remove a link from a bundle.
! 401: */
! 402: void
! 403: ppp_bundle_unjoin(struct ppp_bundle **bundlep, struct ppp_link *link)
! 404: {
! 405: struct ppp_bundle *bundle = *bundlep;
! 406: int link_num;
! 407:
! 408: /* Get bundle */
! 409: if (bundle == NULL)
! 410: return;
! 411: *bundlep = NULL;
! 412:
! 413: /* Find link; do nothing if not found */
! 414: for (link_num = 0; link_num < bundle->nlinks
! 415: && bundle->links[link_num] != link; link_num++);
! 416: if (link_num == bundle->nlinks) {
! 417: LOG(LOG_ERR, "link %p not found in bundle", link);
! 418: return;
! 419: }
! 420:
! 421: /* Disable traffic on link */
! 422: bundle->node_conf.links[link_num].enableLink = 0;
! 423: if (ppp_node_set_config(bundle->node, &bundle->node_conf) == -1)
! 424: LOG(LOG_ERR, "can't disable link: %m");
! 425:
! 426: /* Disconnect link's device from bundle's node */
! 427: if (ppp_node_disconnect(bundle->node, link_num) == -1)
! 428: LOG(LOG_ERR, "can't disconnect link device: %m");
! 429:
! 430: /* Remove link from bundle */
! 431: memmove(&bundle->links[link_num], &bundle->links[link_num + 1],
! 432: (--bundle->nlinks - link_num) * sizeof(*bundle->links));
! 433:
! 434: /* If no links remain, remove bundle */
! 435: if (bundle->nlinks == 0)
! 436: ppp_bundle_destroy(&bundle);
! 437: }
! 438:
! 439: /*
! 440: * Handle protocol rejection by peer.
! 441: */
! 442: void
! 443: ppp_bundle_protorej(struct ppp_bundle *bundle, u_int16_t proto)
! 444: {
! 445: switch (proto) {
! 446: case PPP_PROTO_LCP: /* these are required */
! 447: case PPP_PROTO_MP:
! 448: case PPP_PROTO_IPCP:
! 449: case PPP_PROTO_IP:
! 450: case PPP_PROTO_VJCOMP:
! 451: case PPP_PROTO_VJUNCOMP:
! 452: case PPP_PROTO_COMPD:
! 453: ppp_bundle_shutdown(bundle);
! 454: break;
! 455: case PPP_PROTO_CCP: /* this one is maybe optional */
! 456: if (bundle->conf.mppe_reqd)
! 457: ppp_bundle_shutdown(bundle);
! 458: else {
! 459: pevent_unregister(&bundle->ccp_event);
! 460: ppp_fsm_destroy(&bundle->ccp);
! 461: }
! 462: return;
! 463: default: /* others we don't care */
! 464: break;
! 465: }
! 466: }
! 467:
! 468: /*
! 469: * Write to ng_ppp(4) node "bypass" hook.
! 470: */
! 471: int
! 472: ppp_bundle_write(struct ppp_bundle *bundle, u_int link_num,
! 473: u_int16_t proto, const void *data, size_t len)
! 474: {
! 475: return (ppp_node_write(bundle->node, link_num, proto, data, len));
! 476: }
! 477:
! 478: /***********************************************************************
! 479: BUNDLE CONFIGURATION
! 480: ***********************************************************************/
! 481:
! 482: #define BCONFIG_MTYPE "ppp_bundle.config"
! 483: #define CONFIG_TIMEOUT 20 /* 20 seconds */
! 484:
! 485: /* Configuration state */
! 486: struct ppp_bundle_config_state {
! 487: struct ppp_engine *engine;
! 488: struct ppp_bundle *bundle;
! 489: struct ppp_link *link;
! 490: struct ppp_bundle_config config;
! 491: void *cookie;
! 492: };
! 493:
! 494: static pevent_handler_t ppp_bundle_config_timeout;
! 495:
! 496: static paction_handler_t ppp_bundle_configure_main;
! 497: static paction_finish_t ppp_bundle_configure_finish;
! 498:
! 499: /*
! 500: * Initiate action to configure bundle.
! 501: */
! 502: static int
! 503: ppp_bundle_configure(struct ppp_bundle *bundle)
! 504: {
! 505: struct ppp_bundle_config_state *state;
! 506:
! 507: /* Initialize state */
! 508: if ((state = MALLOC(BCONFIG_MTYPE, sizeof(*state))) == NULL)
! 509: return (-1);
! 510: memset(state, 0, sizeof(*state));
! 511: state->engine = bundle->engine;
! 512: state->bundle = bundle;
! 513: state->link = bundle->links[0];
! 514:
! 515: /* Set a timeout for ppp_engine_bundle_config() to return */
! 516: if (pevent_register(bundle->ev_ctx, &bundle->config_timeout, 0,
! 517: bundle->mutex, ppp_bundle_config_timeout, bundle, PEVENT_TIME,
! 518: CONFIG_TIMEOUT * 1000) == -1) {
! 519: LOG(LOG_ERR, "%s: %m", "pevent_register");
! 520: goto fail;
! 521: }
! 522:
! 523: /* Get the configuration in a separate thread */
! 524: if (paction_start(&bundle->action, bundle->mutex,
! 525: ppp_bundle_configure_main, ppp_bundle_configure_finish,
! 526: state) == -1) {
! 527: LOG(LOG_ERR, "%s: %m", "paction_start");
! 528: goto fail;
! 529: }
! 530:
! 531: /* Done */
! 532: return (0);
! 533:
! 534: fail:
! 535: /* Clean up */
! 536: paction_cancel(&bundle->action);
! 537: pevent_unregister(&bundle->config_timeout);
! 538: FREE(BCONFIG_MTYPE, state);
! 539: return (-1);
! 540: }
! 541:
! 542: /*
! 543: * Configure bundle main routine.
! 544: *
! 545: * This is called from a separate thread.
! 546: */
! 547: static void
! 548: ppp_bundle_configure_main(void *arg)
! 549: {
! 550: struct ppp_bundle_config_state *const state = arg;
! 551:
! 552: /* Get configuration for the new bundle */
! 553: state->cookie = ppp_engine_bundle_config(state->engine,
! 554: state->link, &state->config);
! 555:
! 556: /* Disable 56-bit MPPE if not supported */
! 557: #ifdef MPPE_56_UNSUPPORTED
! 558: state->config.mppe_56 = 0;
! 559: #endif
! 560: }
! 561:
! 562: /*
! 563: * Configure bundle finish routine.
! 564: *
! 565: * This is called from a separate thread.
! 566: */
! 567: static void
! 568: ppp_bundle_configure_finish(void *arg, int was_canceled)
! 569: {
! 570: struct ppp_bundle_config_state *const state = arg;
! 571: struct ppp_bundle *bundle = state->bundle;
! 572: struct ppp_fsm_instance *inst = NULL;
! 573: struct ppp_ipcp_config ipcp_config;
! 574: int i;
! 575:
! 576: /* Canceled? */
! 577: if (was_canceled)
! 578: goto done;
! 579:
! 580: /* Cancel config timer */
! 581: pevent_unregister(&bundle->config_timeout);
! 582:
! 583: /* Check result */
! 584: if (state->cookie == NULL) {
! 585: ppp_log_put(ppp_link_get_log(bundle->links[0]),
! 586: LOG_ERR, "failed to configure new bundle");
! 587: goto fail;
! 588: }
! 589:
! 590: /* Copy config info to bundle */
! 591: bundle->conf = state->config;
! 592: bundle->cookie = state->cookie;
! 593: bundle->conf.logname[sizeof(bundle->conf.logname) - 1] = '\0';
! 594:
! 595: /* Create log */
! 596: if ((bundle->log = ppp_log_prefix(ppp_engine_get_log(bundle->engine),
! 597: "%s: ", *bundle->conf.logname != '\0' ? bundle->conf.logname :
! 598: ppp_link_get_authname(bundle->links[0], PPP_PEER))) == NULL) {
! 599: ppp_log_put(ppp_link_get_log(bundle->links[0]),
! 600: LOG_ERR, "failed to create bundle log: %m");
! 601: goto fail;
! 602: }
! 603:
! 604: /* Create LCP FSM */
! 605: if ((inst = ppp_lcp_create(NULL)) == NULL) {
! 606: LOG(LOG_ERR, "failed to create LCP: %m");
! 607: goto fail;
! 608: }
! 609: if ((bundle->lcp = ppp_fsm_create(bundle->ev_ctx,
! 610: bundle->mutex, inst, bundle->log)) == NULL) {
! 611: LOG(LOG_ERR, "failed to create LCP: %m");
! 612: goto fail;
! 613: }
! 614: inst = NULL;
! 615:
! 616: /* Listen for LCP events */
! 617: if (pevent_register(bundle->ev_ctx, &bundle->lcp_event,
! 618: PEVENT_RECURRING, bundle->mutex, ppp_bundle_lcp_event, bundle,
! 619: PEVENT_MESG_PORT, ppp_fsm_get_outport(bundle->lcp)) == -1) {
! 620: LOG(LOG_ERR, "%s: %m", "adding read event for lcp");
! 621: goto fail;
! 622: }
! 623:
! 624: /* Create IPCP FSM */
! 625: memset(&ipcp_config, 0, sizeof(ipcp_config));
! 626: if (bundle->conf.dns_servers[0].s_addr != 0) {
! 627: ipcp_config.dns[0] = bundle->conf.dns_servers[0];
! 628: ipcp_config.dns[1] = bundle->conf.dns_servers[1];
! 629: ipcp_config.do_dns[PPP_PEER] = 1;
! 630: }
! 631: if (bundle->conf.nbns_servers[0].s_addr != 0) {
! 632: ipcp_config.nbns[0] = bundle->conf.nbns_servers[0];
! 633: ipcp_config.nbns[1] = bundle->conf.nbns_servers[1];
! 634: ipcp_config.do_nbns[PPP_PEER] = 1;
! 635: }
! 636: for (i = 0; i < 2; i++) {
! 637: ipcp_config.ip[i] = bundle->conf.ip[i];
! 638: ipcp_config.mask[i].s_addr
! 639: = (ipcp_config.ip[i].s_addr == 0) ? 0 : 0xffffffff;
! 640: }
! 641: if ((inst = ppp_ipcp_create(&ipcp_config, bundle->node)) == NULL) {
! 642: LOG(LOG_ERR, "failed to create IPCP: %m");
! 643: goto fail;
! 644: }
! 645: if ((bundle->ipcp = ppp_fsm_create(bundle->ev_ctx,
! 646: bundle->mutex, inst, bundle->log)) == NULL) {
! 647: LOG(LOG_ERR, "failed to create IPCP: %m");
! 648: goto fail;
! 649: }
! 650: inst = NULL;
! 651:
! 652: /* Listen for IPCP events */
! 653: if (pevent_register(bundle->ev_ctx, &bundle->ipcp_event,
! 654: PEVENT_RECURRING, bundle->mutex, ppp_bundle_ipcp_event, bundle,
! 655: PEVENT_MESG_PORT, ppp_fsm_get_outport(bundle->ipcp)) == -1) {
! 656: LOG(LOG_ERR, "%s: %m", "adding ipcp event");
! 657: goto fail;
! 658: }
! 659:
! 660: /* Start IPCP */
! 661: ppp_fsm_input(bundle->ipcp, FSM_INPUT_UP);
! 662: ppp_fsm_input(bundle->ipcp, FSM_INPUT_OPEN);
! 663:
! 664: /* Create CCP FSM (if MPPE enabled) */
! 665: if (bundle->conf.mppe_40
! 666: || bundle->conf.mppe_56
! 667: || bundle->conf.mppe_128) {
! 668: struct ppp_ccp_config ccp_config;
! 669: int i;
! 670:
! 671: /* Create CCP config */
! 672: memset(&ccp_config, 0, sizeof(ccp_config));
! 673: for (i = 0; i < 2; i++) {
! 674: if (bundle->conf.mppe_40)
! 675: ccp_config.mppe40[i] = 1;
! 676: if (bundle->conf.mppe_56)
! 677: ccp_config.mppe56[i] = 1;
! 678: if (bundle->conf.mppe_128)
! 679: ccp_config.mppe128[i] = 1;
! 680: if (bundle->conf.mppe_stateless)
! 681: ccp_config.mppe_stateless[i] = 1;
! 682: }
! 683:
! 684: /* Derive the MPPE keys we'll need */
! 685: switch (bundle->mppe_auth) {
! 686: case PPP_AUTH_CHAP_MSV1:
! 687: for (i = 0; i < 2; i++) {
! 688: memcpy(&bundle->mppe_64[i],
! 689: bundle->mppe.msv1.key_64,
! 690: sizeof(bundle->mppe_64[i]));
! 691: memcpy(&bundle->mppe_128[i],
! 692: bundle->mppe.msv1.key_128,
! 693: sizeof(bundle->mppe_128[i]));
! 694: }
! 695: break;
! 696: case PPP_AUTH_CHAP_MSV2:
! 697: for (i = 0; i < 2; i++) {
! 698: memcpy(&bundle->mppe_64[i],
! 699: bundle->mppe.msv2.keys[!i
! 700: ^ bundle->mppe_server],
! 701: sizeof(bundle->mppe_64[i]));
! 702: memcpy(&bundle->mppe_128[i],
! 703: bundle->mppe.msv2.keys[!i
! 704: ^ bundle->mppe_server],
! 705: sizeof(bundle->mppe_128[i]));
! 706: }
! 707: break;
! 708: default:
! 709: if (bundle->conf.mppe_reqd) {
! 710: LOG(LOG_ERR, "MPPE %s but MS-CHAP was not"
! 711: " used for authentication", "required");
! 712: goto fail;
! 713: } else {
! 714: LOG(LOG_WARNING, "MPPE %s but MS-CHAP was not"
! 715: " used for authentication", "requested");
! 716: goto done;
! 717: }
! 718: break;
! 719: }
! 720:
! 721: /* Create CCP instance */
! 722: if ((inst = ppp_ccp_create(&ccp_config,
! 723: bundle->node)) == NULL) {
! 724: LOG(LOG_ERR, "failed to create CCP: %m");
! 725: goto fail;
! 726: }
! 727: if ((bundle->ccp = ppp_fsm_create(bundle->ev_ctx,
! 728: bundle->mutex, inst, bundle->log)) == NULL) {
! 729: LOG(LOG_ERR, "failed to create CCP: %m");
! 730: goto fail;
! 731: }
! 732: inst = NULL;
! 733:
! 734: /* Listen for CCP events */
! 735: if (pevent_register(bundle->ev_ctx, &bundle->ccp_event,
! 736: PEVENT_RECURRING, bundle->mutex, ppp_bundle_ccp_event,
! 737: bundle, PEVENT_MESG_PORT, ppp_fsm_get_outport(bundle->ccp))
! 738: == -1) {
! 739: LOG(LOG_ERR, "%s: %m", "adding ccp event");
! 740: goto fail;
! 741: }
! 742:
! 743: /* Start CCP */
! 744: ppp_fsm_input(bundle->ccp, FSM_INPUT_UP);
! 745: ppp_fsm_input(bundle->ccp, FSM_INPUT_OPEN);
! 746: }
! 747:
! 748: done:
! 749: /* Done */
! 750: FREE(BCONFIG_MTYPE, state);
! 751: return;
! 752:
! 753: fail:
! 754: /* Clean up after failure */
! 755: if (inst != NULL)
! 756: (*inst->type->destroy)(inst);
! 757: ppp_bundle_destroy(&bundle);
! 758: FREE(BCONFIG_MTYPE, state);
! 759: }
! 760:
! 761: /*
! 762: * Handle a timeout trying to configure the bundle.
! 763: */
! 764: static void
! 765: ppp_bundle_config_timeout(void *arg)
! 766: {
! 767: struct ppp_bundle *bundle = arg;
! 768:
! 769: LOG(LOG_ERR, "timed out configuring new bundle");
! 770: paction_cancel(&bundle->action);
! 771: ppp_bundle_destroy(&bundle);
! 772: }
! 773:
! 774: /***********************************************************************
! 775: PPP NODE OUTPUT HANDLER
! 776: ***********************************************************************/
! 777:
! 778: /*
! 779: * Handle data received from the node's bypass hook.
! 780: */
! 781: static void
! 782: ppp_bundle_node_recv(void *arg, u_int link_num,
! 783: u_int16_t proto, u_char *data, size_t len)
! 784: {
! 785: struct ppp_bundle *const bundle = arg;
! 786:
! 787: /* Check for link-specific packets */
! 788: if (PPP_PROTO_LINK_LAYER(proto) && link_num != NG_PPP_BUNDLE_LINKNUM) {
! 789: if (link_num >= bundle->nlinks)
! 790: return;
! 791: ppp_link_recv_bypass(bundle->links[link_num], proto, data, len);
! 792: return;
! 793: }
! 794:
! 795: /* Handle packet at the bundle level */
! 796: switch (proto) {
! 797: case PPP_PROTO_IPCP:
! 798: if (bundle->ipcp != NULL)
! 799: ppp_fsm_input(bundle->ipcp, FSM_INPUT_DATA, data, len);
! 800: break;
! 801: case PPP_PROTO_CCP:
! 802: if (bundle->ccp != NULL)
! 803: ppp_fsm_input(bundle->ccp, FSM_INPUT_DATA, data, len);
! 804: else if (bundle->action == NULL) /* got config already */
! 805: goto proto_reject;
! 806: break;
! 807: case PPP_PROTO_MP:
! 808: case PPP_PROTO_IP:
! 809: case PPP_PROTO_VJCOMP:
! 810: case PPP_PROTO_VJUNCOMP:
! 811: case PPP_PROTO_COMPD:
! 812: break;
! 813: default:
! 814: goto proto_reject;
! 815: }
! 816: return;
! 817:
! 818: proto_reject:
! 819: /* Send a protocol reject */
! 820: if (bundle->lcp != NULL) {
! 821: ppp_fsm_input(bundle->lcp,
! 822: FSM_INPUT_XMIT_PROTOREJ, proto, data, len);
! 823: }
! 824: }
! 825:
! 826: /***********************************************************************
! 827: LCP EVENT HANDLER
! 828: ***********************************************************************/
! 829:
! 830: static void
! 831: ppp_bundle_lcp_event(void *arg)
! 832: {
! 833: struct ppp_bundle *const bundle = arg;
! 834: struct mesg_port *const outport = ppp_fsm_get_outport(bundle->lcp);
! 835: struct ppp_fsm_output *output;
! 836:
! 837: /* Read and handle all FSM events */
! 838: while ((output = mesg_port_get(outport, 0)) != NULL) {
! 839:
! 840: /* Check it out */
! 841: switch (output->type) {
! 842: case FSM_OUTPUT_DATA: /* probably an echo reply */
! 843: ppp_node_write(bundle->node, NG_PPP_BUNDLE_LINKNUM,
! 844: PPP_PROTO_LCP, output->u.data.data,
! 845: output->u.data.length);
! 846: break;
! 847: case FSM_OUTPUT_PROTOREJ:
! 848: {
! 849: LOG(LOG_NOTICE, "peer rejected protocol 0x%04x",
! 850: output->u.proto);
! 851: ppp_bundle_protorej(bundle, output->u.proto);
! 852: break;
! 853: }
! 854: case FSM_OUTPUT_OPEN:
! 855: case FSM_OUTPUT_CLOSE:
! 856: case FSM_OUTPUT_UP:
! 857: case FSM_OUTPUT_DOWN:
! 858: case FSM_OUTPUT_DEAD:
! 859: LOG(LOG_NOTICE, "unexpected LCP output: %s",
! 860: ppp_fsm_output_str(output));
! 861: break;
! 862: }
! 863:
! 864: /* Free output */
! 865: ppp_fsm_free_output(output);
! 866: }
! 867: }
! 868:
! 869: /***********************************************************************
! 870: IPCP EVENT HANDLER
! 871: ***********************************************************************/
! 872:
! 873: static void
! 874: ppp_bundle_ipcp_event(void *arg)
! 875: {
! 876: struct ppp_bundle *const bundle = arg;
! 877: struct mesg_port *const outport = ppp_fsm_get_outport(bundle->ipcp);
! 878: struct ppp_fsm_output *output;
! 879:
! 880: /* Read and handle all FSM events */
! 881: while ((output = mesg_port_get(outport, 0)) != NULL) {
! 882:
! 883: /* Check it out */
! 884: switch (output->type) {
! 885: case FSM_OUTPUT_OPEN:
! 886: case FSM_OUTPUT_CLOSE:
! 887: break;
! 888: case FSM_OUTPUT_UP:
! 889: {
! 890: static const char *chooks[][2] = {
! 891: { NG_PPP_HOOK_VJC_IP, NG_VJC_HOOK_IP },
! 892: { NG_PPP_HOOK_VJC_COMP, NG_VJC_HOOK_VJCOMP },
! 893: { NG_PPP_HOOK_VJC_UNCOMP, NG_VJC_HOOK_VJUNCOMP },
! 894: { NG_PPP_HOOK_VJC_VJIP, NG_VJC_HOOK_VJIP },
! 895: };
! 896: struct ng_ppp_node_conf conf;
! 897: struct ngm_vjc_config vjc;
! 898: struct ppp_ipcp_req req;
! 899: struct ngm_mkpeer mkpeer;
! 900: char buf[16];
! 901: u_int mtu;
! 902: int i;
! 903:
! 904: /* Remember IPCP is up */
! 905: bundle->ipcp_up = 1;
! 906:
! 907: /* Get negotiated parameters */
! 908: ppp_ipcp_get_req(bundle->ipcp, &req);
! 909: strlcpy(buf, inet_ntoa(req.ip[PPP_SELF]), sizeof(buf));
! 910: LOG(LOG_INFO, "IPCP successfully configured: "
! 911: "%s -> %s", buf, inet_ntoa(req.ip[PPP_PEER]));
! 912:
! 913: /* Get ppp node config */
! 914: if (ppp_node_get_config(bundle->node, &conf) == -1) {
! 915: LOG(LOG_ERR, "can't get ppp node config: %m");
! 916: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 917: break;
! 918: }
! 919:
! 920: /* Configure IP traffic */
! 921: conf.bund.enableIP =
! 922: !bundle->conf.mppe_reqd || bundle->ccp_up;
! 923: conf.bund.enableVJCompression = 0;
! 924: conf.bund.enableVJDecompression = 0;
! 925:
! 926: /* Skip VJC config if not negotiated */
! 927: if (!req.vjc[PPP_SELF].enabled
! 928: && !req.vjc[PPP_PEER].enabled)
! 929: goto no_vjc;
! 930:
! 931: /* Attach vjc node to ppp node */
! 932: (void)ppp_node_send_msg(bundle->node,
! 933: chooks[0][0], NGM_GENERIC_COOKIE,
! 934: NGM_SHUTDOWN, NULL, 0);
! 935: memset(&mkpeer, 0, sizeof(mkpeer));
! 936: strlcpy(mkpeer.type,
! 937: NG_VJC_NODE_TYPE, sizeof(mkpeer.type));
! 938: strlcpy(mkpeer.ourhook,
! 939: chooks[0][0], sizeof(mkpeer.ourhook));
! 940: strlcpy(mkpeer.peerhook,
! 941: chooks[0][1], sizeof(mkpeer.peerhook));
! 942: if (ppp_node_send_msg(bundle->node, NULL,
! 943: NGM_GENERIC_COOKIE, NGM_MKPEER, &mkpeer,
! 944: sizeof(mkpeer)) == -1) {
! 945: LOG(LOG_ERR, "can't attach VJC node: %m");
! 946: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 947: break;
! 948: }
! 949: for (i = 1; i < sizeof(chooks) / sizeof(*chooks); i++) {
! 950: struct ngm_connect connect;
! 951:
! 952: memset(&connect, 0, sizeof(connect));
! 953: strlcpy(connect.path,
! 954: NG_PPP_HOOK_VJC_IP, sizeof(connect.path));
! 955: strlcpy(connect.ourhook,
! 956: chooks[i][0], sizeof(connect.ourhook));
! 957: strlcpy(connect.peerhook,
! 958: chooks[i][1], sizeof(connect.peerhook));
! 959: if (ppp_node_send_msg(bundle->node, NULL,
! 960: NGM_GENERIC_COOKIE, NGM_CONNECT, &connect,
! 961: sizeof(connect)) == -1) {
! 962: LOG(LOG_ERR,
! 963: "can't connect VJC node: %m");
! 964: ppp_fsm_input(bundle->ipcp,
! 965: FSM_INPUT_CLOSE);
! 966: break;
! 967: }
! 968: }
! 969: if (i < sizeof(chooks) / sizeof(*chooks)) /* failed */
! 970: break;
! 971:
! 972: /* Configure VJ compression node */
! 973: memset(&vjc, 0, sizeof(vjc));
! 974: vjc.enableComp = req.vjc[PPP_PEER].enabled;
! 975: vjc.enableDecomp = req.vjc[PPP_SELF].enabled;
! 976: vjc.maxChannel = req.vjc[PPP_PEER].maxchan;
! 977: vjc.compressCID = req.vjc[PPP_PEER].compcid;
! 978: if (ppp_node_send_msg(bundle->node, NG_PPP_HOOK_VJC_IP,
! 979: NGM_VJC_COOKIE, NGM_VJC_SET_CONFIG,
! 980: &vjc, sizeof(vjc)) == -1) {
! 981: LOG(LOG_ERR, "error configuring VJC node: %m");
! 982: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 983: break;
! 984: }
! 985:
! 986: /* Configure ppp node to enable VJ (de)compression */
! 987: conf.bund.enableVJCompression
! 988: = req.vjc[PPP_PEER].enabled;
! 989: conf.bund.enableVJDecompression
! 990: = req.vjc[PPP_SELF].enabled;
! 991:
! 992: no_vjc:
! 993: /*
! 994: * Determine the MTU for the interface
! 995: *
! 996: * XXX if/when compression is added, we must account
! 997: * XXX for any possible payload expansion here as well
! 998: */
! 999: mtu = bundle->multilink ? bundle->node_conf.bund.mrru
! 1000: : bundle->node_conf.links[0].mru;
! 1001: if (bundle->conf.mppe_40
! 1002: || bundle->conf.mppe_56
! 1003: || bundle->conf.mppe_128)
! 1004: mtu -= 4; /* allow for mppe header */
! 1005:
! 1006: /* Plumb the 'top' side of the node */
! 1007: if ((bundle->plumb_arg =
! 1008: ppp_engine_bundle_plumb(bundle->engine, bundle,
! 1009: ppp_node_get_path(bundle->node), NG_PPP_HOOK_INET,
! 1010: req.ip, req.dns, req.nbns, mtu)) == NULL) {
! 1011: LOG(LOG_ERR, "error plumbing ppp node: %m");
! 1012: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 1013: break;
! 1014: }
! 1015:
! 1016: /* Update ppp node configuration */
! 1017: if (ppp_node_set_config(bundle->node, &conf) == -1) {
! 1018: LOG(LOG_ERR, "error configuring ppp node: %m");
! 1019: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 1020: break;
! 1021: }
! 1022: break;
! 1023: }
! 1024: case FSM_OUTPUT_DOWN:
! 1025: {
! 1026: struct ng_ppp_node_conf conf;
! 1027: void *parg;
! 1028:
! 1029: /* Remember IPCP is down */
! 1030: bundle->ipcp_up = 0;
! 1031:
! 1032: /* Get ppp node config */
! 1033: if (ppp_node_get_config(bundle->node, &conf) == -1) {
! 1034: LOG(LOG_ERR, "can't get ppp node config: %m");
! 1035: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 1036: break;
! 1037: }
! 1038:
! 1039: /* Disable IP and VJC packets */
! 1040: conf.bund.enableIP = 0;
! 1041: conf.bund.enableVJCompression = 0;
! 1042: conf.bund.enableVJDecompression = 0;
! 1043:
! 1044: /* Update ppp node configuration */
! 1045: if (ppp_node_set_config(bundle->node, &conf) == -1) {
! 1046: LOG(LOG_ERR, "error configuring ppp node: %m");
! 1047: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 1048: break;
! 1049: }
! 1050:
! 1051: /* Clobber VJC node (if any) */
! 1052: (void)ppp_node_send_msg(bundle->node,
! 1053: NG_PPP_HOOK_VJC_IP, NGM_GENERIC_COOKIE,
! 1054: NGM_SHUTDOWN, NULL, 0);
! 1055:
! 1056: /* Disconnect the 'top' side of the node */
! 1057: if ((parg = bundle->plumb_arg) != NULL) {
! 1058: bundle->plumb_arg = NULL;
! 1059: ppp_engine_bundle_unplumb(bundle->engine,
! 1060: parg, bundle);
! 1061: }
! 1062: break;
! 1063: }
! 1064: case FSM_OUTPUT_DATA:
! 1065: ppp_node_write(bundle->node, NG_PPP_BUNDLE_LINKNUM,
! 1066: PPP_PROTO_IPCP, output->u.data.data,
! 1067: output->u.data.length);
! 1068: break;
! 1069: case FSM_OUTPUT_PROTOREJ:
! 1070: LOG(LOG_NOTICE, "unexpected IPCP output: %s",
! 1071: ppp_fsm_output_str(output));
! 1072: break;
! 1073: case FSM_OUTPUT_DEAD:
! 1074: LOG(LOG_INFO, "IPCP is dead: %s",
! 1075: ppp_fsm_reason_str(output));
! 1076: ppp_fsm_destroy(&bundle->ipcp);
! 1077: ppp_bundle_fsm_dead(bundle);
! 1078: ppp_fsm_free_output(output);
! 1079: return;
! 1080: }
! 1081:
! 1082: /* Free output */
! 1083: ppp_fsm_free_output(output);
! 1084: }
! 1085: }
! 1086:
! 1087: /***********************************************************************
! 1088: CCP EVENT HANDLER
! 1089: ***********************************************************************/
! 1090:
! 1091: static void
! 1092: ppp_bundle_ccp_event(void *arg)
! 1093: {
! 1094: struct ppp_bundle *const bundle = arg;
! 1095: struct mesg_port *const outport = ppp_fsm_get_outport(bundle->ccp);
! 1096: struct ppp_fsm_output *output;
! 1097:
! 1098: /* Read and handle all FSM events */
! 1099: while ((output = mesg_port_get(outport, 0)) != NULL) {
! 1100:
! 1101: /* Check it out */
! 1102: switch (output->type) {
! 1103: case FSM_OUTPUT_OPEN:
! 1104: case FSM_OUTPUT_CLOSE:
! 1105: break;
! 1106: case FSM_OUTPUT_UP:
! 1107: {
! 1108: struct ng_ppp_node_conf conf;
! 1109: struct ngm_connect connect;
! 1110: struct ngm_mkpeer mkpeer;
! 1111: struct ppp_ccp_req req;
! 1112: char buf[2][64];
! 1113: int i;
! 1114:
! 1115: /* Remember CCP is up */
! 1116: bundle->ccp_up = 1;
! 1117:
! 1118: /* Some peers don't know 56 bit and will ack it too */
! 1119: for (i = 0; i < 2; i++) {
! 1120: if (req.mppe56[i]
! 1121: && (req.mppe40[i] || req.mppe128[i]))
! 1122: req.mppe56[i] = 0;
! 1123: }
! 1124:
! 1125: /* Get negotiated parameters */
! 1126: ppp_ccp_get_req(bundle->ccp, &req);
! 1127: for (i = 0; i < 2; i++) {
! 1128: strlcpy(buf[i], "MPPC", sizeof(buf[i]));
! 1129: if (req.mppc[i]) {
! 1130: strlcat(buf[i], " compression",
! 1131: sizeof(buf[i]));
! 1132: }
! 1133: if (req.mppe40[i]) {
! 1134: strlcat(buf[i], " 40 bit encryption",
! 1135: sizeof(buf[i]));
! 1136: } else if (req.mppe56[i]) {
! 1137: strlcat(buf[i], " 56 bit encryption",
! 1138: sizeof(buf[i]));
! 1139: } else if (req.mppe128[i]) {
! 1140: strlcat(buf[i], " 128 bit encryption",
! 1141: sizeof(buf[i]));
! 1142: }
! 1143: if (req.mppe_stateless[i]) {
! 1144: strlcat(buf[i], ", stateless",
! 1145: sizeof(buf[i]));
! 1146: }
! 1147: }
! 1148: LOG(LOG_INFO, "CCP successfully configured: "
! 1149: "Recv: %s; Xmit: %s", buf[PPP_SELF], buf[PPP_PEER]);
! 1150:
! 1151: /* Get ppp node config */
! 1152: if (ppp_node_get_config(bundle->node, &conf) == -1) {
! 1153: LOG(LOG_ERR, "can't get ppp node config: %m");
! 1154: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1155: break;
! 1156: }
! 1157:
! 1158: /* Enable IP traffic now */
! 1159: if (bundle->ipcp_up)
! 1160: conf.bund.enableIP = 1;
! 1161:
! 1162: /* Configure ppp node to enable MPPC (de)compression */
! 1163: conf.bund.enableCompression = req.mppc[PPP_PEER]
! 1164: || req.mppe40[PPP_PEER]
! 1165: || req.mppe56[PPP_PEER]
! 1166: || req.mppe128[PPP_PEER];
! 1167: conf.bund.enableDecompression = req.mppc[PPP_SELF]
! 1168: || req.mppe40[PPP_SELF]
! 1169: || req.mppe56[PPP_SELF]
! 1170: || req.mppe128[PPP_SELF];
! 1171:
! 1172: /* Attach mppc node to ppp node */
! 1173: (void)ppp_node_send_msg(bundle->node,
! 1174: NG_PPP_HOOK_COMPRESS, NGM_GENERIC_COOKIE,
! 1175: NGM_SHUTDOWN, NULL, 0);
! 1176: memset(&mkpeer, 0, sizeof(mkpeer));
! 1177: strlcpy(mkpeer.type,
! 1178: NG_MPPC_NODE_TYPE, sizeof(mkpeer.type));
! 1179: strlcpy(mkpeer.ourhook,
! 1180: NG_PPP_HOOK_COMPRESS, sizeof(mkpeer.ourhook));
! 1181: strlcpy(mkpeer.peerhook,
! 1182: NG_MPPC_HOOK_COMP, sizeof(mkpeer.peerhook));
! 1183: if (ppp_node_send_msg(bundle->node, NULL,
! 1184: NGM_GENERIC_COOKIE, NGM_MKPEER, &mkpeer,
! 1185: sizeof(mkpeer)) == -1) {
! 1186: LOG(LOG_ERR, "can't attach MPPC node: %m");
! 1187: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1188: break;
! 1189: }
! 1190: memset(&connect, 0, sizeof(connect));
! 1191: strlcpy(connect.path,
! 1192: NG_PPP_HOOK_COMPRESS, sizeof(connect.path));
! 1193: strlcpy(connect.ourhook,
! 1194: NG_PPP_HOOK_DECOMPRESS, sizeof(connect.ourhook));
! 1195: strlcpy(connect.peerhook,
! 1196: NG_MPPC_HOOK_DECOMP, sizeof(connect.peerhook));
! 1197: if (ppp_node_send_msg(bundle->node, NULL,
! 1198: NGM_GENERIC_COOKIE, NGM_CONNECT, &connect,
! 1199: sizeof(connect)) == -1) {
! 1200: LOG(LOG_ERR, "can't connect MPPC node: %m");
! 1201: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1202: break;
! 1203: }
! 1204:
! 1205: /* Verify we have the MPPE keys that we need */
! 1206: for (i = 0; i < 2; i++) {
! 1207: if (((req.mppe40[i] || req.mppe56[i])
! 1208: && memcmp(&bundle->mppe_64[i],
! 1209: ppp_bundle_zero, 8) == 0)
! 1210: || (req.mppe128[i]
! 1211: && memcmp(&bundle->mppe_128[i],
! 1212: ppp_bundle_zero, 16) == 0)) {
! 1213: LOG(LOG_ERR, "can't do MPPE encryption:"
! 1214: " no keys were provided by the"
! 1215: " authentication process");
! 1216: ppp_fsm_input(bundle->ccp,
! 1217: FSM_INPUT_CLOSE);
! 1218: break;
! 1219: }
! 1220: }
! 1221: if (i < 2)
! 1222: break;
! 1223:
! 1224: /* Configure MPPC node in both directions */
! 1225: for (i = 0; i < 2; i++) {
! 1226: struct ng_mppc_config mppc;
! 1227:
! 1228: memset(&mppc, 0, sizeof(mppc));
! 1229: mppc.enable = req.mppc[i] || req.mppe40[i]
! 1230: || req.mppe56[i] || req.mppe128[i];
! 1231: if (req.mppc[i])
! 1232: mppc.bits |= MPPC_BIT;
! 1233: if (req.mppe40[i] || req.mppe56[i]) {
! 1234: mppc.bits |= req.mppe40[i] ?
! 1235: MPPE_40 : MPPE_56;
! 1236: memcpy(mppc.startkey,
! 1237: &bundle->mppe_64[i],
! 1238: sizeof(bundle->mppe_64[i]));
! 1239: } else if (req.mppe128[i]) {
! 1240: mppc.bits |= MPPE_128;
! 1241: memcpy(mppc.startkey,
! 1242: &bundle->mppe_128[i],
! 1243: sizeof(bundle->mppe_128[i]));
! 1244: }
! 1245: if (req.mppe_stateless[i])
! 1246: mppc.bits |= MPPE_STATELESS;
! 1247: if (ppp_node_send_msg(bundle->node,
! 1248: NG_PPP_HOOK_COMPRESS, NGM_MPPC_COOKIE,
! 1249: (i == PPP_SELF) ? NGM_MPPC_CONFIG_DECOMP
! 1250: : NGM_MPPC_CONFIG_COMP,
! 1251: &mppc, sizeof(mppc)) == -1) {
! 1252: LOG(LOG_ERR,
! 1253: "error configuring MPPC node: %m");
! 1254: ppp_fsm_input(bundle->ccp,
! 1255: FSM_INPUT_CLOSE);
! 1256: break;
! 1257: }
! 1258: }
! 1259:
! 1260: /* Update ppp node configuration */
! 1261: if (ppp_node_set_config(bundle->node, &conf) == -1) {
! 1262: LOG(LOG_ERR, "error configuring ppp node: %m");
! 1263: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1264: break;
! 1265: }
! 1266: break;
! 1267: }
! 1268: case FSM_OUTPUT_DOWN:
! 1269: {
! 1270: struct ng_ppp_node_conf conf;
! 1271:
! 1272: /* Remember CCP is down */
! 1273: bundle->ccp_up = 0;
! 1274:
! 1275: /* Get ppp node config */
! 1276: if (ppp_node_get_config(bundle->node, &conf) == -1) {
! 1277: LOG(LOG_ERR, "can't get ppp node config: %m");
! 1278: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1279: break;
! 1280: }
! 1281:
! 1282: /* Disable IP traffic if encryption is required */
! 1283: if (bundle->conf.mppe_reqd)
! 1284: conf.bund.enableIP = 0;
! 1285:
! 1286: /* Disable compression */
! 1287: conf.bund.enableCompression = 0;
! 1288: conf.bund.enableDecompression = 0;
! 1289:
! 1290: /* Update ppp node configuration */
! 1291: if (ppp_node_set_config(bundle->node, &conf) == -1) {
! 1292: LOG(LOG_ERR, "error configuring ppp node: %m");
! 1293: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1294: break;
! 1295: }
! 1296:
! 1297: /* Clobber MPPC node */
! 1298: (void)ppp_node_send_msg(bundle->node,
! 1299: NG_PPP_HOOK_COMPRESS, NGM_GENERIC_COOKIE,
! 1300: NGM_SHUTDOWN, NULL, 0);
! 1301: break;
! 1302: }
! 1303: case FSM_OUTPUT_DATA:
! 1304: ppp_node_write(bundle->node, NG_PPP_BUNDLE_LINKNUM,
! 1305: PPP_PROTO_CCP, output->u.data.data,
! 1306: output->u.data.length);
! 1307: break;
! 1308: case FSM_OUTPUT_PROTOREJ:
! 1309: LOG(LOG_NOTICE, "unexpected CCP output: %s",
! 1310: ppp_fsm_output_str(output));
! 1311: break;
! 1312: case FSM_OUTPUT_DEAD:
! 1313: LOG(LOG_INFO, "CCP is dead: %s",
! 1314: ppp_fsm_reason_str(output));
! 1315: ppp_fsm_destroy(&bundle->ccp);
! 1316: ppp_bundle_fsm_dead(bundle);
! 1317: ppp_fsm_free_output(output);
! 1318: return;
! 1319: }
! 1320:
! 1321: /* Free output */
! 1322: ppp_fsm_free_output(output);
! 1323: }
! 1324: }
! 1325:
! 1326: /***********************************************************************
! 1327: INTERNAL FUNCTIONS
! 1328: ***********************************************************************/
! 1329:
! 1330: /*
! 1331: * One of our network control protocols has died.
! 1332: * If this is fatal, then shutdown the bundle.
! 1333: */
! 1334: static void
! 1335: ppp_bundle_fsm_dead(struct ppp_bundle *bundle)
! 1336: {
! 1337: if (bundle->ipcp == NULL) {
! 1338: ppp_bundle_shutdown(bundle);
! 1339: return;
! 1340: }
! 1341: if (bundle->conf.mppe_reqd && bundle->ccp == NULL) {
! 1342: LOG(LOG_ERR, "MPPE is required but CCP negotiation failed");
! 1343: ppp_bundle_shutdown(bundle);
! 1344: }
! 1345: }
! 1346:
! 1347: /*
! 1348: * Shutdown the bundle.
! 1349: */
! 1350: static void
! 1351: ppp_bundle_shutdown(struct ppp_bundle *bundle)
! 1352: {
! 1353: int i;
! 1354:
! 1355: if (bundle->ipcp != NULL)
! 1356: ppp_fsm_input(bundle->ipcp, FSM_INPUT_CLOSE);
! 1357: if (bundle->ccp != NULL)
! 1358: ppp_fsm_input(bundle->ccp, FSM_INPUT_CLOSE);
! 1359: for (i = 0; i < bundle->nlinks; i++)
! 1360: ppp_link_close(bundle->links[i]);
! 1361: }
! 1362:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>