/* * link.c * * Written by Archie Cobbs * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved. * See ``COPYRIGHT.whistle'' */ #include "ppp.h" #include "link.h" #include "msg.h" #include "lcp.h" #include "phys.h" #include "command.h" #include "input.h" #include "ngfunc.h" /* * DEFINITIONS */ /* Set menu options */ enum { SET_DEVTYPE, SET_BANDWIDTH, SET_LATENCY, SET_ACCMAP, SET_MRU, SET_MTU, SET_FSM_RETRY, SET_MAX_RETRY, SET_KEEPALIVE, SET_IDENT, SET_ACCEPT, SET_DENY, SET_ENABLE, SET_DISABLE, SET_YES, SET_NO, }; /* * INTERNAL FUNCTIONS */ static int LinkSetCommand(int ac, char *av[], void *arg); static void LinkMsg(int type, void *cookie); /* * GLOBAL VARIABLES */ const struct cmdtab LinkSetCmds[] = { { "bandwidth bps", "Link bandwidth", LinkSetCommand, NULL, (void *) SET_BANDWIDTH }, { "type type", "Device type", LinkSetCommand, NULL, (void *) SET_DEVTYPE }, { "latency microsecs", "Link latency", LinkSetCommand, NULL, (void *) SET_LATENCY }, { "accmap hex-value", "Accmap value", LinkSetCommand, NULL, (void *) SET_ACCMAP }, { "mru value", "Link MRU value", LinkSetCommand, NULL, (void *) SET_MRU }, { "mtu value", "Link MTU value", LinkSetCommand, NULL, (void *) SET_MTU }, { "fsm-timeout seconds", "FSM retry timeout", LinkSetCommand, NULL, (void *) SET_FSM_RETRY }, { "max-redial num", "Max connect attempts", LinkSetCommand, NULL, (void *) SET_MAX_RETRY }, { "keep-alive secs max", "LCP echo keep-alives", LinkSetCommand, NULL, (void *) SET_KEEPALIVE }, { "ident ident-string", "LCP ident string", LinkSetCommand, NULL, (void *) SET_IDENT }, { "accept [opt ...]", "Accept option", LinkSetCommand, NULL, (void *) SET_ACCEPT }, { "deny [opt ...]", "Deny option", LinkSetCommand, NULL, (void *) SET_DENY }, { "enable [opt ...]", "Enable option", LinkSetCommand, NULL, (void *) SET_ENABLE }, { "disable [opt ...]", "Disable option", LinkSetCommand, NULL, (void *) SET_DISABLE }, { "yes [opt ...]", "Enable and accept option", LinkSetCommand, NULL, (void *) SET_YES }, { "no [opt ...]", "Disable and deny option", LinkSetCommand, NULL, (void *) SET_NO }, { NULL }, }; /* * INTERNAL VARIABLES */ static struct confinfo gConfList[] = { { 1, LINK_CONF_PAP, "pap" }, { 1, LINK_CONF_CHAPMD5, "chap-md5" }, { 1, LINK_CONF_CHAPMSv1, "chap-msv1" }, { 1, LINK_CONF_CHAPMSv2, "chap-msv2" }, { 1, LINK_CONF_ACFCOMP, "acfcomp" }, { 1, LINK_CONF_PROTOCOMP, "protocomp" }, { 0, LINK_CONF_MAGICNUM, "magicnum" }, { 0, LINK_CONF_PASSIVE, "passive" }, { 0, LINK_CONF_CHECK_MAGIC, "check-magic" }, { 0, LINK_CONF_NO_ORIG_AUTH, "no-orig-auth" }, { 0, LINK_CONF_CALLBACK, "callback" }, { 0, 0, NULL }, }; /* * LinkOpen() */ void LinkOpen(Link l) { MsgSend(l->msgs, MSG_OPEN, NULL); } /* * LinkClose() */ void LinkClose(Link l) { MsgSend(l->msgs, MSG_CLOSE, NULL); } /* * LinkUp() */ void LinkUp(Link l) { MsgSend(l->msgs, MSG_UP, NULL); } /* * LinkDown() */ void LinkDown(Link l) { MsgSend(l->msgs, MSG_DOWN, NULL); } /* * LinkMsg() * * Deal with incoming message to this link */ static void LinkMsg(int type, void *arg) { Log(LG_LINK, ("[%s] link: %s event", lnk->name, MsgName(type))); switch (type) { case MSG_OPEN: lnk->num_redial = 0; lnk->radius.authentic = 0; LcpOpen(); break; case MSG_CLOSE: LcpClose(); break; case MSG_UP: lnk->originate = PhysGetOriginate(); Log(LG_LINK, ("[%s] link: origination is %s", lnk->name, LINK_ORIGINATION(lnk->originate))); LcpUp(); break; case MSG_DOWN: LcpDown(); /* reset Link-stats */ LinkResetStats(); if (OPEN_STATE(lnk->lcp.fsm.state)) { if (lnk->conf.max_redial == -1) { SetStatus(ADLG_WAN_WAIT_FOR_DEMAND, STR_READY_TO_DIAL); LcpClose(); BundLinkGaveUp(); } else if (!lnk->conf.max_redial || lnk->num_redial < lnk->conf.max_redial) { lnk->num_redial++; RecordLinkUpDownReason(lnk, 1, STR_REDIAL, NULL); PhysOpen(); /* Try again */ } else { Log(LG_LINK, ("[%s] giving up after %d connection attempts", lnk->name, lnk->num_redial)); SetStatus(ADLG_WAN_WAIT_FOR_DEMAND, STR_READY_TO_DIAL); LcpClose(); BundLinkGaveUp(); } } break; } } /* * LinkNew() * * Allocate a new link for the specified device, then * read in any device-specific commands from ppp.links. */ Link LinkNew(char *name) { int k; /* Check if name is already used */ for (k = 0; k < gNumLinks; k++) { if (gLinks[k] && !strcmp(gLinks[k]->name, name)) { Log(LG_ERR, ("mpd: link \"%s\" already defined in bundle \"%s\"", name, gLinks[k]->bund->name)); return(NULL); } } /* Find a free link pointer */ for (k = 0; k < gNumLinks && gLinks[k] != NULL; k++); if (k == gNumLinks) /* add a new link pointer */ LengthenArray(&gLinks, sizeof(*gLinks), &gNumLinks, MB_BUND); /* Create and initialize new link */ lnk = Malloc(MB_BUND, sizeof(*lnk)); gLinks[k] = lnk; snprintf(lnk->name, sizeof(lnk->name), "%s", name); lnk->msgs = MsgRegister(LinkMsg, LINK_PRIO); /* Initialize link configuration with defaults */ lnk->conf.mru = LCP_DEFAULT_MRU; lnk->conf.mtu = LCP_DEFAULT_MRU; lnk->conf.accmap = 0x000a0000; lnk->conf.retry_timeout = LINK_DEFAULT_RETRY; lnk->bandwidth = LINK_DEFAULT_BANDWIDTH; lnk->latency = LINK_DEFAULT_LATENCY; Disable(&lnk->conf.options, LINK_CONF_CHAPMD5); Accept(&lnk->conf.options, LINK_CONF_CHAPMD5); Disable(&lnk->conf.options, LINK_CONF_CHAPMSv1); Deny(&lnk->conf.options, LINK_CONF_CHAPMSv1); Disable(&lnk->conf.options, LINK_CONF_CHAPMSv2); Accept(&lnk->conf.options, LINK_CONF_CHAPMSv2); Disable(&lnk->conf.options, LINK_CONF_PAP); Accept(&lnk->conf.options, LINK_CONF_PAP); Enable(&lnk->conf.options, LINK_CONF_ACFCOMP); Accept(&lnk->conf.options, LINK_CONF_ACFCOMP); Enable(&lnk->conf.options, LINK_CONF_PROTOCOMP); Accept(&lnk->conf.options, LINK_CONF_PROTOCOMP); Enable(&lnk->conf.options, LINK_CONF_MAGICNUM); Disable(&lnk->conf.options, LINK_CONF_PASSIVE); Enable(&lnk->conf.options, LINK_CONF_CHECK_MAGIC); /* Initialize link layer stuff */ lnk->phys = PhysInit(); LcpInit(); /* Read special configuration for link, if any */ (void) ReadFile(LINKS_FILE, name, DoCommand); /* Hang out and be a link */ return(lnk); } /* * LinkShow() */ int LinkCommand(int ac, char *av[], void *arg) { int k; if (ac != 1) return(-1); k=gNumLinks; if ((sscanf(av[0],"[%x]",&k)!=1)||(k<0)||(k>=gNumLinks)) { /* Find link */ for (k = 0; k < gNumLinks && (!gLinks[k] || strcmp(gLinks[k]->name, av[0])); k++); }; if (k == gNumLinks) { printf("Link \"%s\" is not defined\n", av[0]); return(0); } /* Change default link and bundle */ lnk = gLinks[k]; bund = lnk->bund; return(0); } /* * LinkStat() */ int LinkStat(int ac, char *av[], void *arg) { printf("Link %s:\n", lnk->name); printf("Configuration\n"); printf("\tMRU : %d bytes\n", lnk->conf.mru); printf("\tCtrl char map : 0x%08x bytes\n", lnk->conf.accmap); printf("\tRetry timeout : %d seconds\n", lnk->conf.retry_timeout); printf("\tMax redial : %d connect attempts\n", lnk->conf.max_redial); printf("\tBandwidth : %d bits/sec\n", lnk->bandwidth); printf("\tLatency : %d usec\n", lnk->latency); printf("\tKeep-alive : "); if (lnk->lcp.fsm.conf.echo_int == 0) printf("disabled\n"); else printf("every %d secs, timeout %d\n", lnk->lcp.fsm.conf.echo_int, lnk->lcp.fsm.conf.echo_max); printf("\tIdent string : \"%s\"\n", lnk->conf.ident ? lnk->conf.ident : ""); printf("Link level options\n"); OptStat(&lnk->conf.options, gConfList); LinkUpdateStats(); printf("Traffic stats:\n"); printf("\tOctets input : %llu\n", lnk->stats.recvOctets); printf("\tFrames input : %llu\n", lnk->stats.recvFrames); printf("\tOctets output : %llu\n", lnk->stats.xmitOctets); printf("\tFrames output : %llu\n", lnk->stats.xmitFrames); printf("\tBad protocols : %llu\n", lnk->stats.badProtos); #if NGM_PPP_COOKIE >= 940897794 printf("\tRunts : %llu\n", lnk->stats.runts); #endif printf("\tDup fragments : %llu\n", lnk->stats.dupFragments); #if NGM_PPP_COOKIE >= 940897794 printf("\tDrop fragments : %llu\n", lnk->stats.dropFragments); #endif printf("Device specific info:\n"); PhysStat(0, NULL, NULL); return(0); } /* * LinkUpdateStats() */ void LinkUpdateStats(void) { struct ng_ppp_link_stat stats; if (NgFuncGetStats(lnk->bundleIndex, FALSE, &stats) != -1) { lnk->stats.xmitFrames += abs(stats.xmitFrames - lnk->stats.oldStats.xmitFrames); lnk->stats.xmitOctets += abs(stats.xmitOctets - lnk->stats.oldStats.xmitOctets); lnk->stats.recvFrames += abs(stats.recvFrames - lnk->stats.oldStats.recvFrames); lnk->stats.recvOctets += abs(stats.recvOctets - lnk->stats.oldStats.recvOctets); lnk->stats.badProtos += abs(stats.badProtos - lnk->stats.oldStats.badProtos); #if NGM_PPP_COOKIE >= 940897794 lnk->stats.runts += abs(stats.runts - lnk->stats.oldStats.runts); #endif lnk->stats.dupFragments += abs(stats.dupFragments - lnk->stats.oldStats.dupFragments); #if NGM_PPP_COOKIE >= 940897794 lnk->stats.dropFragments += abs(stats.dropFragments - lnk->stats.oldStats.dropFragments); #endif } lnk->stats.oldStats = stats; } /* * LinkUpdateStatsTimer() */ void LinkUpdateStatsTimer(void *cookie) { TimerStop(&lnk->stats.updateTimer); LinkUpdateStats(); TimerStart(&lnk->stats.updateTimer); } /* * LinkResetStats() */ void LinkResetStats(void) { NgFuncGetStats(lnk->bundleIndex, TRUE, NULL); memset(&lnk->stats, 0, sizeof(struct linkstats)); } /* * LinkSetCommand() */ static int LinkSetCommand(int ac, char *av[], void *arg) { int val, nac = 0; const char *name; char *nav[ac]; const char *av2[] = { "chap-md5", "chap-msv1", "chap-msv2" }; if (ac == 0) return(-1); /* make "chap" as an alias for all chap-variants, this should keep BC */ switch ((intptr_t)arg) { case SET_ACCEPT: case SET_DENY: case SET_ENABLE: case SET_DISABLE: case SET_YES: case SET_NO: { int i = 0; for ( ; i < ac; i++) { if (strcasecmp(av[i], "chap") == 0) { LinkSetCommand(3, (char **)av2, arg); } else { nav[nac++] = av[i]; } } av = nav; ac = nac; break; } } switch ((intptr_t)arg) { case SET_BANDWIDTH: val = atoi(*av); if (val <= 0) Log(LG_ERR, ("Bandwidth must be positive")); else lnk->bandwidth = val; break; case SET_LATENCY: val = atoi(*av); lnk->latency = val; break; case SET_DEVTYPE: PhysSetDeviceType(*av); break; case SET_MRU: case SET_MTU: val = atoi(*av); name = ((intptr_t)arg == SET_MTU) ? "MTU" : "MRU"; if (!lnk->phys->type) Log(LG_ERR, ("[%s] this link has no type set", lnk->name)); else if (val < LCP_MIN_MRU) Log(LG_ERR, ("[%s] the min %s is %d", lnk->name, name, LCP_MIN_MRU)); else if (val > lnk->phys->type->mru) Log(LG_ERR, ("[%s] the max %s on type \"%s\" links is %d", lnk->name, name, lnk->phys->type->name, lnk->phys->type->mru)); else if ((intptr_t)arg == SET_MTU) lnk->conf.mtu = val; else lnk->conf.mru = val; break; case SET_FSM_RETRY: lnk->conf.retry_timeout = atoi(*av); if (lnk->conf.retry_timeout < 1 || lnk->conf.retry_timeout > 10) lnk->conf.retry_timeout = LINK_DEFAULT_RETRY; break; case SET_MAX_RETRY: lnk->conf.max_redial = atoi(*av); break; case SET_ACCMAP: sscanf(*av, "%x", &val); lnk->conf.accmap = val; break; case SET_KEEPALIVE: if (ac != 2) return(-1); lnk->lcp.fsm.conf.echo_int = atoi(av[0]); lnk->lcp.fsm.conf.echo_max = atoi(av[1]); break; case SET_IDENT: if (ac != 1) return(-1); if (lnk->conf.ident != NULL) { Freee(lnk->conf.ident); lnk->conf.ident = NULL; } if (*av[0] != '\0') strcpy(lnk->conf.ident = Malloc(MB_FSM, strlen(av[0]) + 1), av[0]); break; case SET_ACCEPT: AcceptCommand(ac, av, &lnk->conf.options, gConfList); break; case SET_DENY: DenyCommand(ac, av, &lnk->conf.options, gConfList); break; case SET_ENABLE: EnableCommand(ac, av, &lnk->conf.options, gConfList); break; case SET_DISABLE: DisableCommand(ac, av, &lnk->conf.options, gConfList); break; case SET_YES: YesCommand(ac, av, &lnk->conf.options, gConfList); break; case SET_NO: NoCommand(ac, av, &lnk->conf.options, gConfList); break; default: assert(0); } return(0); }