/*
* phys.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 "msg.h"
#include "link.h"
#include "devices.h"
#include "util.h"
/*
* The physical layer has four states: DOWN, OPENING, CLOSING, and UP.
* Each device type must implement this set of standard methods:
*
* init Called once for each device to initialize it.
* open Called in the DOWN state to initiate connection.
* Device should eventually call PhysUp() or PhysDown().
* close Called in the OPENING or UP states.
* Device should eventually call PhysDown().
* update Called when LCP reaches the UP state. Device should
* update its configuration based on LCP negotiated
* settings, if necessary.
* showstat Display device statistics.
*
* The device should generate UP and DOWN events in response to OPEN
* and CLOSE events. If the device goes down suddenly after being OPEN,
* the close method will not be explicitly called to clean up.
*
* All device types must support MRU's of at least 1500.
*
* Each device is responsible for connecting the appropriate netgraph
* node to the PPP node when the link comes up, and disconnecting it
* when the link goes down (or is closed). The device should NOT send
* any NGM_PPP_SET_CONFIG messsages to the ppp node.
*/
/*
* DEFINITIONS
*/
/* Set menu options */
enum {
SET_DEVTYPE,
SET_ACCEPT,
SET_DENY,
SET_ENABLE,
SET_DISABLE,
SET_YES,
SET_NO,
};
/*
* INTERNAL FUNCTIONS
*/
static void PhysOpenTimeout(void *arg);
static void PhysMsg(int type, void *arg);
static int PhysSetCommand(Context ctx, int ac, char *av[], void *arg);
static PhysInfo PhysFind(char *name);
/*
* GLOBAL VARIABLES
*/
const struct cmdtab PhysSetCmds[] = {
{ "type type", "Device type",
PhysSetCommand, NULL, (void *) SET_DEVTYPE },
{ NULL },
};
const PhysType gPhysTypes[] = {
#define _WANT_DEVICE_TYPES
#include "devices.h"
NULL,
};
const char *gPhysStateNames[] = {
"DOWN",
"CONNECTING",
"READY",
"UP",
};
/*
* PhysInit()
*
* Initialize physical layer state. Note that
* the device type remains unspecified at this point.
*/
PhysInfo
PhysInit(char *name, Link l, Rep r)
{
PhysInfo p;
struct context ctx;
int k;
/* See if bundle name already taken */
if ((p = PhysFind(name)) != NULL) {
Log(LG_ERR, ("phys \"%s\" already exists", name));
return NULL;
}
p = Malloc(MB_PHYS, sizeof(*p));
strlcpy(p->name, name, sizeof(p->name));
p->state = PHYS_STATE_DOWN;
p->msgs = MsgRegister(PhysMsg);
p->link = l;
p->rep = r;
/* Find a free link pointer */
for (k = 0; k < gNumPhyses && gPhyses[k] != NULL; k++);
if (k == gNumPhyses) /* add a new link pointer */
LengthenArray(&gPhyses, sizeof(*gPhyses), &gNumPhyses, MB_PHYS);
p->id = k;
gPhyses[k] = p;
memset(&ctx, 0, sizeof(ctx));
ctx.lnk = l;
ctx.phys = p;
ctx.rep = NULL;
ctx.bund = NULL;
/* Read special configuration for link, if any */
(void) ReadFile(LINKS_FILE, name, DoCommand, &ctx);
return(p);
}
/*
* PhysOpenCmd()
*/
void
PhysOpenCmd(Context ctx)
{
PhysOpen(ctx->phys);
}
/*
* PhysOpen()
*/
void
PhysOpen(PhysInfo p)
{
MsgSend(p->msgs, MSG_OPEN, p);
}
/*
* PhysCloseCmd()
*/
void
PhysCloseCmd(Context ctx)
{
PhysClose(ctx->phys);
}
/*
* PhysClose()
*/
void
PhysClose(PhysInfo p)
{
MsgSend(p->msgs, MSG_CLOSE, p);
}
/*
* PhysUp()
*/
void
PhysUp(PhysInfo p)
{
Log(LG_PHYS2, ("[%s] device: UP event", p->name));
if (p->link) {
LinkUp(p->link);
} else if (p->rep) {
RepUp(p);
}
}
/*
* PhysDown()
*/
void
PhysDown(PhysInfo p, const char *reason, const char *details, ...)
{
Log(LG_PHYS2, ("[%s] device: DOWN event", p->name));
p->lastClose = time(NULL);
if (p->link) {
if (details) {
va_list args;
char buf[256];
va_start(args, details);
vsnprintf(buf, sizeof(buf), details, args);
va_end(args);
RecordLinkUpDownReason(NULL, p->link, 0, reason, buf);
} else {
RecordLinkUpDownReason(NULL, p->link, 0, reason, NULL);
}
p->link->upReasonValid=0;
LinkDown(p->link);
} else if (p->rep) {
RepDown(p);
}
}
/*
* PhysIncoming()
*/
void
PhysIncoming(PhysInfo p)
{
if (p->link) {
RecordLinkUpDownReason(NULL, p->link, 1, STR_INCOMING_CALL, NULL);
BundOpenLink(p->link);
} else if (p->rep) {
RepIncoming(p);
}
}
/*
* PhysSetAccm()
*/
int
PhysSetAccm(PhysInfo p, uint32_t xmit, u_int32_t recv)
{
if (p->type && p->type->setaccm)
return (*p->type->setaccm)(p, xmit, recv);
else
return (0);
}
/*
* PhysGetUpperHook()
*/
int
PhysGetUpperHook(PhysInfo p, char *path, char *hook)
{
if (p->link && p->link->bund) {
snprintf(path, NG_PATHLEN, "[%lx]:", (u_long)p->link->bund->nodeID);
snprintf(hook, NG_HOOKLEN, "%s%d",
NG_PPP_HOOK_LINK_PREFIX, p->link->bundleIndex);
return 1;
} else if (p->rep) {
return RepGetHook(p, path, hook);
}
return 0;
}
/*
* PhysGetOriginate()
*
* This returns one of LINK_ORIGINATE_{UNKNOWN, LOCAL, REMOTE}
*/
int
PhysGetOriginate(PhysInfo p)
{
PhysType const pt = p->type;
return((pt && pt->originate) ? (*pt->originate)(p) : LINK_ORIGINATE_UNKNOWN);
}
/*
* PhysIsSync()
*
* This returns 1 if link is synchronous
*/
int
PhysIsSync(PhysInfo p)
{
PhysType const pt = p->type;
return((pt && pt->issync) ? (*pt->issync)(p) : 0);
}
/*
* PhysSetCalledNum()
*/
int
PhysSetCallingNum(PhysInfo p, char *buf)
{
PhysType const pt = p->type;
if (pt && pt->setcallingnum)
return ((*pt->setcallingnum)(p, buf));
else
return (0);
}
/*
* PhysSetCalledNum()
*/
int
PhysSetCalledNum(PhysInfo p, char *buf)
{
PhysType const pt = p->type;
if (pt && pt->setcallednum)
return ((*pt->setcallednum)(p, buf));
else
return (0);
}
/*
* PhysGetPeerAddr()
*/
int
PhysGetPeerAddr(PhysInfo p, char *buf, int buf_len)
{
PhysType const pt = p->type;
buf[0] = 0;
if (pt && pt->peeraddr)
return ((*pt->peeraddr)(p, buf, buf_len));
else
return (0);
}
/*
* PhysGetPeerPort()
*/
int
PhysGetPeerPort(PhysInfo p, char *buf, int buf_len)
{
PhysType const pt = p->type;
buf[0] = 0;
if (pt && pt->peerport)
return ((*pt->peerport)(p, buf, buf_len));
else
return (0);
}
/*
* PhysGetCalledNum()
*/
int
PhysGetCallingNum(PhysInfo p, char *buf, int buf_len)
{
PhysType const pt = p->type;
buf[0] = 0;
if (pt && pt->callingnum)
return ((*pt->callingnum)(p, buf, buf_len));
else
return (0);
}
/*
* PhysGetCalledNum()
*/
int
PhysGetCalledNum(PhysInfo p, char *buf, int buf_len)
{
PhysType const pt = p->type;
buf[0] = 0;
if (pt && pt->callednum)
return ((*pt->callednum)(p, buf, buf_len));
else
return (0);
}
/*
* PhysShutdown()
*/
void
PhysShutdown(PhysInfo p)
{
PhysType const pt = p->type;
int k;
if (pt && pt->shutdown)
(*pt->shutdown)(p);
for (k = 0;
k < gNumPhyses && gPhyses[k] != p;
k++);
if (k < gNumPhyses)
gPhyses[k] = NULL;
Freee(MB_PHYS, p);
}
/*
* PhysSetDeviceType()
*/
void
PhysSetDeviceType(PhysInfo p, char *typename)
{
PhysType pt;
int k;
/* Make sure device type not already set */
if (p->type) {
Log(LG_ERR, ("[%s] device type already set to %s",
p->name, p->type->name));
return;
}
/* Locate type */
for (k = 0; (pt = gPhysTypes[k]); k++) {
if (!strcmp(pt->name, typename))
break;
}
if (pt == NULL) {
Log(LG_ERR, ("[%s] device type \"%s\" unknown", p->name, typename));
return;
}
p->type = pt;
/* Initialize type specific stuff */
if ((p->type->init)(p) < 0) {
Log(LG_ERR, ("[%s] type \"%s\" initialization failed",
p->name, p->type->name));
p->type = NULL;
return;
}
}
/*
* PhysMsg()
*/
static void
PhysMsg(int type, void *arg)
{
PhysInfo const p = (PhysInfo)arg;
time_t const now = time(NULL);
Log(LG_PHYS2, ("[%s] device: %s event",
p->name, MsgName(type)));
if (!p->type) {
Log(LG_ERR, ("[%s] this link has no type set", p->name));
return;
}
switch (type) {
case MSG_OPEN:
if (p->link)
p->link->downReasonValid=0;
if (now - p->lastClose < p->type->minReopenDelay) {
if (TimerRemain(&p->openTimer) < 0) {
int delay = p->type->minReopenDelay - (now - p->lastClose);
if ((random() ^ gPid ^ time(NULL)) & 1)
delay++;
Log(LG_PHYS, ("[%s] pausing %d seconds before open",
p->name, delay));
TimerStop(&p->openTimer);
TimerInit(&p->openTimer, "PhysOpen",
delay * SECONDS, PhysOpenTimeout, p);
TimerStart(&p->openTimer);
}
break;
}
TimerStop(&p->openTimer);
(*p->type->open)(p);
break;
case MSG_CLOSE:
TimerStop(&p->openTimer);
(*p->type->close)(p);
break;
default:
assert(FALSE);
}
}
/*
* PhysOpenTimeout()
*/
static void
PhysOpenTimeout(void *arg)
{
PhysInfo const p = (PhysInfo)arg;
TimerStop(&p->openTimer);
PhysOpen(p);
}
/*
* PhysCommand()
*/
int
PhysCommand(Context ctx, int ac, char *av[], void *arg)
{
int k;
PhysInfo p;
switch (ac) {
case 0:
Printf("Defined phys items:\r\n");
for (k = 0; k < gNumPhyses; k++) {
if ((p = gPhyses[k]) != NULL) {
if (p->link && p->link->bund)
Printf("\t\"%s\" -> link \"%s\" -> bundle \"%s\"\r\n",
p->name, p->link->name, p->link->bund->name);
else if (p->rep)
Printf("\t\"%s\" -> repeater \"%s\"\r\n", p->name, p->rep->name);
else
Printf("\t\"%s\" -> unknown\r\n", p->name);
}
}
break;
case 1:
if ((p = PhysFind(av[0])) == NULL) {
Printf("Phys \"%s\" is not defined\r\n", av[0]);
return(0);
}
/* Change default link and bundle */
ctx->phys = p;
ctx->lnk = p->link;
if (p->link) {
ctx->bund = ctx->lnk->bund;
} else {
ctx->bund = NULL;
}
ctx->rep = p->rep;
break;
default:
return(-1);
}
return(0);
}
/*
* PhysFind()
*
* Find a phys structure
*/
static PhysInfo
PhysFind(char *name)
{
int k;
for (k = 0;
k < gNumPhyses && strcmp(gPhyses[k]->name, name);
k++);
return((k < gNumPhyses) ? gPhyses[k] : NULL);
}
/*
* PhysStat()
*/
int
PhysStat(Context ctx, int ac, char *av[], void *arg)
{
PhysInfo const p = ctx->phys;
Printf("\tType : %s\r\n", p->type->name);
if (p->type->showstat)
(*p->type->showstat)(ctx);
return 0;
}
/*
* PhysSetCommand()
*/
static int
PhysSetCommand(Context ctx, int ac, char *av[], void *arg)
{
if (ac == 0)
return(-1);
switch ((intptr_t)arg) {
case SET_DEVTYPE:
PhysSetDeviceType(ctx->phys, *av);
break;
/*
case SET_ACCEPT:
AcceptCommand(ac, av, &phys->options, gConfList);
break;
case SET_DENY:
DenyCommand(ac, av, &phys->options, gConfList);
break;
case SET_ENABLE:
EnableCommand(ac, av, &phys->options, gConfList);
break;
case SET_DISABLE:
DisableCommand(ac, av, &phys->options, gConfList);
break;
case SET_YES:
YesCommand(ac, av, &phys->options, gConfList);
break;
case SET_NO:
NoCommand(ac, av, &phys->options, gConfList);
break;
*/
default:
assert(0);
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1