1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
TP-Link_Archer-XR500v/EN7526G_3.18Kernel_SDK/apps/public/linux-atm/switch/control.c
2024-07-22 01:58:46 -03:00

168 lines
4.1 KiB
C
Executable File

/* control.c - User control command processing */
/* Written 1998 by Werner Almesberger, EPFL ICA */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <atm.h>
#include <atmd.h>
#include "fab.h"
#include "dispatch.h"
#include "swc.h"
#define COMPONENT "COMMAND"
typedef struct _user_call {
CALL call;
struct _user_call *next;
} USER_CALL;
typedef struct {
USER_CALL *u_call;
UN_CTX un_ctx;
} CONTEXT;
static int s_control = -1;
static USER_CALL *calls = NULL;
static USER_CALL *find_call(const struct sockaddr_atmpvc *in,
const struct sockaddr_atmpvc *out)
{
USER_CALL *u_call;
for (u_call = calls; u_call; u_call = u_call->next)
if (atm_equal((struct sockaddr *) in,
(struct sockaddr *) &u_call->call.in.pvc,0,0) &&
atm_equal((struct sockaddr *) out,
(struct sockaddr *) &u_call->call.out.pvc,0,0)) break;
return u_call;
}
static void add_cb(CALL *call,int cause,void *more,void *user)
{
CONTEXT *context = user;
SWC_MSG msg;
USER_CALL **walk;
memset(&msg,0,sizeof(msg));
msg.type = smt_add;
msg.n = cause ? -EIO : 0; /* @@@ */
if (cause) free(context->u_call);
else {
for (walk = &calls; *walk && *walk; walk = &(*walk)->next);
*walk = context->u_call;
}
if (un_send(&context->un_ctx,&msg,sizeof(msg)) < 0)
diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno));
}
static void del_cb(CALL *call,int cause,void *more,void *user)
{
CONTEXT *context = user;
SWC_MSG msg;
USER_CALL **walk;
memset(&msg,0,sizeof(msg));
msg.type = smt_del;
msg.n = cause ? -EIO : 0; /* @@@ */
if (!cause) {
for (walk = &calls; *walk && *walk != context->u_call;
walk = &(*walk)->next);
if (!*walk)
diag(COMPONENT,DIAG_FATAL,"del_cb: call %p not found",
context->u_call);
*walk = (*walk)->next;
free(context->u_call);
}
if (un_send(&context->un_ctx,&msg,sizeof(msg)) < 0)
diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno));
}
static void control_msg(int sock,void *dummy)
{
CONTEXT context;
SWC_MSG msg;
USER_CALL *u_call;
int len,i;
len = un_recv(&context.un_ctx,s_control,&msg,sizeof(msg));
if (len < 0) {
diag(COMPONENT,DIAG_ERROR,"control_msg: un_recv: %s",strerror(errno));
return;
}
if (len != sizeof(SWC_MSG))
diag(COMPONENT,DIAG_FATAL,"control_msg: bad length (%d != %d)",len,
sizeof(SWC_MSG));
switch (msg.type) {
case smt_get:
/*
* This code only shows VCs set up using the manual configuration
* interface. Any VCs set up by signaling are invisible. To fix
* this we'll need a "list fabric" function in the fabric-specific
* part. (The relay doesn't maintain a list of active connections,
* nor should it.)
*/
i = msg.n;
for (u_call = calls; i && u_call; u_call = u_call->next) i--;
if (!u_call) {
msg.n = -ENOENT;
break;
}
msg.in = u_call->call.in.pvc;
msg.out = u_call->call.out.pvc;
msg.qos = u_call->call.out.qos;
break;
case smt_add:
u_call = find_call(&msg.in,&msg.out);
if (u_call) {
msg.n = -EEXIST;
break;
}
u_call = alloc_t(USER_CALL);
memset(u_call,0,sizeof(USER_CALL));
u_call->call.in.pvc = msg.in;
u_call->call.out.pvc = msg.out;
fab_init(&u_call->call);
context.u_call = u_call;
fab_op(&u_call->call,RM_CLAIM(_RM_ANY) | RM_RSV(_RM_ANY),&msg.qos,
add_cb,&context);
return;
case smt_del:
u_call = find_call(&msg.in,&msg.out);
if (!u_call) {
msg.n = -ENOENT;
break;
}
context.u_call = u_call;
fab_op(&u_call->call,RM_FREE,NULL,del_cb,&context);
return;
default:
diag(COMPONENT,DIAG_FATAL,"control_msg: unknown message type %d",
msg.type);
}
if (un_send(&context.un_ctx,&msg,sizeof(msg)) < 0)
diag(COMPONENT,DIAG_ERROR,"control_msg: un_send: %s",strerror(errno));
}
void control_init(const char *path)
{
if (s_control != -1)
diag(COMPONENT,DIAG_FATAL,"control channel is already set");
s_control = un_create(path,0600);
if (s_control < 0)
diag(COMPONENT,DIAG_FATAL,"un_create: %s",strerror(errno));
dsp_fd_add(s_control,control_msg,NULL);
}