587 lines
16 KiB
C
587 lines
16 KiB
C
/* kernel.c - Processing of incoming kernel messages */
|
|
|
|
/* Written 1995-2000 by Werner Almesberger, EPFL-LRC/ICA */
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
#include <atm.h>
|
|
#include <linux/atmsvc.h>
|
|
#include <linux/atmdev.h>
|
|
|
|
#include "atmd.h"
|
|
#include "uni.h"
|
|
#include "qlib.h"
|
|
#include <q.out.h>
|
|
|
|
#include "proto.h"
|
|
#include "sap.h"
|
|
#include "io.h"
|
|
#include "policy.h"
|
|
#include "timeout.h"
|
|
|
|
|
|
#define COMPONENT "KERNEL"
|
|
|
|
|
|
static int send_setup(SOCKET *sock)
|
|
{
|
|
static unsigned long call_ref = 0;
|
|
struct sockaddr_atmsvc *local;
|
|
SOCKET *walk;
|
|
Q_DSC dsc;
|
|
int error,size;
|
|
|
|
do {
|
|
if (++call_ref == 0x7fffff) call_ref = 1;
|
|
for (walk = sockets; walk; walk = walk->next)
|
|
if (walk->call_ref == call_ref) break;
|
|
}
|
|
while (walk);
|
|
sock->call_ref = call_ref;
|
|
q_create(&dsc,q_buffer,MAX_Q_MSG);
|
|
local = NULL;
|
|
error = 0;
|
|
sock->sig = route_remote(&sock->remote);
|
|
if (sock->sig && sock->sig->mode == sm_switch) local = &sock->local;
|
|
if (atmsvc_addr_in_use(sock->local) && !local) {
|
|
sock->sig = route_local(&sock->local);
|
|
if (sock->sig) local = &sock->local;
|
|
else {
|
|
error = -EADDRNOTAVAIL;
|
|
diag(COMPONENT,DIAG_WARN,"local address no longer available");
|
|
}
|
|
}
|
|
else {
|
|
if (!sock->sig) error = -EHOSTUNREACH;
|
|
else {
|
|
if (!local) local = get_local(sock->sig);
|
|
if (!local) local = get_local(NULL);
|
|
if (local) sock->local = *local;
|
|
else {
|
|
error = -EADDRNOTAVAIL;
|
|
diag(COMPONENT,DIAG_ERROR,"no local address");
|
|
}
|
|
}
|
|
}
|
|
if (local) {
|
|
if (*local->sas_addr.pub) {
|
|
q_assign(&dsc,QF_cgpn_plan,ATM_NP_E164);
|
|
q_assign(&dsc,QF_cgpn_type,ATM_TON_INTRNTNL);
|
|
q_write(&dsc,QF_cgpn,(void *) local->sas_addr.pub,
|
|
strlen(local->sas_addr.pub));
|
|
}
|
|
else {
|
|
q_assign(&dsc,QF_cgpn_plan,ATM_NP_AEA);
|
|
q_assign(&dsc,QF_cgpn_type,ATM_TON_UNKNOWN);
|
|
q_write(&dsc,QF_cgpn,(void *) local->sas_addr.prv,ATM_ESA_LEN);
|
|
}
|
|
}
|
|
q_assign(&dsc,QF_call_ref,call_ref);
|
|
q_assign(&dsc,QF_msg_type,ATM_MSG_SETUP);
|
|
q_assign(&dsc,QF_aal_type,5); /* AAL 5 */
|
|
#if defined(UNI30) || defined(DYNAMIC_UNI)
|
|
if (!error && sock->sig->uni == S_UNI30)
|
|
q_assign(&dsc,QF_aal_mode,1); /* Message mode - LANE seems to really
|
|
want this */
|
|
#endif
|
|
q_assign(&dsc,QF_sscs_type,0); /* unspecified - LANE wants this */
|
|
if (!error)
|
|
error = sap_encode(&dsc,&sock->remote,&sock->sap,&sock->qos,
|
|
sock->sig->uni,sock->sig->max_rate);
|
|
q_assign(&dsc,QF_bearer_class,16); /* BCOB-X */
|
|
q_assign(&dsc,QF_upcc,0); /* p2p */
|
|
#if !defined(UNI30) || defined(DYNAMIC_UNI)
|
|
if (!error && sock->sig->uni != S_UNI30)
|
|
q_assign(&dsc,QF_qos_cs,Q2931_CS_ITU);
|
|
#endif
|
|
q_assign(&dsc,QF_qos_fw,0); /* QOS 0 */
|
|
q_assign(&dsc,QF_qos_bw,0);
|
|
if (!error && sock->sig->mode != sm_user) {
|
|
if (!atmpvc_addr_in_use(sock->pvc)) {
|
|
int vpci,vci;
|
|
|
|
if (sock->sig->mode == sm_switch)
|
|
diag(COMPONENT,DIAG_FATAL,"No CI allocator (use -A)");
|
|
vpci = 0;
|
|
sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci);
|
|
sock->pvc.sap_addr.vpi = vpci;
|
|
vci = get_vci(sock->pvc.sap_addr.itf);
|
|
if (vci < 0) {
|
|
(void) q_close(&dsc);
|
|
return vci;
|
|
}
|
|
sock->pvc.sap_addr.vci = vci;
|
|
}
|
|
q_assign(&dsc,QF_vpi,sock->pvc.sap_addr.vpi);
|
|
q_assign(&dsc,QF_vci,sock->pvc.sap_addr.vci);
|
|
}
|
|
if ((size = q_close(&dsc)) < 0) error = -EINVAL;
|
|
else if (!error) to_signaling(sock->sig,q_buffer,size);
|
|
return error;
|
|
}
|
|
|
|
|
|
static int send_connect(SOCKET *sock)
|
|
{
|
|
Q_DSC dsc;
|
|
int size;
|
|
|
|
q_create(&dsc,q_buffer,MAX_Q_MSG);
|
|
q_assign(&dsc,QF_msg_type,ATM_MSG_CONNECT);
|
|
q_assign(&dsc,QF_call_ref,sock->call_ref);
|
|
if (sock->ep_ref >= 0) q_assign(&dsc,QF_ep_ref,sock->ep_ref);
|
|
if (sock->ep_ref <= 0) { /* no AAL parameters if ep_ref present and != 0 */
|
|
q_assign(&dsc,QF_aal_type,5);
|
|
#if defined(UNI30) || defined(DYNAMIC_UNI)
|
|
if (sock->sig->uni == S_UNI30)
|
|
q_assign(&dsc,QF_aal_mode,1); /* Message mode - LANE seems to
|
|
really want this */
|
|
#endif
|
|
q_assign(&dsc,QF_sscs_type,0); /* unspecified - LANE wants this */
|
|
q_assign(&dsc,QF_fw_max_sdu,sock->qos.rxtp.max_sdu);
|
|
q_assign(&dsc,QF_bw_max_sdu,sock->qos.txtp.max_sdu);
|
|
}
|
|
if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size);
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
|
|
|
|
static void send_modify_request(SOCKET *sock)
|
|
{
|
|
Q_DSC dsc;
|
|
int size;
|
|
|
|
q_create(&dsc,q_buffer,MAX_Q_MSG);
|
|
q_assign(&dsc,QF_msg_type,ATM_MSG_MODIFY_REQ);
|
|
q_assign(&dsc,QF_call_ref,sock->call_ref);
|
|
if (sock->new_qos.txtp.traffic_class)
|
|
q_assign(&dsc,QF_fw_pcr_01,SELECT_TOP_PCR(sock->new_qos.txtp));
|
|
if (sock->new_qos.rxtp.traffic_class)
|
|
q_assign(&dsc,QF_bw_pcr_01,SELECT_TOP_PCR(sock->new_qos.rxtp));
|
|
if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size);
|
|
}
|
|
|
|
|
|
static void send_modify_ack(SOCKET *sock)
|
|
{
|
|
Q_DSC dsc;
|
|
int size;
|
|
|
|
q_create(&dsc,q_buffer,MAX_Q_MSG);
|
|
q_assign(&dsc,QF_msg_type,ATM_MSG_MODIFY_ACK);
|
|
q_assign(&dsc,QF_call_ref,sock->call_ref);
|
|
if (sock->qos.rxtp.traffic_class != ATM_NONE &&
|
|
sock->qos.rxtp.max_pcr < sock->new_qos.rxtp.max_pcr) {
|
|
q_assign(&dsc,QF_type_of_report,ATM_TOR_MOD_CONF);
|
|
START_TIMER(sock,T361);
|
|
}
|
|
if ((size = q_close(&dsc)) >= 0) to_signaling(sock->sig,q_buffer,size);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
static void dispatch(SOCKET *sock,struct atmsvc_msg *msg)
|
|
{
|
|
int error;
|
|
|
|
switch (msg->type) {
|
|
case as_bind: /* only in NULL state */
|
|
if (sock) break;
|
|
if (msg->svc.sas_family != AF_ATMSVC) {
|
|
SEND_ERROR(msg->vcc,-EAFNOSUPPORT);
|
|
return;
|
|
}
|
|
if (!atmsvc_addr_in_use(msg->svc))
|
|
#ifdef BE_PICKY_ABOUT_BINDING_LOCAL_WILDCARD_ADDRESSES
|
|
if (!get_local(NULL)) SEND_ERROR(msg->vcc,-EADDRNOTAVAIL);
|
|
else
|
|
#endif
|
|
send_kernel(msg->vcc,kptr_null,as_okay,0,NULL,NULL,
|
|
get_local(NULL),NULL,NULL);
|
|
else {
|
|
if (!route_local(&msg->svc)) {
|
|
SEND_ERROR(msg->vcc,-EADDRNOTAVAIL);
|
|
return;
|
|
}
|
|
send_kernel(msg->vcc,kptr_null,as_okay,0,NULL,NULL,NULL,NULL,
|
|
NULL);
|
|
}
|
|
return;
|
|
case as_connect: /* NULL state only */
|
|
if (sock) break;
|
|
if (!allow(&msg->svc,ACL_OUT)) {
|
|
SEND_ERROR(msg->vcc,-EACCES);
|
|
return;
|
|
}
|
|
sock = new_sock(msg->vcc);
|
|
sock->local = msg->local;
|
|
sock->remote = msg->svc;
|
|
sock->qos = msg->qos;
|
|
sock->sap = msg->sap;
|
|
sock->state = ss_connecting;
|
|
sock->pvc = msg->pvc;
|
|
error = send_setup(sock);
|
|
if (error) {
|
|
SEND_ERROR(msg->vcc,error);
|
|
free_sock(sock);
|
|
return;
|
|
}
|
|
START_TIMER(sock,T303);
|
|
new_state(sock,ss_connecting);
|
|
return;
|
|
case as_accept:
|
|
if (sock->state == ss_zombie) {
|
|
SEND_ERROR(msg->vcc,-ECONNABORTED); /* -ERESTARTSYS ? */
|
|
free_sock(sock);
|
|
return;
|
|
}
|
|
if (sock->state != ss_indicated && sock->state != ss_proceeding)
|
|
break;
|
|
if (sock->state == ss_indicated && sock->sig->mode != sm_user)
|
|
diag(COMPONENT,DIAG_FATAL,"No CI allocator (use -A)");
|
|
error = send_connect(sock);
|
|
if (!error) {
|
|
START_TIMER(sock,T313);
|
|
new_state(sock,ss_accepting);
|
|
return;
|
|
}
|
|
SEND_ERROR(sock->id,error);
|
|
send_release(sock,0); /* @@@ */
|
|
START_TIMER(sock,T308_1);
|
|
new_state(sock,ss_wait_rel);
|
|
return;
|
|
case as_reject: /* ZOMBIE, INDICATED, or PROCEEDING */
|
|
switch (sock->state) {
|
|
case ss_indicated:
|
|
send_release_complete(sock->sig,sock->call_ref,
|
|
ATM_CV_CALL_REJ);
|
|
/* fall through */
|
|
case ss_zombie:
|
|
free_sock(sock);
|
|
return;
|
|
case ss_proceeding:
|
|
send_release(sock,ATM_CV_CALL_REJ);
|
|
/* @@@ should use msg->reply */
|
|
START_TIMER(sock,T308_1);
|
|
new_state(sock,ss_wait_rel);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case as_listen: /* NULL */
|
|
if (sock) break;
|
|
if (msg->svc.sas_family != AF_ATMSVC) {
|
|
SEND_ERROR(msg->vcc,-EAFNOSUPPORT);
|
|
return;
|
|
}
|
|
if (msg->qos.aal != ATM_AAL5) {
|
|
SEND_ERROR(msg->vcc,-EINVAL);
|
|
return;
|
|
}
|
|
if (lookup_sap(&msg->svc,&msg->sap,&msg->qos,NULL,NULL,NULL,1)) {
|
|
SEND_ERROR(msg->vcc,-EADDRINUSE);
|
|
return;
|
|
}
|
|
sock = new_sock(msg->vcc);
|
|
sock->local = msg->svc;
|
|
sock->sap = msg->sap;
|
|
sock->qos = msg->qos;
|
|
send_kernel(sock->id,kptr_null,as_okay,0,NULL,NULL,NULL,NULL,NULL);
|
|
sock->state = ss_listening;
|
|
return;
|
|
case as_close: /* all but INDICATED, PROCEEDING, ZOMBIE, and WAIT_REL */
|
|
if (sock && (sock->state == ss_indicated ||
|
|
sock->state == ss_proceeding || sock->state == ss_zombie ||
|
|
sock->state == ss_wait_rel)) break;
|
|
switch (sock ? sock->state : ss_null) {
|
|
case ss_listening:
|
|
send_close(sock);
|
|
if (sock->listen) new_state(sock,ss_listen_zombie);
|
|
else free_sock(sock);
|
|
return;
|
|
case ss_zombie:
|
|
send_close(sock);
|
|
/* fall through */
|
|
case ss_wait_close:
|
|
free_sock(sock);
|
|
/* fall through */
|
|
case ss_null:
|
|
case ss_rel_req:
|
|
return;
|
|
case ss_connecting:
|
|
case ss_accepting:
|
|
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
|
|
case ss_mod_req:
|
|
#endif
|
|
STOP_TIMER(sock);
|
|
/* fall through */
|
|
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
|
|
case ss_mod_lcl:
|
|
case ss_mod_rcv:
|
|
case ss_mod_fin_ok:
|
|
case ss_mod_fin_fail:
|
|
case ss_mod_fin_ack:
|
|
#endif
|
|
case ss_connected:
|
|
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
|
|
if (timer_handler(sock->conn_timer) == on_T361)
|
|
STOP_TIMER(sock);
|
|
#endif
|
|
if (sock->state == ss_connected)
|
|
diag(COMPONENT,DIAG_INFO,"Active close (CR 0x%06X)",
|
|
sock->call_ref);
|
|
send_release(sock,
|
|
#ifdef DYNAMIC_UNI
|
|
sock->sig->uni != S_UNI30 ? ATM_CV_NORMAL_CLEAR :
|
|
ATM_CV_NORMAL_UNSPEC
|
|
#else
|
|
#if defined(UNI31) || defined(UNI40)
|
|
ATM_CV_NORMAL_CLEAR
|
|
#else
|
|
ATM_CV_NORMAL_UNSPEC
|
|
#endif
|
|
#endif
|
|
);
|
|
START_TIMER(sock,T308_1);
|
|
new_state(sock,ss_rel_req);
|
|
return;
|
|
case ss_rel_ind:
|
|
send_release_complete(sock->sig,sock->call_ref,0); /* @@@ */
|
|
free_sock(sock);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case as_identify:
|
|
if (sock->state != ss_indicated && sock->state != ss_proceeding)
|
|
break;
|
|
if (!atmpvc_addr_in_use(msg->pvc)) {
|
|
if (sock->sig->mode == sm_switch)
|
|
diag(COMPONENT,DIAG_FATAL,"No CI allocator (use -A)");
|
|
return;
|
|
}
|
|
if (sock->sig->mode == sm_net)
|
|
diag(COMPONENT,DIAG_FATAL,"CI allocation role conflict");
|
|
sock->pvc = msg->pvc;
|
|
if (send_call_proceeding(sock))
|
|
diag(COMPONENT,DIAG_FATAL,"s_c_p failed");
|
|
new_state(sock,ss_proceeding);
|
|
return;
|
|
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
|
|
case as_modify:
|
|
if (sock && !(sock->sig->uni & S_Q2963_1)) {
|
|
send_kernel(sock->id,kptr_null,as_okay,-ENOPROTOOPT,NULL,NULL,
|
|
NULL,NULL,NULL);
|
|
return;
|
|
}
|
|
if (sock && (sock->state == ss_mod_lcl ||
|
|
sock->state == ss_mod_req || sock->state == ss_mod_rcv ||
|
|
sock->state == ss_mod_fin_ok || sock->state == ss_mod_fin_fail ||
|
|
sock->state == ss_mod_fin_ack)) {
|
|
send_kernel(sock->id,kptr_null,as_okay,-EALREADY,NULL,NULL,
|
|
NULL,NULL,NULL);
|
|
return;
|
|
}
|
|
if (!sock || sock->state != ss_connected || !sock->owner) {
|
|
send_kernel(sock->id,kptr_null,as_okay,-EBADFD,NULL,NULL,NULL,
|
|
NULL,NULL);
|
|
return;
|
|
}
|
|
if (sock->qos.txtp.traffic_class != msg->qos.txtp.traffic_class ||
|
|
sock->qos.rxtp.traffic_class != msg->qos.rxtp.traffic_class ||
|
|
(sock->qos.txtp.traffic_class &&
|
|
(sock->qos.txtp.max_sdu != msg->qos.txtp.max_sdu)) ||
|
|
(sock->qos.rxtp.traffic_class &&
|
|
(sock->qos.rxtp.max_sdu != msg->qos.rxtp.max_sdu))) {
|
|
/* @@@ may do more checking */
|
|
send_kernel(sock->id,kptr_null,as_okay,-EINVAL,NULL,NULL,NULL,
|
|
NULL,NULL);
|
|
return;
|
|
}
|
|
sock->new_qos = msg->qos;
|
|
send_kernel(sock->id,kptr_null,as_modify,
|
|
ATM_MF_INC_RSV | ATM_MF_DEC_SHP,NULL,NULL,NULL,NULL,&msg->qos);
|
|
new_state(sock,ss_mod_lcl);
|
|
return;
|
|
case as_okay:
|
|
switch (sock ? sock->state : ss_null) {
|
|
case ss_mod_lcl:
|
|
send_modify_request(sock);
|
|
START_TIMER(sock,T360);
|
|
new_state(sock,ss_mod_req);
|
|
return;
|
|
case ss_mod_rcv:
|
|
send_modify_ack(sock);
|
|
sock->qos = sock->new_qos;
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
case ss_mod_fin_ok:
|
|
send_kernel(sock->id,kptr_null,as_okay,0,NULL,NULL,NULL,
|
|
NULL,NULL);
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
case ss_mod_fin_fail:
|
|
send_kernel(sock->id,kptr_null,as_okay,sock->error,NULL,
|
|
NULL,NULL,NULL,NULL);
|
|
sock->error = 0;
|
|
/* fall through */
|
|
case ss_mod_fin_ack:
|
|
new_state(sock,ss_connected);
|
|
/* fall through */
|
|
default:
|
|
return; /* ignore stray as_okay */
|
|
}
|
|
case as_error:
|
|
switch (sock ? sock->state : ss_null) {
|
|
case ss_mod_lcl:
|
|
send_kernel(sock->id,kptr_null,as_okay,msg->reply,NULL,
|
|
NULL,NULL,NULL,NULL);
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
case ss_mod_rcv:
|
|
send_modify_reject(sock,ATM_CV_RES_UNAVAIL);
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
case ss_mod_fin_ok:
|
|
diag(COMPONENT,DIAG_ERROR,"QOS commit failed");
|
|
send_kernel(sock->id,kptr_null,as_okay,0,NULL,NULL,NULL,
|
|
NULL,NULL);
|
|
/* @@@ clear call instead ? */
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
case ss_mod_fin_fail:
|
|
diag(COMPONENT,DIAG_ERROR,"QOS rollback failed");
|
|
send_kernel(sock->id,kptr_null,as_okay,sock->error,NULL,
|
|
NULL,NULL,NULL,NULL);
|
|
sock->error = 0;
|
|
/* @@@ clear call instead ? */
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
case ss_mod_fin_ack:
|
|
/* @@@ maybe we should even clear the call now */
|
|
diag(COMPONENT,DIAG_ERROR,"QOS commit failed");
|
|
new_state(sock,ss_connected);
|
|
return;
|
|
default:
|
|
return; /* ignore stray as_error */
|
|
}
|
|
#endif
|
|
default:
|
|
diag(COMPONENT,DIAG_WARN,"invalid message %d",(int) msg->type);
|
|
return;
|
|
}
|
|
diag(COMPONENT,DIAG_WARN,"message %s is incompatible with state %s (%d)",
|
|
as_name[msg->type],state_name[sock ? sock->state : ss_null],
|
|
(int) (sock ? sock->state : ss_null));
|
|
}
|
|
|
|
|
|
static void dispatch_listen(SOCKET *sock,struct atmsvc_msg *msg)
|
|
{
|
|
SOCKET *next;
|
|
|
|
if (!sock) {
|
|
diag(COMPONENT,DIAG_WARN,"message %s is incompatible with state %s "
|
|
"(%d)",as_name[msg->type],state_name[ss_null],ss_null);
|
|
return;
|
|
}
|
|
if (!(next = sock->listen)) {
|
|
diag(COMPONENT,DIAG_WARN,
|
|
"socket 0x%lx got accept/reject/identify with empty listen queue",
|
|
msg->vcc);
|
|
return;
|
|
}
|
|
sock->listen = next->listen;
|
|
if (sock->state == ss_listen_zombie && !sock->listen) free_sock(sock);
|
|
next->listen = NULL;
|
|
next->id = msg->vcc;
|
|
dispatch(next,msg);
|
|
}
|
|
|
|
|
|
void sync_addr(VPCI *vpci)
|
|
{
|
|
char buf[MAX_ATM_ADDR_LEN+1];
|
|
LOCAL_ADDR *walk;
|
|
|
|
(void) get_addr(vpci->itf,vpci->local_addr);
|
|
for (walk = vpci->local_addr; walk->state != ls_unused; walk++) {
|
|
if (atm2text(buf,MAX_ATM_ADDR_LEN+1,(struct sockaddr *)
|
|
&walk->addr,pretty) < 0) strcpy(buf,"<invalid>");
|
|
switch (walk->state) {
|
|
case ls_added:
|
|
diag(COMPONENT,DIAG_INFO,"Added local ATM address %s at "
|
|
"itf %d",buf,vpci->itf);
|
|
walk->state = ls_same;
|
|
break;
|
|
case ls_removed:
|
|
diag(COMPONENT,DIAG_INFO,"Removed local ATM address %s at "
|
|
"itf %d",buf,vpci->itf);
|
|
/*
|
|
* walk->state = ls_unused;
|
|
*
|
|
* This is probably wrong. What if we delete an entry from the middle of
|
|
* the list ? @@@
|
|
*/
|
|
/* @@@ delete SVCs using that address ? */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void from_kernel(struct atmsvc_msg *msg,int size)
|
|
{
|
|
void (*dispatcher)(SOCKET *,struct atmsvc_msg *);
|
|
SOCKET *curr;
|
|
|
|
if (msg->type == as_itf_notify) {
|
|
itf_reload(msg->pvc.sap_addr.itf);
|
|
return;
|
|
}
|
|
if (msg->type == as_terminate) {
|
|
#if 0 /* need to pass some ID ... @@@ */
|
|
if (mode != sm_switch) {
|
|
diag(COMPONENT,DIAG_ERROR,"Ignoring as_terminate received in %s "
|
|
"mode",mode == sm_user ? "USER" : "NETWORK");
|
|
return;
|
|
}
|
|
clear_all_calls(sig);
|
|
#endif
|
|
stop = 1;
|
|
diag(COMPONENT,DIAG_INFO,"Going down on as_terminate");
|
|
/*
|
|
* Fix this - we need to shut it down more gracefully.
|
|
*/
|
|
return;
|
|
}
|
|
if (!kptr_eq(&msg->listen_vcc,&kptr_null) && (msg->type == as_accept ||
|
|
msg->type == as_reject || msg->type == as_identify)) {
|
|
dispatcher = dispatch_listen;
|
|
for (curr = sockets; curr; curr = curr->next)
|
|
if (kptr_eq(&msg->listen_vcc,&curr->id) &&
|
|
(curr->state == ss_listening || curr->state == ss_listen_zombie))
|
|
break;
|
|
}
|
|
else {
|
|
dispatcher = dispatch;
|
|
for (curr = sockets; curr; curr = curr->next)
|
|
if (kptr_eq(&msg->vcc,&curr->id)) break;
|
|
}
|
|
diag(COMPONENT,DIAG_DEBUG,"FROM KERNEL: %s for socket %p (%s/%s) "
|
|
"in state %s",as_name[msg->type],curr,kptr_print(&msg->vcc),
|
|
kptr_print(&msg->listen_vcc),state_name[curr ? curr->state : ss_null]);
|
|
dispatcher(curr,msg);
|
|
}
|