Annotation of embedaddon/libpdel/ppp/ppp_link.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_lcp.h"
! 47: #include "ppp/ppp_node.h"
! 48: #include "ppp/ppp_engine.h"
! 49: #include "ppp/ppp_bundle.h"
! 50: #include "ppp/ppp_channel.h"
! 51: #include "ppp/ppp_link.h"
! 52:
! 53: #define LINK_MTYPE "ppp_link"
! 54: #define PKTBUFLEN 4096
! 55: #define LINK_LATENCY 100 /* arbitrary fixed value */
! 56: #define LINK_BANDWIDTH 100 /* arbitrary fixed value */
! 57:
! 58: #define AUTH_TIMEOUT 20 /* time limit for auth phase */
! 59:
! 60: #define WINXP_PPTP_HACK(x) ((x) - 20) /* winxp pptp stupidity hack */
! 61:
! 62: /*
! 63: * Authorization info for one direction
! 64: */
! 65: struct ppp_link_auth {
! 66: struct ppp_link *link; /* back pointer */
! 67: u_int16_t proto; /* auth protocol number */
! 68: const struct ppp_auth_type *type; /* auth type negotiated */
! 69: void *arg; /* auth object in progress */
! 70: struct ppp_auth_cred cred; /* auth credentials */
! 71: struct ppp_auth_resp resp; /* auth response */
! 72: union ppp_auth_mppe mppe; /* mppe keys from ms-chap */
! 73: struct paction *action;/* auth acquire/check action */
! 74: };
! 75:
! 76: /*
! 77: * PPP link structure
! 78: */
! 79: struct ppp_link {
! 80: enum ppp_link_state state; /* link state */
! 81: struct ppp_log *log; /* log */
! 82: struct ppp_link_config conf; /* link configuration */
! 83: struct ppp_engine *engine; /* ppp engine */
! 84: struct ppp_channel *device; /* underlying device */
! 85: struct ppp_node *node; /* ng_ppp(4) node */
! 86: struct ppp_fsm *lcp; /* lcp fsm */
! 87: struct ppp_lcp_req lcp_req; /* lcp negotiation result */
! 88: struct ppp_bundle *bundle; /* bundle, if joined */
! 89: struct pevent_ctx *ev_ctx; /* event context */
! 90: pthread_mutex_t *mutex; /* mutex */
! 91: struct pevent *lcp_event; /* lcp fsm event */
! 92: struct pevent *dev_event; /* device event */
! 93: struct pevent *auth_timer; /* timer for auth phase */
! 94: u_char device_up; /* device is up */
! 95: struct ppp_link_auth auth[2]; /* authorization info */
! 96: u_int16_t link_num; /* ppp node link number */
! 97: u_char shutdown; /* normal shutdown */
! 98: };
! 99:
! 100: /* Internal functions */
! 101: static void ppp_link_join(struct ppp_link *link);
! 102: static void ppp_link_unjoin(struct ppp_link *link);
! 103: static int ppp_link_get_node(struct ppp_link *link);
! 104: static void ppp_link_auth_start(struct ppp_link *link);
! 105: static void ppp_link_auth_stop(struct ppp_link *link);
! 106:
! 107: static ppp_node_recv_t ppp_link_node_recv;
! 108:
! 109: static pevent_handler_t ppp_link_device_event;
! 110: static pevent_handler_t ppp_link_lcp_event;
! 111: static pevent_handler_t ppp_link_auth_timeout;
! 112:
! 113: /* Macro for logging */
! 114: #define LOG(sev, fmt, args...) PPP_LOG(link->log, sev, fmt , ## args)
! 115:
! 116: /***********************************************************************
! 117: PUBLIC FUNCTIONS
! 118: ***********************************************************************/
! 119:
! 120: /*
! 121: * Create a new PPP link.
! 122: *
! 123: * The link is not returned. Instead it disappears into the PPP engine.
! 124: * The "device" and "log" are destroyed when the link is destroyed.
! 125: */
! 126: int
! 127: ppp_link_create(struct ppp_engine *engine, struct ppp_channel *device,
! 128: struct ppp_link_config *conf, struct ppp_log *log)
! 129: {
! 130: struct ppp_fsm_instance *inst = NULL;
! 131: struct ppp_lcp_config lcp_conf;
! 132: struct ppp_fsm *lcp = NULL;
! 133: struct ppp_link *link;
! 134: int esave;
! 135: int i;
! 136: int j;
! 137:
! 138: /* Create new link structure */
! 139: if ((link = MALLOC(LINK_MTYPE, sizeof(*link))) == NULL)
! 140: return (-1);
! 141: memset(link, 0, sizeof(*link));
! 142: link->state = PPP_LINK_DOWN;
! 143: link->engine = engine;
! 144: link->ev_ctx = ppp_engine_get_ev_ctx(engine);
! 145: link->mutex = ppp_engine_get_mutex(engine);
! 146: link->device = device;
! 147: link->conf = *conf;
! 148: link->log = log;
! 149: for (i = 0; i < 2; i++)
! 150: link->auth[i].link = link;
! 151:
! 152: /* Derive LCP configuration from link configuration and device info */
! 153: memset(&lcp_conf, 0, sizeof(lcp_conf));
! 154: lcp_conf.max_mru[PPP_SELF] = conf->max_self_mru;
! 155: lcp_conf.min_mru[PPP_PEER] = conf->min_peer_mru;
! 156: lcp_conf.accm = ppp_channel_is_async(device) ? 0x0a000000 : ~0;
! 157: if (ppp_channel_get_acfcomp(device)) {
! 158: lcp_conf.acfcomp[PPP_SELF] = 1;
! 159: lcp_conf.acfcomp[PPP_PEER] = 1;
! 160: }
! 161: if (ppp_channel_get_pfcomp(device)) {
! 162: lcp_conf.pfcomp[PPP_SELF] = 1;
! 163: lcp_conf.pfcomp[PPP_PEER] = 1;
! 164: }
! 165: for (i = 0; i < PPP_AUTH_MAX; i++) {
! 166: for (j = 0; j < 2; j++) {
! 167: if ((conf->auth.allow[j] & (1 << i)) != 0)
! 168: lcp_conf.auth[j][i] = 1;
! 169: }
! 170: }
! 171: lcp_conf.eid = conf->eid;
! 172: if (conf->multilink) {
! 173: lcp_conf.max_mrru[PPP_SELF] = conf->max_self_mrru;
! 174: lcp_conf.min_mrru[PPP_PEER] = conf->min_peer_mrru;
! 175: lcp_conf.multilink[PPP_SELF] = 1;
! 176: lcp_conf.multilink[PPP_PEER] = 1;
! 177: lcp_conf.shortseq[PPP_SELF] = 1;
! 178: lcp_conf.shortseq[PPP_PEER] = 1;
! 179: }
! 180:
! 181: /* Create ppp node object */
! 182: if (ppp_link_get_node(link) == -1)
! 183: goto fail;
! 184:
! 185: /* Create a new LCP FSM for this link */
! 186: if ((inst = ppp_lcp_create(&lcp_conf)) == NULL) {
! 187: LOG(LOG_ERR, "failed to create LCP: %m");
! 188: goto fail;
! 189: }
! 190: if ((link->lcp = ppp_fsm_create(link->ev_ctx,
! 191: link->mutex, inst, link->log)) == NULL) {
! 192: LOG(LOG_ERR, "failed to create LCP: %m");
! 193: goto fail;
! 194: }
! 195: inst = NULL;
! 196:
! 197: /* Listen for device events */
! 198: if (pevent_register(link->ev_ctx, &link->dev_event, PEVENT_RECURRING,
! 199: link->mutex, ppp_link_device_event, link, PEVENT_MESG_PORT,
! 200: ppp_channel_get_outport(link->device)) == -1) {
! 201: LOG(LOG_ERR, "%s: %m", "adding read event");
! 202: goto fail;
! 203: }
! 204:
! 205: /* Listen for LCP events */
! 206: if (pevent_register(link->ev_ctx, &link->lcp_event, PEVENT_RECURRING,
! 207: link->mutex, ppp_link_lcp_event, link, PEVENT_MESG_PORT,
! 208: ppp_fsm_get_outport(link->lcp)) == -1) {
! 209: LOG(LOG_ERR, "%s: %m", "adding read event");
! 210: goto fail;
! 211: }
! 212:
! 213: /* Notify engine of new link */
! 214: if (ppp_engine_add_link(engine, link) == -1) {
! 215: LOG(LOG_ERR, "failed to add link: %m");
! 216: goto fail;
! 217: }
! 218:
! 219: /* Start LCP negotiations (whenver link comes up) */
! 220: ppp_fsm_input(link->lcp, FSM_INPUT_OPEN);
! 221:
! 222: /* Done */
! 223: return (0);
! 224:
! 225: fail:
! 226: /* Clean up after failure */
! 227: esave = errno;
! 228: pevent_unregister(&link->dev_event);
! 229: pevent_unregister(&link->lcp_event);
! 230: ppp_node_destroy(&link->node);
! 231: ppp_node_destroy(&link->node);
! 232: ppp_fsm_destroy(&lcp);
! 233: if (inst != NULL)
! 234: (*inst->type->destroy)(inst);
! 235: FREE(LINK_MTYPE, link);
! 236: errno = esave;
! 237: return (-1);
! 238: }
! 239:
! 240: /*
! 241: * Destroy a link.
! 242: */
! 243: void
! 244: ppp_link_destroy(struct ppp_link **linkp)
! 245: {
! 246: struct ppp_link *const link = *linkp;
! 247: int r;
! 248:
! 249: /* Sanity check */
! 250: if (link == NULL)
! 251: return;
! 252: *linkp = NULL;
! 253:
! 254: /* Avoid recursion */
! 255: if (link->shutdown)
! 256: return;
! 257: link->shutdown = 1;
! 258:
! 259: /* Acquire lock */
! 260: r = pthread_mutex_lock(link->mutex);
! 261: assert(r == 0);
! 262:
! 263: /* Stop authentication (if any) */
! 264: ppp_link_auth_stop(link);
! 265:
! 266: /* Disconnect from bundle or engine */
! 267: ppp_bundle_unjoin(&link->bundle, link);
! 268: ppp_engine_del_link(link->engine, link);
! 269:
! 270: /* Destroy link */
! 271: r = pthread_mutex_unlock(link->mutex);
! 272: assert(r == 0);
! 273: ppp_fsm_destroy(&link->lcp);
! 274: pevent_unregister(&link->dev_event);
! 275: pevent_unregister(&link->lcp_event);
! 276: ppp_node_destroy(&link->node);
! 277: ppp_channel_destroy(&link->device);
! 278: ppp_log_close(&link->log);
! 279: FREE(LINK_MTYPE, link);
! 280: }
! 281:
! 282: /*
! 283: * Close a link.
! 284: */
! 285: void
! 286: ppp_link_close(struct ppp_link *link)
! 287: {
! 288: ppp_link_auth_stop(link);
! 289: ppp_fsm_input(link->lcp, FSM_INPUT_CLOSE);
! 290: }
! 291:
! 292: /*
! 293: * Get the device associated with a link.
! 294: */
! 295: struct ppp_channel *
! 296: ppp_link_get_device(struct ppp_link *link)
! 297: {
! 298: return (link->device);
! 299: }
! 300:
! 301: /*
! 302: * Get the link's origination (PPP_SELF or PPP_PEER) which
! 303: * is simply inherited from the underlying device.
! 304: */
! 305: int
! 306: ppp_link_get_origination(struct ppp_link *link)
! 307: {
! 308: return (ppp_channel_get_origination(link->device));
! 309: }
! 310:
! 311: /*
! 312: * Get link state.
! 313: */
! 314: enum ppp_link_state
! 315: ppp_link_get_state(struct ppp_link *link)
! 316: {
! 317: return (link->state);
! 318: }
! 319:
! 320: /*
! 321: * Get bundle associated with link, if any.
! 322: */
! 323: struct ppp_bundle *
! 324: ppp_link_get_bundle(struct ppp_link *link)
! 325: {
! 326: if (link->bundle == NULL)
! 327: errno = ENXIO;
! 328: return (link->bundle);
! 329: }
! 330:
! 331: /*
! 332: * Get LCP request state.
! 333: */
! 334: void
! 335: ppp_link_get_lcp_req(struct ppp_link *link, struct ppp_lcp_req *req)
! 336: {
! 337: ppp_lcp_get_req(link->lcp, req);
! 338: }
! 339:
! 340: /*
! 341: * Get link authorization name.
! 342: *
! 343: * Note: we reverse the sense of 'dir' because we want PPP_SELF to
! 344: * mean my authname to peer, which is the opposite of the way that
! 345: * authorization is negotiated, i.e., PPP_SELF is peer's auth to me.
! 346: */
! 347: const char *
! 348: ppp_link_get_authname(struct ppp_link *link, int dir)
! 349: {
! 350: struct ppp_link_auth *const auth = &link->auth[!dir];
! 351:
! 352: if (auth->type == NULL)
! 353: return ("");
! 354: switch (auth->type->index) {
! 355: case PPP_AUTH_PAP:
! 356: return (auth->cred.u.pap.name);
! 357: case PPP_AUTH_CHAP_MSV1:
! 358: case PPP_AUTH_CHAP_MSV2:
! 359: case PPP_AUTH_CHAP_MD5:
! 360: return (auth->cred.u.chap.name);
! 361: default:
! 362: return ("");
! 363: }
! 364: }
! 365:
! 366: /*
! 367: * Get endpoint ID.
! 368: */
! 369: void
! 370: ppp_link_get_eid(struct ppp_link *link, int dir, struct ppp_eid *eid)
! 371: {
! 372: struct ppp_lcp_req req;
! 373:
! 374: dir &= 1;
! 375: ppp_lcp_get_req(link->lcp, &req);
! 376: *eid = req.eid[dir];
! 377: }
! 378:
! 379: void
! 380: ppp_link_get_mppe(struct ppp_link *link, int dir, union ppp_auth_mppe *mppe)
! 381: {
! 382: struct ppp_link_auth *const auth = &link->auth[dir & 1];
! 383:
! 384: memcpy(mppe, &auth->mppe, sizeof(*mppe));
! 385: }
! 386:
! 387: /*
! 388: * Ouput a packet on the link.
! 389: */
! 390: void
! 391: ppp_link_write(struct ppp_link *link,
! 392: u_int16_t proto, const void *data, size_t len)
! 393: {
! 394: int rtn;
! 395:
! 396: /* Drop packet if channel is down */
! 397: if (!link->device_up)
! 398: return;
! 399:
! 400: /* Write packet */
! 401: if (link->bundle != NULL) {
! 402: rtn = ppp_bundle_write(link->bundle,
! 403: link->link_num, proto, data, len);
! 404: } else {
! 405: rtn = ppp_node_write(link->node,
! 406: link->link_num, proto, data, len);
! 407: }
! 408:
! 409: if (rtn == -1) {
! 410: LOG(LOG_ERR, "%s: %m", "error writing to bypass");
! 411: ppp_link_close(link);
! 412: }
! 413: }
! 414:
! 415: /***********************************************************************
! 416: LCP EVENT HANDLER
! 417: ***********************************************************************/
! 418:
! 419: static void
! 420: ppp_link_lcp_event(void *arg)
! 421: {
! 422: struct ppp_link *link = arg;
! 423: struct mesg_port *const outport = ppp_fsm_get_outport(link->lcp);
! 424: struct ppp_fsm_output *output;
! 425:
! 426: /* Read and handle all FSM events */
! 427: while ((output = mesg_port_get(outport, 0)) != NULL) {
! 428:
! 429: /* Check it out */
! 430: switch (output->type) {
! 431: case FSM_OUTPUT_OPEN:
! 432: ppp_channel_open(link->device);
! 433: break;
! 434: case FSM_OUTPUT_CLOSE:
! 435: ppp_channel_close(link->device);
! 436: break;
! 437: case FSM_OUTPUT_UP:
! 438: {
! 439: struct ng_ppp_node_conf conf;
! 440: struct ng_ppp_link_conf *const lconf = &conf.links[0];
! 441:
! 442: /* Get ng_ppp(4) node configuration */
! 443: if (ppp_node_get_config(link->node, &conf) == -1) {
! 444: LOG(LOG_ERR, "can't configure node: %m");
! 445: ppp_link_close(link);
! 446: break;
! 447: }
! 448:
! 449: /* Update with negotiated LCP parameters */
! 450: ppp_lcp_get_req(link->lcp, &link->lcp_req);
! 451: lconf->enableProtoComp = link->lcp_req.pfcomp[PPP_PEER];
! 452: lconf->enableACFComp = link->lcp_req.acfcomp[PPP_PEER];
! 453: lconf->mru = MIN(
! 454: WINXP_PPTP_HACK(link->lcp_req.mru[PPP_PEER]),
! 455: ppp_channel_get_mtu(link->device));
! 456: lconf->latency = LINK_LATENCY;
! 457: lconf->bandwidth = LINK_BANDWIDTH;
! 458: if (ppp_node_set_config(link->node, &conf) == -1) {
! 459: LOG(LOG_ERR, "can't configure node: %m");
! 460: ppp_link_close(link);
! 461: break;
! 462: }
! 463:
! 464: /* Begin authentication phase */
! 465: link->state = PPP_LINK_AUTH;
! 466: ppp_link_auth_start(link);
! 467: break;
! 468: }
! 469: case FSM_OUTPUT_DOWN:
! 470: link->state = PPP_LINK_DOWN;
! 471: ppp_link_auth_stop(link);
! 472: if (link->bundle != NULL) {
! 473:
! 474: /* Leave our bundle */
! 475: assert(link->node == NULL);
! 476: ppp_bundle_unjoin(&link->bundle, link);
! 477:
! 478: /* Create a new node for this link */
! 479: if (ppp_link_get_node(link) == -1) {
! 480: ppp_link_close(link);
! 481: break;
! 482: }
! 483: }
! 484: break;
! 485: case FSM_OUTPUT_DATA:
! 486: ppp_link_write(link, PPP_PROTO_LCP,
! 487: output->u.data.data, output->u.data.length);
! 488: break;
! 489: case FSM_OUTPUT_PROTOREJ:
! 490: {
! 491: /* Log it */
! 492: LOG(LOG_NOTICE,
! 493: "peer rejected protocol 0x%04x", output->u.proto);
! 494:
! 495: /* If fatal, shut down, else report to bundle */
! 496: switch (output->u.proto) {
! 497: case PPP_PROTO_LCP:
! 498: case PPP_PROTO_CHAP:
! 499: case PPP_PROTO_PAP:
! 500: case PPP_PROTO_MP:
! 501: ppp_fsm_input(link->lcp,
! 502: FSM_INPUT_RECD_PROTOREJ, output->u.proto);
! 503: break;
! 504: default:
! 505: if (link->bundle != NULL) {
! 506: ppp_bundle_protorej(link->bundle,
! 507: output->u.proto);
! 508: }
! 509: break;
! 510: }
! 511: break;
! 512: }
! 513: case FSM_OUTPUT_DEAD:
! 514: LOG(LOG_INFO, "LCP is dead: %s",
! 515: ppp_fsm_reason_str(output));
! 516: if (link->bundle != NULL)
! 517: ppp_link_unjoin(link);
! 518: ppp_fsm_free_output(output);
! 519: ppp_link_destroy(&link);
! 520: return;
! 521: }
! 522:
! 523: /* Free output */
! 524: ppp_fsm_free_output(output);
! 525: }
! 526: }
! 527:
! 528: /***********************************************************************
! 529: DEVICE EVENT HANDLER
! 530: ***********************************************************************/
! 531:
! 532: static void
! 533: ppp_link_device_event(void *arg)
! 534: {
! 535: struct ppp_link *const link = arg;
! 536: struct mesg_port *const outport = ppp_channel_get_outport(link->device);
! 537: struct ppp_channel_output *output;
! 538:
! 539: /* Handle channel events */
! 540: while ((output = mesg_port_get(outport, 0)) != NULL) {
! 541:
! 542: /* Check event */
! 543: switch (output->type) {
! 544: case PPP_CHANNEL_OUTPUT_UP:
! 545: LOG(LOG_INFO, "device layer is up");
! 546: ppp_fsm_input(link->lcp, FSM_INPUT_UP);
! 547: link->device_up = 1;
! 548: break;
! 549: case PPP_CHANNEL_OUTPUT_DOWN_FATAL:
! 550: case PPP_CHANNEL_OUTPUT_DOWN_NONFATAL:
! 551: LOG(LOG_INFO, "device layer is down: %s", output->info);
! 552: ppp_fsm_input(link->lcp,
! 553: output->type == PPP_CHANNEL_OUTPUT_DOWN_FATAL ?
! 554: FSM_INPUT_DOWN_FATAL : FSM_INPUT_DOWN_NONFATAL);
! 555: link->device_up = 0;
! 556: break;
! 557: }
! 558:
! 559: /* Free channel output */
! 560: ppp_channel_free_output(link->device, output);
! 561: }
! 562: }
! 563:
! 564: /***********************************************************************
! 565: PPP NODE OUTPUT HANDLER
! 566: ***********************************************************************/
! 567:
! 568: /*
! 569: * Handle data received from the node's bypass hook.
! 570: */
! 571: void
! 572: ppp_link_recv_bypass(struct ppp_link *link,
! 573: u_int16_t proto, u_char *data, size_t len)
! 574: {
! 575: LOG(LOG_DEBUG + 1, "rec'd proto 0x%04x %u bytes", proto, len);
! 576: switch (proto) {
! 577: case PPP_PROTO_LCP:
! 578: ppp_fsm_input(link->lcp, FSM_INPUT_DATA, data, len);
! 579: break;
! 580: case PPP_PROTO_PAP:
! 581: case PPP_PROTO_CHAP:
! 582: {
! 583: int i;
! 584:
! 585: for (i = 0; i < 2; i++) {
! 586: struct ppp_link_auth *const auth = &link->auth[i];
! 587:
! 588: if (auth->type == NULL
! 589: || auth->arg == NULL
! 590: || auth->proto != proto)
! 591: continue;
! 592: (*auth->type->input)(auth->arg, i, data, len);
! 593: }
! 594: break;
! 595: }
! 596: case PPP_PROTO_MP:
! 597: case PPP_PROTO_IPCP:
! 598: case PPP_PROTO_IP:
! 599: case PPP_PROTO_VJCOMP:
! 600: case PPP_PROTO_VJUNCOMP:
! 601: case PPP_PROTO_CCP:
! 602: case PPP_PROTO_COMPD:
! 603: break;
! 604: default: /* send a protocol-reject */
! 605: ppp_fsm_input(link->lcp,
! 606: FSM_INPUT_XMIT_PROTOREJ, proto, data, len);
! 607: break;
! 608: }
! 609: }
! 610:
! 611: static void
! 612: ppp_link_node_recv(void *arg, u_int link_num,
! 613: u_int16_t proto, u_char *data, size_t len)
! 614: {
! 615: struct ppp_link *const link = arg;
! 616:
! 617: assert(link_num == 0);
! 618: ppp_link_recv_bypass(link, proto, data, len);
! 619: }
! 620:
! 621: /***********************************************************************
! 622: AUTHORIZATION PHASE
! 623: ***********************************************************************/
! 624:
! 625: /*
! 626: * Begin link authorization.
! 627: */
! 628: static void
! 629: ppp_link_auth_start(struct ppp_link *link)
! 630: {
! 631: int i;
! 632:
! 633: /* Get auth types negotiated by LCP */
! 634: for (i = 0; i < 2; i++) {
! 635: link->auth[i].type = (link->lcp_req.auth[i] != PPP_AUTH_NONE) ?
! 636: ppp_auth_by_index(link->lcp_req.auth[i]) : NULL;
! 637: }
! 638: LOG(LOG_DEBUG, "auth required: self=%s peer=%s",
! 639: link->auth[PPP_PEER].type != NULL ?
! 640: link->auth[PPP_PEER].type->name : "None",
! 641: link->auth[PPP_SELF].type != NULL ?
! 642: link->auth[PPP_SELF].type->name : "None");
! 643:
! 644: /* If no auth required, skip it */
! 645: if (link->auth[PPP_SELF].type == NULL
! 646: && link->auth[PPP_PEER].type == NULL) {
! 647: ppp_link_join(link);
! 648: return;
! 649: }
! 650:
! 651: /* Start auth timer */
! 652: pevent_unregister(&link->auth_timer);
! 653: if (pevent_register(link->ev_ctx, &link->auth_timer, 0,
! 654: link->mutex, ppp_link_auth_timeout, link, PEVENT_TIME,
! 655: AUTH_TIMEOUT * 1000) == -1) {
! 656: LOG(LOG_ERR, "%s: %m", "pevent_register");
! 657: ppp_link_close(link);
! 658: return;
! 659: }
! 660:
! 661: /* Start authorization in each direction */
! 662: for (i = 0; i < 2; i++) {
! 663: struct ppp_link_auth *const auth = &link->auth[i];
! 664:
! 665: if (auth->type == NULL)
! 666: continue;
! 667: if ((auth->arg = (*auth->type->start)(link->ev_ctx, link,
! 668: link->mutex, i, &auth->proto, ppp_log_dup(link->log)))
! 669: == NULL) {
! 670: LOG(LOG_ERR, "failed to initialize authorization");
! 671: ppp_link_close(link);
! 672: return;
! 673: }
! 674: }
! 675: }
! 676:
! 677: /*
! 678: * Stop link authorization.
! 679: */
! 680: static void
! 681: ppp_link_auth_stop(struct ppp_link *link)
! 682: {
! 683: int i;
! 684:
! 685: /* Stop auth timer */
! 686: pevent_unregister(&link->auth_timer);
! 687:
! 688: /* Stop auth in both directions */
! 689: for (i = 0; i < 2; i++) {
! 690: struct ppp_link_auth *const auth = &link->auth[i];
! 691:
! 692: /* Kill any threads */
! 693: paction_cancel(&auth->action);
! 694:
! 695: /* Clean up authorization code */
! 696: if (auth->arg != NULL) {
! 697: (*auth->type->cancel)(auth->arg);
! 698: auth->arg = NULL;
! 699: }
! 700: }
! 701: }
! 702:
! 703: /*
! 704: * Authorization failed to happen within the alloted time.
! 705: */
! 706: static void
! 707: ppp_link_auth_timeout(void *arg)
! 708: {
! 709: struct ppp_link *const link = arg;
! 710:
! 711: pevent_unregister(&link->auth_timer);
! 712: LOG(LOG_ERR, "authorization timed out");
! 713: ppp_link_close(link);
! 714: }
! 715:
! 716: /***********************************************************************
! 717: AUTHORIZATION CALLBACKS
! 718: ***********************************************************************/
! 719:
! 720: #define AUTHINFO_MTYPE "ppp_link.authinfo"
! 721:
! 722: /* Authorization acquire/check state */
! 723: struct ppp_link_auth_info {
! 724: struct ppp_link *link; /* link being authorized */
! 725: struct ppp_auth_cred cred; /* auth credentials */
! 726: struct ppp_auth_resp resp; /* auth response */
! 727: ppp_link_auth_finish_t *finish;/* auth finish routine */
! 728: int rtn; /* return value from user */
! 729: int error; /* saved value of 'errno' */
! 730: };
! 731:
! 732: static paction_handler_t ppp_link_auth_acquire_main;
! 733: static paction_finish_t ppp_link_auth_acquire_finish;
! 734:
! 735: static paction_handler_t ppp_link_auth_check_main;
! 736: static paction_finish_t ppp_link_auth_check_finish;
! 737:
! 738: /*
! 739: * Acquire or check authorization credentials.
! 740: *
! 741: * This action is done in a separate thread.
! 742: */
! 743: int
! 744: ppp_link_authorize(struct ppp_link *link, int dir,
! 745: const struct ppp_auth_cred *cred, ppp_link_auth_finish_t *authfinish)
! 746: {
! 747: struct ppp_link_auth *const auth = &link->auth[dir];
! 748: struct ppp_link_auth_info *authinfo;
! 749: paction_handler_t *handler;
! 750: paction_finish_t *finish;
! 751:
! 752: /* Sanity check */
! 753: assert(auth->action == NULL);
! 754:
! 755: /* Set up for 'acquire' or 'check' */
! 756: if (dir == PPP_PEER) {
! 757: if (link->conf.auth.meth->acquire == NULL) {
! 758: LOG(LOG_ERR, "no method provided for %s credentials",
! 759: "acquiring");
! 760: return (-1);
! 761: }
! 762: handler = ppp_link_auth_acquire_main;
! 763: finish = ppp_link_auth_acquire_finish;
! 764: } else {
! 765: if (link->conf.auth.meth->check == NULL) {
! 766: LOG(LOG_ERR, "no method provided for %s credentials",
! 767: "checking");
! 768: return (-1);
! 769: }
! 770: handler = ppp_link_auth_check_main;
! 771: finish = ppp_link_auth_check_finish;
! 772: }
! 773:
! 774: /* Create auth info */
! 775: if ((authinfo = MALLOC(AUTHINFO_MTYPE, sizeof(*authinfo))) == NULL) {
! 776: LOG(LOG_ERR, "%s: %m", "malloc");
! 777: return (-1);
! 778: }
! 779: memset(authinfo, 0, sizeof(*authinfo));
! 780: authinfo->link = link;
! 781: authinfo->cred = *cred;
! 782: authinfo->finish = authfinish;
! 783:
! 784: /* Initiate authorization action */
! 785: if (paction_start(&auth->action, link->mutex,
! 786: handler, finish, authinfo) == -1) {
! 787: LOG(LOG_ERR, "%s: %m", "paction_start");
! 788: FREE(AUTHINFO_MTYPE, authinfo);
! 789: return (-1);
! 790: }
! 791:
! 792: /* Done */
! 793: return (0);
! 794: }
! 795:
! 796: /*
! 797: * Acquire authorization credentials.
! 798: *
! 799: * The mutex is NOT locked when this is called.
! 800: */
! 801: static void
! 802: ppp_link_auth_acquire_main(void *arg)
! 803: {
! 804: struct ppp_link_auth_info *const authinfo = arg;
! 805: struct ppp_link *const link = authinfo->link;
! 806:
! 807: /* Acquire credentials */
! 808: authinfo->rtn = (*link->conf.auth.meth->acquire)(link,
! 809: &authinfo->cred, &authinfo->resp);
! 810: authinfo->error = errno;
! 811: }
! 812:
! 813: /*
! 814: * Finish acquiring authorization credentials.
! 815: *
! 816: * The mutex is locked when this is called unless 'canceled' is true.
! 817: */
! 818: static void
! 819: ppp_link_auth_acquire_finish(void *arg, int canceled)
! 820: {
! 821: struct ppp_link_auth_info *const authinfo = arg;
! 822: struct ppp_link *const link = authinfo->link;
! 823: struct ppp_link_auth *const auth = &link->auth[PPP_PEER];
! 824:
! 825: /* If canceled, just clean up */
! 826: if (canceled)
! 827: goto done;
! 828:
! 829: /* If acquiring credentials failed, bail out here */
! 830: if (authinfo->rtn != 0) {
! 831: if (*authinfo->resp.errmsg == '\0') {
! 832: strlcpy(authinfo->resp.errmsg,
! 833: strerror(authinfo->error),
! 834: sizeof(authinfo->resp.errmsg));
! 835: }
! 836: LOG(LOG_WARNING, "failed to acquire credentials: %s",
! 837: auth->resp.errmsg);
! 838: ppp_link_auth_complete(link, PPP_PEER, NULL, NULL);
! 839: return;
! 840: }
! 841:
! 842: /* Save a copy of credentials */
! 843: auth->cred = authinfo->cred;
! 844: auth->resp = authinfo->resp;
! 845:
! 846: /* Report credentials back to authorization code */
! 847: (*authinfo->finish)(auth->arg, &authinfo->cred, &authinfo->resp);
! 848:
! 849: done:
! 850: /* Free authinfo */
! 851: FREE(AUTHINFO_MTYPE, authinfo);
! 852: }
! 853:
! 854: /*
! 855: * Check authorization credentials.
! 856: *
! 857: * The mutex is NOT locked when this is called.
! 858: */
! 859: static void
! 860: ppp_link_auth_check_main(void *arg)
! 861: {
! 862: struct ppp_link_auth_info *const authinfo = arg;
! 863: struct ppp_link *const link = authinfo->link;
! 864:
! 865: /* Check credentials */
! 866: authinfo->rtn = (*link->conf.auth.meth->check)(link,
! 867: &authinfo->cred, &authinfo->resp);
! 868: authinfo->error = errno;
! 869: }
! 870:
! 871: /*
! 872: * Finish checking authorization credentials.
! 873: *
! 874: * The mutex is locked when this is called.
! 875: */
! 876: static void
! 877: ppp_link_auth_check_finish(void *arg, int canceled)
! 878: {
! 879: struct ppp_link_auth_info *const authinfo = arg;
! 880: struct ppp_link *const link = authinfo->link;
! 881: struct ppp_link_auth *const auth = &link->auth[PPP_SELF];
! 882:
! 883: /* If canceled, just clean up */
! 884: if (canceled)
! 885: goto done;
! 886:
! 887: /* Save a copy of credentials */
! 888: auth->cred = authinfo->cred;
! 889: auth->resp = authinfo->resp;
! 890:
! 891: /* Fill in error message to indicate invalid credentials */
! 892: if (authinfo->rtn != 0) {
! 893: if (*authinfo->resp.errmsg == '\0') {
! 894: strlcpy(authinfo->resp.errmsg,
! 895: strerror(authinfo->error),
! 896: sizeof(authinfo->resp.errmsg));
! 897: }
! 898: }
! 899:
! 900: /* Report result back to authorization code */
! 901: (*authinfo->finish)(auth->arg, &authinfo->cred, &authinfo->resp);
! 902:
! 903: done:
! 904: /* Free authinfo */
! 905: FREE(AUTHINFO_MTYPE, authinfo);
! 906: }
! 907:
! 908: /*
! 909: * Determine if an authorization action is already in progress.
! 910: */
! 911: int
! 912: ppp_link_auth_in_progress(struct ppp_link *link, int dir)
! 913: {
! 914: struct ppp_link_auth *const auth = &link->auth[dir];
! 915:
! 916: return (auth->action != NULL);
! 917: }
! 918:
! 919: /*
! 920: * Finish link authorization (in one direction).
! 921: *
! 922: * A NULL 'cred' indicates failure.
! 923: */
! 924: void
! 925: ppp_link_auth_complete(struct ppp_link *link, int dir,
! 926: const struct ppp_auth_cred *cred, const union ppp_auth_mppe *mppe)
! 927: {
! 928: struct ppp_link_auth *const auth = &link->auth[dir];
! 929:
! 930: /* Sanity check */
! 931: assert(auth->arg != NULL);
! 932:
! 933: /* If auth failed, close link */
! 934: if (cred == NULL) {
! 935: LOG(LOG_NOTICE, "authorization %s peer failed",
! 936: dir == PPP_SELF ? "from" : "to");
! 937: ppp_link_close(link);
! 938: return;
! 939: }
! 940:
! 941: /* Save credentials and MPPE info */
! 942: auth->cred = *cred;
! 943: if (mppe != NULL)
! 944: auth->mppe = *mppe;
! 945:
! 946: /* Destroy auth object for this direction */
! 947: (*auth->type->cancel)(auth->arg);
! 948: auth->arg = NULL;
! 949:
! 950: /* If other direction still active, let it finish */
! 951: if (link->auth[!dir].arg != NULL)
! 952: return;
! 953:
! 954: /* Move to the 'UP' state */
! 955: ppp_link_auth_stop(link);
! 956: ppp_link_join(link);
! 957: }
! 958:
! 959: /*
! 960: * Get this link's authorization configuration.
! 961: */
! 962: const struct ppp_auth_config *
! 963: ppp_link_auth_get_config(struct ppp_link *link)
! 964: {
! 965: return (&link->conf.auth);
! 966: }
! 967:
! 968: /*
! 969: * Get this link's authorization type in one direction.
! 970: */
! 971: const struct ppp_auth_type *
! 972: ppp_link_get_auth(struct ppp_link *link, int dir)
! 973: {
! 974: dir &= 1;
! 975: return (link->auth[dir].type);
! 976: }
! 977:
! 978: /*
! 979: * Get this link's log
! 980: */
! 981: struct ppp_log *
! 982: ppp_link_get_log(struct ppp_link *link)
! 983: {
! 984: return (link->log);
! 985: }
! 986:
! 987: /***********************************************************************
! 988: BUNDLE OPERATIONS
! 989: ***********************************************************************/
! 990:
! 991: /*
! 992: * The link FSM has reached the OPENED state and authentication
! 993: * was successful, so join a bundle.
! 994: */
! 995: static void
! 996: ppp_link_join(struct ppp_link *link)
! 997: {
! 998: assert(link->bundle == NULL);
! 999: if ((link->bundle = ppp_engine_join(link->engine,
! 1000: link, &link->node, &link->link_num)) == NULL) {
! 1001: ppp_link_close(link);
! 1002: return;
! 1003: }
! 1004: link->state = PPP_LINK_UP;
! 1005: }
! 1006:
! 1007: /*
! 1008: * Link has left the OPENED state, so leave bundle (if any).
! 1009: */
! 1010: static void
! 1011: ppp_link_unjoin(struct ppp_link *link)
! 1012: {
! 1013: ppp_bundle_unjoin(&link->bundle, link); /* ok if bundle null */
! 1014: }
! 1015:
! 1016: /***********************************************************************
! 1017: INTERNAL FUNCTIONS
! 1018: ***********************************************************************/
! 1019:
! 1020: /*
! 1021: * Acquire an ng_ppp(4) node for this link to use.
! 1022: */
! 1023: static int
! 1024: ppp_link_get_node(struct ppp_link *link)
! 1025: {
! 1026: const char *node;
! 1027: const char *hook;
! 1028:
! 1029: /* Sanity check */
! 1030: if (link->node != NULL)
! 1031: return (0);
! 1032:
! 1033: /* Get new node */
! 1034: if ((link->node = ppp_node_create(link->ev_ctx,
! 1035: link->mutex, ppp_log_dup(link->log))) == NULL) {
! 1036: LOG(LOG_ERR, "%s: %m", "creating ppp node");
! 1037: return (-1);
! 1038: }
! 1039:
! 1040: /* Connect device to node */
! 1041: if ((node = ppp_channel_get_node(link->device)) == NULL
! 1042: || (hook = ppp_channel_get_hook(link->device)) == NULL) {
! 1043: LOG(LOG_ERR, "channel is not a device");
! 1044: ppp_node_destroy(&link->node);
! 1045: return (-1);
! 1046: }
! 1047: if (ppp_node_connect(link->node, 0, node, hook) == -1) {
! 1048: LOG(LOG_ERR, "%s: %m", "connecting device to node");
! 1049: ppp_node_destroy(&link->node);
! 1050: return (-1);
! 1051: }
! 1052:
! 1053: /* Receive all node bypass packets */
! 1054: ppp_node_set_recv(link->node, ppp_link_node_recv, link);
! 1055:
! 1056: /* Done */
! 1057: return (0);
! 1058: }
! 1059:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>