/*
* link.c
*
* Written by Archie Cobbs <archie@freebsd.org>
* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1