/*
* rep.c
*
* Written by Alexander Motin <mav@FreeBSD.org>
*/
#include "ppp.h"
#include "rep.h"
#include "msg.h"
#include "ngfunc.h"
#include "log.h"
#include "util.h"
#include <netgraph/ng_message.h>
#include <netgraph/ng_socket.h>
#include <netgraph/ng_tee.h>
#include <netgraph.h>
/*
* INTERNAL FUNCTIONS
*/
static void RepShowLinks(Context ctx, Rep r);
/*
* RepIncoming()
*/
void
RepIncoming(Link l)
{
Rep r = l->rep;
struct ngm_mkpeer mkp;
char buf[64];
Log(LG_REP, ("[%s] Rep: INCOMING event from %s (0)",
r->name, l->name));
if (r->csock <= 0) {
/* Create a new netgraph node to control TCP ksocket node. */
if (NgMkSockNode(NULL, &r->csock, NULL) < 0) {
Perror("[%s] Rep: can't create control socket", r->name);
PhysClose(l);
return;
}
(void)fcntl(r->csock, F_SETFD, 1);
}
strcpy(mkp.type, NG_TEE_NODE_TYPE);
snprintf(mkp.ourhook, sizeof(mkp.ourhook), "tee");
snprintf(mkp.peerhook, sizeof(mkp.peerhook), NG_TEE_HOOK_LEFT2RIGHT);
if (NgSendMsg(r->csock, ".:", NGM_GENERIC_COOKIE,
NGM_MKPEER, &mkp, sizeof(mkp)) < 0) {
Perror("[%s] Rep: can't attach %s %s node",
l->name, NG_TEE_NODE_TYPE, mkp.ourhook);
close(r->csock);
PhysClose(l);
return;
}
/* Get tee node ID */
if ((r->node_id = NgGetNodeID(r->csock, ".:tee")) == 0) {
Perror("[%s] Rep: Cannot get %s node id", l->name, NG_TEE_NODE_TYPE);
close(r->csock);
PhysClose(l);
return;
};
PhysGetCallingNum(r->links[0], buf, sizeof(buf));
PhysSetCallingNum(r->links[1], buf);
PhysGetCalledNum(r->links[0], buf, sizeof(buf));
PhysSetCalledNum(r->links[1], buf);
PhysOpen(r->links[1]);
}
/*
* RepUp()
*/
void
RepUp(Link l)
{
Rep r = l->rep;
int n = (r->links[0] == l)?0:1;
Log(LG_REP, ("[%s] Rep: UP event from %s (%d)",
r->name, l->name, n));
r->p_up |= (1 << n);
if (n == 1)
PhysOpen(r->links[1-n]);
if (r->p_up == 3 && r->csock > 0 && r->node_id) {
char path[NG_PATHSIZ];
snprintf(path, sizeof(path), "[%x]:", r->node_id);
NgFuncShutdownNode(r->csock, r->name, path);
r->node_id = 0;
close(r->csock);
r->csock = -1;
}
}
/*
* RepDown()
*/
void
RepDown(Link l)
{
Rep r = l->rep;
int n = (r->links[0] == l)?0:1;
Log(LG_REP, ("[%s] Rep: DOWN event from %s (%d)",
r->name, l->name, n));
r->p_up &= ~(1 << n);
if (r->links[1-n])
PhysClose(r->links[1-n]);
if (r->csock > 0 && r->node_id) {
char path[NG_PATHSIZ];
snprintf(path, sizeof(path), "[%x]:", r->node_id);
NgFuncShutdownNode(r->csock, r->name, path);
r->node_id = 0;
close(r->csock);
r->csock = -1;
}
l->rep->links[n] = NULL;
l->rep = NULL;
if (!l->stay) {
REF(l);
MsgSend(&l->msgs, MSG_SHUTDOWN, l);
}
if (r->links[1-n] == NULL)
RepShutdown(r);
}
/*
* RepIsSync()
*/
int
RepIsSync(Link l) {
Rep r = l->rep;
int n = (r->links[0] == l)?0:1;
if (r->links[1-n])
return (PhysIsSync(r->links[1-n]));
else
return (0);
}
/*
* RepSetAccm()
*/
void
RepSetAccm(Link l, u_int32_t xmit, u_int32_t recv) {
Rep r = l->rep;
int n = (r->links[0] == l)?0:1;
Log(LG_REP, ("[%s] Rep: SetAccm(0x%08x, 0x%08x) from %s (%d)",
r->name, xmit, recv, l->name, n));
if (r->links[1-n])
PhysSetAccm(r->links[1-n], xmit, recv);
}
/*
* RepGetHook()
*/
int
RepGetHook(Link l, char *path, char *hook)
{
Rep r = l->rep;
int n = (r->links[0] == l)?0:1;
if (r->node_id == 0)
return (0);
snprintf(path, NG_PATHSIZ, "[%lx]:", (u_long)r->node_id);
if (n == 0)
snprintf(hook, NG_HOOKSIZ, NG_TEE_HOOK_LEFT);
else
snprintf(hook, NG_HOOKSIZ, NG_TEE_HOOK_RIGHT);
return (1);
}
/*
* RepCommand()
*
* Show list of all bundles or set bundle
*/
int
RepCommand(Context ctx, int ac, const char *const av[], const void *arg)
{
Rep r;
int k;
(void)arg;
if (ac > 1)
return (-1);
if (ac == 0) {
Printf("Defined repeaters:\r\n");
for (k = 0; k < gNumReps; k++) {
if ((r = gReps[k]) != NULL) {
Printf("\t%-15s%s %s\n",
r->name, r->links[0]->name, r->links[1]->name);
}
}
return (0);
}
if ((r = RepFind(av[0])) == NULL) {
RESETREF(ctx->rep, NULL);
RESETREF(ctx->bund, NULL);
RESETREF(ctx->lnk, NULL);
Error("Repeater \"%s\" not defined.", av[0]);
}
/* Change repeater, and link also if needed */
RESETREF(ctx->rep, r);
RESETREF(ctx->bund, NULL);
RESETREF(ctx->lnk, r->links[0]);
return(0);
}
/*
* RepCreate()
*
* Create a new repeater.
*/
int
RepCreate(Link in, const char *out)
{
Rep r;
Link l;
int k;
if ((l = LinkFind(out)) == NULL) {
Log(LG_REP, ("[%s] Can't find link \"%s\"", in->name, out));
return (-1);
}
if (PhysIsBusy(l)) {
Log(LG_REP, ("[%s] Link \"%s\" is busy", in->name, out));
return (-1);
}
if (l->tmpl)
l = LinkInst(l, NULL, 0, 0);
if (!l) {
Log(LG_REP, ("[%s] Can't create link \"%s\"", in->name, out));
return (-1);
}
/* Create a new repeater structure */
r = Malloc(MB_REP, sizeof(*r));
snprintf(r->name, sizeof(r->name), "R-%s", in->name);
r->csock = -1;
/* Add repeater to the list of repeaters and make it the current active repeater */
for (k = 0; k < gNumReps && gReps[k] != NULL; k++);
if (k == gNumReps) /* add a new repeater pointer */
LengthenArray(&gReps, sizeof(*gReps), &gNumReps, MB_REP);
r->id = k;
gReps[k] = r;
REF(r);
/* Join all part */
r->links[0] = in;
r->links[1] = l;
in->rep = r;
l->rep = r;
/* Done */
return(0);
}
/*
* RepShutdown()
*/
void
RepShutdown(Rep r)
{
int k;
gReps[r->id] = NULL;
Log(LG_REP, ("[%s] Rep: Shutdown", r->name));
for (k = 0; k < 2; k++) {
Link l;
if ((l = r->links[k]) != NULL)
if (!l->stay)
LinkShutdown(l);
}
if (r->csock > 0 && r->node_id) {
char path[NG_PATHSIZ];
snprintf(path, sizeof(path), "[%x]:", r->node_id);
NgFuncShutdownNode(r->csock, r->name, path);
r->node_id = 0;
close(r->csock);
r->csock = -1;
}
r->dead = 1;
UNREF(r);
}
/*
* RepStat()
*
* Show state of a repeater
*/
int
RepStat(Context ctx, int ac, const char *const av[], const void *arg)
{
Rep r;
(void)arg;
/* Find repeater they're talking about */
switch (ac) {
case 0:
r = ctx->rep;
break;
case 1:
if ((r = RepFind(av[0])) == NULL)
Error("Repeater \"%s\" not defined.", av[0]);
break;
default:
return(-1);
}
/* Show stuff about the repeater */
Printf("Repeater %s:\r\n", r->name);
Printf("\tLinks : ");
RepShowLinks(ctx, r);
return(0);
}
/*
* RepShowLinks()
*/
static void
RepShowLinks(Context ctx, Rep r)
{
int j;
for (j = 0; j < 2; j++) {
if (r->links[j]) {
Printf("%s[%s/%s] ", r->links[j]->name, r->links[j]->type->name,
gPhysStateNames[r->links[j]->state]);
}
}
Printf("\r\n");
}
/*
* RepFind()
*
* Find a repeater structure
*/
Rep
RepFind(const char *name)
{
int k;
for (k = 0;
k < gNumReps && (!gReps[k] || strcmp(gReps[k]->name, name));
k++);
return((k < gNumReps) ? gReps[k] : NULL);
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>