/*
* 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>
#ifdef __DragonFly__
#include <netgraph/socket/ng_socket.h>
#include <netgraph/tee/ng_tee.h>
#else
#include <netgraph/ng_socket.h>
#include <netgraph/ng_tee.h>
#endif
#include <netgraph.h>
/*
* DEFINITIONS
*/
/* Set menu options */
enum {
SET_ACCEPT,
SET_DENY,
SET_ENABLE,
SET_DISABLE,
SET_YES,
SET_NO,
};
/*
* INTERNAL FUNCTIONS
*/
static Rep RepFind(char *name);
static int RepSetCommand(Context ctx, int ac, char *av[], void *arg);
static void RepShowLinks(Context ctx, Rep r);
/*
* GLOBAL VARIABLES
*/
struct discrim self_discrim;
const struct cmdtab RepSetCmds[] = {
{ "accept [opt ...]", "Accept option",
RepSetCommand, NULL, (void *) SET_ACCEPT },
{ "deny [opt ...]", "Deny option",
RepSetCommand, NULL, (void *) SET_DENY },
{ "enable [opt ...]", "Enable option",
RepSetCommand, NULL, (void *) SET_ENABLE },
{ "disable [opt ...]", "Disable option",
RepSetCommand, NULL, (void *) SET_DISABLE },
{ "yes [opt ...]", "Enable and accept option",
RepSetCommand, NULL, (void *) SET_YES },
{ "no [opt ...]", "Disable and deny option",
RepSetCommand, NULL, (void *) SET_NO },
{ NULL },
};
/*
* INTERNAL VARIABLES
*/
static const struct confinfo gConfList[] = {
{ 0, 0, NULL },
};
/*
* RepOpen()
*/
void
RepOpen(void)
{
// MsgSend(rep->msgs, MSG_OPEN, NULL);
}
/*
* RepClose()
*/
void
RepClose(void)
{
// MsgSend(rep->msgs, MSG_CLOSE, NULL);
}
/*
* RepIncoming()
*/
void
RepIncoming(PhysInfo p)
{
Rep r = p->rep;
int n = (r->physes[0] == p)?0:1;
struct ngm_mkpeer mkp;
union {
u_char buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
struct ng_mesg reply;
} repbuf;
struct ng_mesg *const reply = &repbuf.reply;
struct nodeinfo *ninfo = (struct nodeinfo *)&reply->data;
char buf[64];
r->initiator = n;
Log(LG_REP, ("[%s] REP: INCOMING event from %s (%d)",
r->name, p->name, n));
if (r->csock <= 0) {
/* Create a new netgraph node to control TCP ksocket node. */
if (NgMkSockNode(NULL, &r->csock, NULL) < 0) {
Log(LG_ERR, ("[%s] REP: can't create control socket: %s",
r->name, strerror(errno)));
PhysClose(p);
return;
}
(void)fcntl(r->csock, F_SETFD, 1);
}
snprintf(mkp.type, sizeof(mkp.type), "%s", 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) {
Log(LG_ERR, ("[%s] REP: can't attach %s %s node: %s",
p->name, NG_TEE_NODE_TYPE, mkp.ourhook, strerror(errno)));
close(r->csock);
PhysClose(p);
return;
}
/* Get tee node ID */
if (NgSendMsg(r->csock, ".:tee",
NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) != -1) {
if (NgRecvMsg(r->csock, reply, sizeof(repbuf), NULL) != -1) {
r->node_id = ninfo->id;
}
}
PhysGetCallingNum(r->physes[n], buf, sizeof(buf));
PhysSetCallingNum(r->physes[1-n], buf);
PhysGetCalledNum(r->physes[n], buf, sizeof(buf));
PhysSetCalledNum(r->physes[1-n], buf);
PhysOpen(r->physes[1-n]);
}
/*
* RepUp()
*/
void
RepUp(PhysInfo p)
{
Rep r = p->rep;
int n = (r->physes[0] == p)?0:1;
Log(LG_REP, ("[%s] REP: UP event from %s (%d)",
r->name, p->name, n));
r->p_up |= (1 << n);
if (n != r->initiator) {
PhysOpen(r->physes[1-n]);
}
if (r->p_up == 3 && r->csock > 0 && r->node_id) {
char path[NG_PATHLEN + 1];
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(PhysInfo p)
{
Rep r = p->rep;
int n = (r->physes[0] == p)?0:1;
Log(LG_REP, ("[%s] REP: DOWN event from %s (%d)",
r->name, p->name, n));
r->p_up &= ~(1 << n);
PhysClose(r->physes[0]);
PhysClose(r->physes[1]);
if (r->csock > 0 && r->node_id) {
char path[NG_PATHLEN + 1];
snprintf(path, sizeof(path), "[%x]:", r->node_id);
NgFuncShutdownNode(r->csock, r->name, path);
r->node_id = 0;
close(r->csock);
r->csock = -1;
}
}
/*
* RepIsSync()
*/
int
RepIsSync(PhysInfo p) {
Rep r = p->rep;
int n = (r->physes[0] == p)?0:1;
return (PhysIsSync(r->physes[1-n]));
}
/*
* RepSetAccm()
*/
void
RepSetAccm(PhysInfo p, u_int32_t xmit, u_int32_t recv) {
Rep r = p->rep;
int n = (r->physes[0] == p)?0:1;
Log(LG_REP, ("[%s] REP: SetAccm(0x%08x, 0x%08x) from %s (%d)",
r->name, xmit, recv, p->name, n));
PhysSetAccm(r->physes[1-n], xmit, recv);
}
/*
* RepGetHook()
*/
int
RepGetHook(PhysInfo p, char *path, char *hook)
{
Rep r = p->rep;
int n = (r->physes[0] == p)?0:1;
if (r->node_id == 0)
return (0);
snprintf(path, NG_PATHLEN, "[%lx]:", (u_long)r->node_id);
if (n == 0)
snprintf(hook, NG_HOOKLEN, NG_TEE_HOOK_LEFT);
else
snprintf(hook, NG_HOOKLEN, NG_TEE_HOOK_RIGHT);
return (1);
}
/*
* RepCommand()
*
* Show list of all bundles or set bundle
*/
int
RepCommand(Context ctx, int ac, char *av[], void *arg)
{
Rep r;
int k;
switch (ac) {
case 0:
Printf("Defined repeaters:\r\n");
for (k = 0; k < gNumReps; k++)
if ((r = gReps[k]) != NULL) {
Printf("\t%-15s", r->name);
RepShowLinks(ctx, r);
}
break;
case 1:
/* Change bundle, and link also if needed */
if ((r = RepFind(av[0])) != NULL) {
ctx->rep = r;
ctx->phys = r->physes[0];
ctx->bund = NULL;
ctx->lnk = NULL;
} else
Printf("Repeater \"%s\" not defined.\r\n", av[0]);
break;
default:
return(-1);
}
return(0);
}
/*
* RepCreateCmd()
*
* Create a new repeater.
*/
int
RepCreateCmd(Context ctx, int ac, char *av[], void *arg)
{
Rep r;
PhysInfo new_link;
int k;
/* Args */
if (ac != 3)
return(-1);
#if NG_NODESIZ>=32
if (strlen(av[0])>16) {
#else
if (strlen(av[0])>6) {
#endif
Log(LG_ERR, ("repeater name \"%s\" is too long", av[0]));
return (-1);
}
/* See if repeater name already taken */
if ((r = RepFind(av[0])) != NULL) {
Log(LG_ERR, ("repeater \"%s\" already exists", av[0]));
return (-1);
}
/* Create a new repeater structure */
r = Malloc(MB_REP, sizeof(*r));
snprintf(r->name, sizeof(r->name), "%s", av[0]);
r->csock = -1;
/* Create each link and add it to the repeater */
for (k = 1; k < ac; k++) {
#if NG_NODESIZ>=32
if (strlen(av[k])>16) {
#else
if (strlen(av[k])>6) {
#endif
Log(LG_ERR, ("phys name \"%s\" is too long", av[k]));
RepShutdown(r);
return (-1);
}
if ((new_link = PhysInit(av[k], NULL, r)) == NULL) {
Log(LG_ERR, ("[%s] creation of phys \"%s\" failed", av[0], av[k]));
RepShutdown(r);
return (-1);
} else {
r->physes[k - 1] = new_link;
}
}
/* 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);
gReps[k] = r;
ctx->rep = r;
ctx->phys = r->physes[0];
ctx->lnk = NULL;
ctx->bund = NULL;
/* Done */
return(0);
}
/*
* RepShutdown()
*
*/
void
RepShutdown(Rep r)
{
int k;
for(k = 0; k < 2; k++) {
if (r->physes[k])
PhysShutdown(r->physes[k]);
}
for (k = 0;
k < gNumReps && gReps[k] != r;
k++);
if (k < gNumReps)
gReps[k] = NULL;
if (r->csock > 0 && r->node_id) {
char path[NG_PATHLEN + 1];
snprintf(path, sizeof(path), "[%x]:", r->node_id);
NgFuncShutdownNode(r->csock, r->name, path);
r->node_id = 0;
close(r->csock);
r->csock = -1;
}
Freee(MB_REP, r);
}
/*
* RepStat()
*
* Show state of a repeater
*/
int
RepStat(Context ctx, int ac, char *av[], void *arg)
{
Rep r;
/* Find repeater they're talking about */
switch (ac) {
case 0:
r = ctx->rep;
break;
case 1:
if ((r = RepFind(av[0])) == NULL) {
Printf("Repeater \"%s\" not defined.\r\n", av[0]);
return(0);
}
break;
default:
return(-1);
}
/* Show stuff about the repeater */
Printf("Repeater %s:\r\n", r->name);
Printf("\tPhyses : ");
RepShowLinks(ctx, r);
return(0);
}
/*
* RepShowLinks()
*/
static void
RepShowLinks(Context ctx, Rep r)
{
int j;
for (j = 0; j < 2; j++) {
Printf("%s", r->physes[j]->name);
if (!r->physes[j]->type)
Printf("[no type/%s] ",
gPhysStateNames[r->physes[j]->state]);
else
Printf("[%s/%s] ", r->physes[j]->type->name,
gPhysStateNames[r->physes[j]->state]);
}
Printf("\r\n");
}
/*
* RepFind()
*
* Find a repeater structure
*/
static Rep
RepFind(char *name)
{
int k;
for (k = 0;
k < gNumReps && (strcmp(gReps[k]->name, name));
k++);
return((k < gNumReps) ? gReps[k] : NULL);
}
/*
* RepSetCommand()
*/
static int
RepSetCommand(Context ctx, int ac, char *av[], void *arg)
{
Rep r = ctx->rep;
if (ac == 0)
return(-1);
switch ((intptr_t)arg) {
case SET_ACCEPT:
AcceptCommand(ac, av, &r->options, gConfList);
break;
case SET_DENY:
DenyCommand(ac, av, &r->options, gConfList);
break;
case SET_ENABLE:
EnableCommand(ac, av, &r->options, gConfList);
break;
case SET_DISABLE:
DisableCommand(ac, av, &r->options, gConfList);
break;
case SET_YES:
YesCommand(ac, av, &r->options, gConfList);
break;
case SET_NO:
NoCommand(ac, av, &r->options, gConfList);
break;
default:
assert(0);
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1