File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / phys.c
Revision 1.1.1.3.2.1: download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:08:01 2023 UTC (15 months ago) by misho
Branches: v5_9p16
Diff to: branchpoint 1.1.1.3: preferred, unified
Version 5.9p16


/*
 * 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"

#include <netgraph/ng_tee.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.
 */

/*
 * INTERNAL FUNCTIONS
 */

  static void	PhysMsg(int type, void *arg);

/*
 * GLOBAL VARIABLES
 */

  const struct phystype *gPhysTypes[] = {
#define _WANT_DEVICE_TYPES
#include "devices.h"
    NULL,
  };

  const char *gPhysStateNames[] = {
    "DOWN",
    "CONNECTING",
    "READY",
    "UP",
  };

int
PhysInit(Link l)
{
    MsgRegister(&l->pmsgs, PhysMsg);

    /* Initialize type specific stuff */
    if ((l->type->init)(l) < 0) {
	Log(LG_ERR, ("[%s] type \"%s\" initialization failed",
    	    l->name, l->type->name));
	l->type = NULL;
	return (0);
    }

    return (0);
}

/*
 * PhysInst()
 */

int
PhysInst(Link l, Link lt)
{
    return ((l->type->inst)(l, lt));
}

/*
 * PhysOpenCmd()
 */

int
PhysOpenCmd(Context ctx)
{
    if (ctx->lnk->tmpl)
	Error("impossible to open template");
    RecordLinkUpDownReason(NULL, ctx->lnk, 1, STR_MANUALLY, NULL);
    PhysOpen(ctx->lnk);
    return (0);
}

/*
 * PhysOpen()
 */

void
PhysOpen(Link l)
{
    REF(l);
    MsgSend(&l->pmsgs, MSG_OPEN, l);
}

/*
 * PhysCloseCmd()
 */

int
PhysCloseCmd(Context ctx)
{
    if (ctx->lnk->tmpl)
	Error("impossible to close template");
    RecordLinkUpDownReason(NULL, ctx->lnk, 0, STR_MANUALLY, NULL);
    PhysClose(ctx->lnk);
    return (0);
}

/*
 * PhysClose()
 */

void
PhysClose(Link l)
{
    REF(l);
    MsgSend(&l->pmsgs, MSG_CLOSE, l);
}

/*
 * PhysUp()
 */

void
PhysUp(Link l)
{
    Log(LG_PHYS2, ("[%s] device: UP event", l->name));
    l->last_up = time(NULL);
    if (!l->rep) {
	LinkUp(l);
    } else {
	RepUp(l);
    }
}

/*
 * PhysDown()
 */

void
PhysDown(Link l, const char *reason, const char *details)
{
    Log(LG_PHYS2, ("[%s] device: DOWN event", l->name));
    if (!l->rep) {
	RecordLinkUpDownReason(NULL, l, 0, reason, details);
	l->upReasonValid=0;
	LinkDown(l);
	LinkShutdownCheck(l, l->lcp.fsm.state);

    } else {
	RepDown(l);
    }
}

/*
 * PhysIncoming()
 */

void
PhysIncoming(Link l)
{
    const char	*rept;
    
    rept = LinkMatchAction(l, 1, NULL);
    if (rept) {
	if (strcmp(rept,"##DROP##") == 0) {
	    /* Action told we must drop this connection */
	    Log(LG_PHYS, ("[%s] Drop connection", l->name));
	    PhysClose(l);
	    return;
	}
	if (RepCreate(l, rept)) {
	    Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));
	    PhysClose(l);
	    return;
	}
    }

    if (!l->rep) {
	RecordLinkUpDownReason(NULL, l, 1, STR_INCOMING_CALL, NULL);
	LinkOpen(l);
    } else {
        RepIncoming(l);
    }
}

/*
 * PhysSetAccm()
 */

int
PhysSetAccm(Link l, uint32_t xmit, u_int32_t recv)
{
    if (l->type && l->type->setaccm)
	return (*l->type->setaccm)(l, xmit, recv);
    else 
	return (0);
}

/*
 * PhysGetUpperHook()
 */

int
PhysGetUpperHook(Link l, char *path, char *hook)
{
    if (!l->rep) {
	snprintf(path, NG_PATHSIZ, "[%lx]:", (u_long)l->nodeID);
	strcpy(hook, NG_TEE_HOOK_LEFT);
	return 1;
    } else {
	return RepGetHook(l, path, hook);
    }
    return 0;
}

/*
 * PhysGetOriginate()
 *
 * This returns one of LINK_ORIGINATE_{UNKNOWN, LOCAL, REMOTE}
 */

int
PhysGetOriginate(Link l)
{
  const struct phystype *pt = l->type;

  return((pt && pt->originate) ? (*pt->originate)(l) : LINK_ORIGINATE_UNKNOWN);
}

/*
 * PhysIsSync()
 *
 * This returns 1 if link is synchronous
 */

int
PhysIsSync(Link l)
{
  const struct phystype *pt = l->type;

  return((pt && pt->issync) ? (*pt->issync)(l) : 0);
}

/*
 * PhysSetCalledNum()
 */

int
PhysSetCallingNum(Link l, char *buf)
{
    const struct phystype *pt = l->type;

    if (pt && pt->setcallingnum)
	return ((*pt->setcallingnum)(l, buf));
    else
	return (0);
}

/*
 * PhysSetCalledNum()
 */

int
PhysSetCalledNum(Link l, char *buf)
{
    const struct phystype *pt = l->type;

    if (pt && pt->setcallednum)
	return ((*pt->setcallednum)(l, buf));
    else
	return (0);
}

/*
 * PhysGetSelfName()
 */

int
PhysGetSelfName(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->selfname)
	return ((*pt->selfname)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetPeerName()
 */

int
PhysGetPeerName(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->peername)
	return ((*pt->peername)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetSelfAddr()
 */

int
PhysGetSelfAddr(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->selfaddr)
	return ((*pt->selfaddr)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetPeerAddr()
 */

int
PhysGetPeerAddr(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->peeraddr)
	return ((*pt->peeraddr)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetPeerPort()
 */

int
PhysGetPeerPort(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->peerport)
	return ((*pt->peerport)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetPeerMacAddr()
 */

int
PhysGetPeerMacAddr(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->peermacaddr)
	return ((*pt->peermacaddr)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetPeerIface()
 */

int
PhysGetPeerIface(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->peeriface)
	return ((*pt->peeriface)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetCallingNum()
 */

int
PhysGetCallingNum(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt) {
	/* For untrusted peers use peeraddr as calling */
	if (Enabled(&l->conf.options, LINK_CONF_PEER_AS_CALLING) && pt->peeraddr)
	    (*pt->peeraddr)(l, buf, buf_len);
	else if (pt->callingnum)
	    (*pt->callingnum)(l, buf, buf_len);
	if (Enabled(&l->conf.options, LINK_CONF_REPORT_MAC)) {
	    char tmp[64];
	    strlcat(buf, " / ", buf_len);
	    if (pt->peermacaddr) {
		(*pt->peermacaddr)(l, tmp, sizeof(tmp));
		strlcat(buf, tmp, buf_len);
	    }
	    strlcat(buf, " / ", buf_len);
	    if (pt->peeriface) {
		(*pt->peeriface)(l, tmp, sizeof(tmp));
		strlcat(buf, tmp, buf_len);
	    }
	}
    }
    return (0);
}

/*
 * PhysGetCalledNum()
 */

int
PhysGetCalledNum(Link l, char *buf, size_t buf_len)
{
    const struct phystype *pt = l->type;

    buf[0] = 0;

    if (pt && pt->callednum)
	return ((*pt->callednum)(l, buf, buf_len));
    else
	return (0);
}

/*
 * PhysGetMtu()
 */

u_short
PhysGetMtu(Link l, int conf)
{
    const struct phystype *pt = l->type;

    if (pt) {
	if (pt->getmtu)
	    return ((*pt->getmtu)(l, conf));
	if (conf == 0) {
	    if (pt->mtu)
		return (pt->mtu);
	    else
		return (0);
	} else
	    return (l->conf.mtu ? l->conf.mtu : LCP_DEFAULT_MRU);
    } else
	return (0);
}

/*
 * PhysGetMru()
 */

u_short
PhysGetMru(Link l, int conf)
{
    const struct phystype *pt = l->type;

    if (pt) {
	if (pt->getmru)
	    return ((*pt->getmru)(l, conf));
	if (conf == 0) {
	    if (pt->mru)
		return (pt->mru);
	    else
		return (0);
	} else
	    return (l->conf.mru);
    } else
	return (0);
}

/*
 * PhysIsBusy()
 *
 * This returns 1 if link is busy
 */

int
PhysIsBusy(Link l)
{
    return (l->die || l->rep || l->state != PHYS_STATE_DOWN ||
	l->lcp.fsm.state != ST_INITIAL || l->lcp.auth.acct_thread != NULL ||
	(l->tmpl && (l->children >= l->conf.max_children || gChildren >= gMaxChildren)));
}

/*
 * PhysShutdown()
 */

void
PhysShutdown(Link l)
{
    const struct phystype *pt = l->type;

    MsgUnRegister(&l->pmsgs);

    if (pt && pt->shutdown)
	(*pt->shutdown)(l);
}

/*
 * PhysSetDeviceType()
 */

void
PhysSetDeviceType(Link l, char *typename)
{
  const struct phystype *pt;
  int		k;

  /* Make sure device type not already set */
  if (l->type) {
    Log(LG_ERR, ("[%s] device type already set to %s",
      l->name, l->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", l->name, typename));
    return;
  }
  l->type = pt;

  /* Initialize type specific stuff */
  if ((l->type->init)(l) < 0) {
    Log(LG_ERR, ("[%s] type \"%s\" initialization failed",
      l->name, l->type->name));
    l->type = NULL;
    return;
  }
}

/*
 * PhysMsg()
 */

static void
PhysMsg(int type, void *arg)
{
    Link	const l = (Link)arg;

    if (l->dead) {
	UNREF(l);
	return;
    }
    Log(LG_PHYS2, ("[%s] device: %s event in state %s",
	l->name, MsgName(type), gPhysStateNames[l->state]));
    switch (type) {
    case MSG_OPEN:
    	l->downReasonValid=0;
        if (l->rep && l->state == PHYS_STATE_UP) {
	    PhysUp(l);
	    break;
	}
	/* Redial may result in MSG_OPEN for just opened device */
	if (l->state != PHYS_STATE_UP)
	    (*l->type->open)(l);
	else
	    Log(LG_PHYS2, ("[%s] device: OPEN event ignored",
		l->name));
        break;
    case MSG_CLOSE:
        (*l->type->close)(l);
        break;
    default:
        assert(FALSE);
    }
    UNREF(l);
}

/*
 * PhysStat()
 */

int
PhysStat(Context ctx, int ac, const char *const av[], const void *arg)
{
    Link	const l = ctx->lnk;

    (void)ac;
    (void)av;
    (void)arg;

    Printf("Device '%s' (%s)\r\n", l->name, (l->tmpl)?"template":"instance");
    Printf("\tType         : %s\r\n", l->type->name);
    if (!l->tmpl) {
	Printf("\tState        : %s\r\n", gPhysStateNames[l->state]);
	if (l->state == PHYS_STATE_UP)
    	    Printf("\tSession time : %ld seconds\r\n", (long int)(time(NULL) - l->last_up));
    }

    if (l->type->showstat)
	(*l->type->showstat)(ctx);
    return 0;
}


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>