void new_state(SOCKET *sock,STATE state) { diag(COMPONENT,DIAG_DEBUG,"socket %s enters state %s (UNI %s)", kptr_print(&sock->id),state_name[state],cs_name[state_map[state]]); sock->state = state; sock->call_state = state_map[state]; }
void to_kernel(struct atmsvc_msg *msg) { int wrote; diag("KERNEL",DIAG_DEBUG,"TO KERNEL: %s (%d) for %s/%s", as_name[msg->type],msg->reply,kptr_print(&msg->vcc), kptr_print(&msg->listen_vcc)); /* should be "IO" ... */ trace_kernel("TO KERNEL",msg); wrote = write(kernel,msg,sizeof(*msg)); if (wrote == sizeof(*msg)) return; if (wrote < 0) { perror("kernel write"); return; } diag(COMPONENT,DIAG_ERROR,"bad kernel write: wanted %d, wrote %d", sizeof(*msg),wrote); }
void on_T303(void *user) /* CONNECTING */ { SOCKET *sock = user; diag(COMPONENT,DIAG_DEBUG,"T303 on %s",kptr_print(&sock->id)); if (sock->state != ss_connecting) complain(sock,"T303"); SEND_ERROR(sock->id,-ETIMEDOUT); sock->conn_timer = NULL; free_sock(sock); }
void on_T360(void *user) { SOCKET *sock = user; diag(COMPONENT,DIAG_DEBUG,"T360 on %s",kptr_print(&sock->id)); if (sock->state != ss_mod_req) complain(sock,"T360"); send_release(sock,ATM_CV_TIMER_EXP,360); sock->conn_timer = NULL; START_TIMER(sock,T308_1); new_state(sock,ss_rel_req); }
void on_T313(void *user) /* ACCEPTING */ { SOCKET *sock = user; diag(COMPONENT,DIAG_DEBUG,"T313 on %s",kptr_print(&sock->id)); if (sock->state != ss_accepting) complain(sock,"T313"); send_release(sock,ATM_CV_TIMER_EXP,313); sock->conn_timer = NULL; START_TIMER(sock,T308_1); new_state(sock,ss_rel_req); }
void on_T308_1(void *user) /* WAIT_REL or REL_REQ */ { SOCKET *sock = user; diag(COMPONENT,DIAG_DEBUG,"T308_1 on %s",kptr_print(&sock->id)); if (sock->state != ss_wait_rel && sock->state != ss_rel_req) complain(sock,"T308_1"); send_release(sock,ATM_CV_TIMER_EXP,308); /* @@@ ? */ sock->conn_timer = NULL; START_TIMER(sock,T308_2); }
void on_T361(void *user) { SOCKET *sock = user; diag(COMPONENT,DIAG_DEBUG,"T361 on %s",kptr_print(&sock->id)); if (sock->state != ss_connected) complain(sock,"T361"); sock->qos = sock->new_qos; send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL,NULL, &sock->qos); sock->conn_timer = NULL; new_state(sock,ss_mod_fin_ack); }
void free_sock(SOCKET *sock) { SOCKET **walk; diag(COMPONENT,DIAG_DEBUG,"freeing socket %s@%p", kptr_print(&sock->id),sock); for (walk = &sockets; *walk != sock; walk = &(*walk)->next); if (!*walk) diag(COMPONENT,DIAG_FATAL, "INTERNAL ERROR: freeing non-existing socket %s", kptr_print(&sock->id)); *walk = sock->next; if (sock->conn_timer) { diag(COMPONENT,DIAG_ERROR,"socket %s has timer (%p) running", kptr_print(&sock->id),sock->conn_timer->callback); stop_timer(sock->conn_timer); } if (sock->listen) diag(COMPONENT,DIAG_ERROR,"socket %s has non-empty listen queue", kptr_print(&sock->id)); sock->state = ss_invalid; free(sock); }
static void process_uni(SIG_ENTITY *sig,void *msg) { SOCKET *curr; unsigned long call_ref; unsigned char mid; call_ref = q_fetch(&in_dsc,QF_call_ref)^0x800000; mid = q_fetch(&in_dsc,QF_msg_type); if (mid == ATM_MSG_REST_ACK) return; if (mid == ATM_MSG_RESTART) { /* 5.5.5.2 */ int rst_class; rst_class = q_fetch(&in_dsc,QF_rst_class); switch (rst_class) { case ATM_RST_IND_VC: { int vpi,vci; if (!q_present(&in_dsc,QG_conn_id)) { send_status(sig,NULL,call_ref,ATM_CV_MAND_IE_MISSING, ATM_IE_CONN_ID); return; } vpi = q_fetch(&in_dsc,QF_vpi); vci = q_fetch(&in_dsc,QF_vci); for (curr = sockets; curr; curr = curr->next) if (curr->sig == sig && curr->pvc.sap_addr.vpi == vpi && curr->pvc.sap_addr.vci == vci) break; if (!curr) { send_status(sig,NULL,call_ref,ATM_CV_INVALID_IE, ATM_IE_CONN_ID); return; } uni_call(curr,mid); send_restart_ack(sig,call_ref,vpi,vci); } break; case ATM_RST_ALL_VC: clear_all_calls(sig); send_restart_ack(sig,call_ref,0,0); break; default: send_status(sig,NULL,call_ref,ATM_CV_INVALID_IE,ATM_IE_RESTART); } return; } if (!(call_ref & 0x7fffff)) { diag(COMPONENT,DIAG_ERROR,"unrecognized global call ref"); return; } for (curr = sockets; curr; curr = curr->next) if (curr->sig == sig && curr->call_ref == call_ref) break; diag(COMPONENT,DIAG_DEBUG,"FROM SAAL %d.%d.%d: %s (0x%02X) CR 0x%06lx for " "%s",S_PVC(sig),mid2name(((unsigned char *) msg)[5]), ((unsigned char *) msg)[5],call_ref,curr ? kptr_print(&curr->id) : "?"); if (mid == ATM_MSG_SETUP) { if (!curr) setup_call(sig,call_ref); return; } if (mid == ATM_MSG_STATUS_ENQ) { send_status(sig,curr,call_ref,ATM_CV_RESP_STAT_ENQ); return; } if (curr && q_present(&in_dsc,QF_ep_ref) && mid != ATM_MSG_ADD_PARTY && mid != ATM_MSG_DROP_PARTY_ACK) { unsigned short ep_ref; ep_ref = cvt_ep_ref(sig,q_fetch(&in_dsc,QF_ep_ref)); if (curr->ep_ref != ep_ref) { send_drop_party_ack(sig,call_ref,ep_ref,ATM_CV_INV_EPR); return; } } if (!curr || curr->call_state == cs_null) { if (mid == ATM_MSG_REL_COMP) return; if (mid != ATM_MSG_STATUS) send_release_complete(sig,call_ref,ATM_CV_INV_CR); else if (q_fetch(&in_dsc,QF_call_state) != (int) cs_null) send_release_complete(sig,call_ref,ATM_CV_INCOMP_MSG); return; } uni_call(curr,mid); }
static void uni_call(SOCKET *sock,unsigned char mid) { char buffer[MAX_ATM_ADDR_LEN+1]; int error; switch (mid) { case ATM_MSG_STATUS: /* 5.5.6.12 */ { CALL_STATE state; /* * NOTE: T322 isn't implemented yet, but when it is, make sure * to only stop it on STATUS iff the cause is * ATM_CV_RESP_STAT_ENQ. Supplementary services break if * you stop on any STATUS. */ state = q_fetch(&in_dsc,QF_call_state); if (state == cs_null) break; /* clear call */ if (sock->call_state == cs_rel_req || sock->call_state == cs_rel_ind) return; if (state != sock->call_state) diag(COMPONENT,DIAG_WARN,"STATUS %s received in state %s", cs_name[state],cs_name[sock->call_state]); } return; default: ; } switch (mid) { case ATM_MSG_CALL_PROC: /* CONNECTING, WAIT_REL, REL_REQ */ if (sock->state == ss_wait_rel || sock->state == ss_rel_req) { send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG, ATM_MSG_CALL_PROC); return; } if (sock->state != ss_connecting) break; /* check for 2nd CALL_PROC @@@ */ STOP_TIMER(sock); if (q_present(&in_dsc,QG_conn_id)) { int vpci; vpci = q_fetch(&in_dsc,QF_vpi); sock->pvc.sap_family = AF_ATMPVC; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d", sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi, sock->pvc.sap_addr.vci); } START_TIMER(sock,T310); sock->call_state = cs_out_proc; return; case ATM_MSG_CONNECT: /* CONNECTING, REL_REQ */ if (sock->state == ss_rel_req) { send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,ATM_MSG_CONNECT); return; } if (sock->state != ss_connecting) break; STOP_TIMER(sock); if (q_present(&in_dsc,QG_conn_id)) { int vpci; vpci = q_fetch(&in_dsc,QF_vpi); sock->pvc.sap_family = AF_ATMPVC; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d/%d.%d", sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi, sock->pvc.sap_addr.vci); } error = 0; if (!sock->pvc.sap_addr.vpi && !sock->pvc.sap_addr.vci) error = -EPROTO; /* more problems */ if (error) { set_error(sock,error); send_release(sock,0); /* @@@ cause follows reason ??? */ START_TIMER(sock,T308_1); new_state(sock,ss_rel_req); return; } send_connect_ack(sock); /* @@@ fill in sock->remote */ /* @@@ fill in traffic parameters */ send_kernel(sock->id,kptr_null,as_okay,0,&sock->pvc,NULL, &sock->local,&sock->sap,&sock->qos); new_state(sock,ss_connected); #if defined(Q2963_1) || defined(DYNAMIC_UNI) sock->owner = 1; #endif if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &sock->remote,0) < 0) strcpy(buffer,"<invalid>"); diag(COMPONENT,DIAG_INFO,"Active open succeeded (CR 0x%06X, " "ID %s, to %s)",sock->call_ref,kptr_print(&sock->id),buffer); return; case ATM_MSG_CONN_ACK: /* ACCEPTING, WAIT_REL, REL_REQ */ diag(COMPONENT,DIAG_DEBUG,"CA vpi.vci=%d.%d", sock->pvc.sap_addr.vpi,sock->pvc.sap_addr.vci); if (sock->state == ss_wait_rel || sock->state == ss_rel_req) { send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG, ATM_MSG_CONN_ACK); return; } if (sock->state != ss_accepting) break; STOP_TIMER(sock); send_kernel(sock->id,kptr_null,as_okay,0,NULL,NULL,&sock->local, &sock->sap,NULL); new_state(sock,ss_connected); #if defined(Q2963_1) || defined(DYNAMIC_UNI) sock->owner = 0; #endif if (atm2text(buffer,MAX_ATM_ADDR_LEN+1, (struct sockaddr *) &sock->remote,0) < 0) strcpy(buffer,"<invalid>"); diag(COMPONENT,DIAG_INFO,"Passive open succeeded (CR 0x%06X, " "ID %s, from %s)",sock->call_ref,kptr_print(&sock->id),buffer); return; case ATM_MSG_RELEASE: /* all states */ { unsigned char cause; cause = q_fetch(&in_dsc,QF_cause); diag(COMPONENT,DIAG_DEBUG,"Cause %d (%s)",cause,cause > 127 ? "invalid cause" : cause_text[cause]); } switch (sock->state) { case ss_connecting: set_error(sock,-ECONNREFUSED); /* fall through */ case ss_accepting: set_error(sock,-ECONNRESET); /* ERESTARTSYS ? */ send_release_complete(sock->sig,sock->call_ref,0); SEND_ERROR(sock->id,sock->error); STOP_TIMER(sock); free_sock(sock); return; case ss_rel_req: send_close(sock); /* fall through */ case ss_wait_rel: STOP_TIMER(sock); free_sock(sock); return; #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: diag(COMPONENT,DIAG_INFO,"Passive close (CR 0x%06X)", sock->call_ref); #if defined(Q2963_1) || defined(DYNAMIC_UNI) if (timer_handler(sock->conn_timer) == on_T361) STOP_TIMER(sock); #endif send_close(sock); new_state(sock,ss_rel_ind); return; case ss_indicated: /* fall through */ case ss_proceeding: send_release_complete(sock->sig,sock->call_ref,0); new_state(sock,ss_zombie); /* fall through */ case ss_rel_ind: return; default: send_release_complete(sock->sig,sock->call_ref,0); /* @@@ should be ATM_CV_INCOMP_MSG */ break; } break; case ATM_MSG_RESTART: set_error(sock,-ENETRESET); /* fall through */ case ATM_MSG_STATUS: /* fall through when clearing */ case ATM_MSG_REL_COMP: /* basically any state (except LISTENING and ZOMBIE) */ { unsigned char cause; if (mid != ATM_MSG_REL_COMP || !q_present(&in_dsc,QF_cause)) cause = 0; else { cause = q_fetch(&in_dsc,QF_cause); diag(COMPONENT,DIAG_DEBUG,"Cause %d (%s)",cause, cause > 127 ? "invalid cause" : cause_text[cause]); } switch (sock->state) { case ss_connecting: set_error(sock,cause == ATM_CV_UNALLOC ? -EADDRNOTAVAIL : cause == ATM_CV_RES_UNAVAIL || #if defined(UNI31) || defined(UNI40) || defined(DYNAMIC_UNI) cause == ATM_CV_UCR_UNAVAIL_NEW || #endif cause == ATM_CV_NO_ROUTE_DEST ? -EHOSTUNREACH : cause == ATM_CV_NUM_CHANGED ? -EREMCHG : cause == ATM_CV_DEST_OOO ? -EHOSTDOWN : -ECONNREFUSED); /* fall through */ case ss_accepting: set_error(sock,-ECONNRESET); /* ERESTARTSYS ? */ SEND_ERROR(sock->id,sock->error); STOP_TIMER(sock); free_sock(sock); return; case ss_rel_req: send_close(sock); /* fall through */ case ss_wait_rel: STOP_TIMER(sock); free_sock(sock); return; #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: diag(COMPONENT,DIAG_INFO,"Passive close (CR 0x%06X)", sock->call_ref); #if defined(Q2963_1) || defined(DYNAMIC_UNI) if (timer_handler(sock->conn_timer) == on_T361) STOP_TIMER(sock); #endif send_close(sock); /* fall through */ case ss_rel_ind: new_state(sock,ss_wait_close); return; case ss_indicated: /* fall through */ case ss_proceeding: new_state(sock,ss_zombie); return; default: break; } break; /* fail */ } case ATM_MSG_ALERTING: /* * We basically ignore this junk message, except for the connection * identifier it may carry. */ if (q_present(&in_dsc,QG_conn_id)) { int vpci; vpci = q_fetch(&in_dsc,QF_vpi); sock->pvc.sap_family = AF_ATMPVC; sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci); sock->pvc.sap_addr.vpi = vpci; sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci); diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d", sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi, sock->pvc.sap_addr.vci); } return; case ATM_MSG_NOTIFY: /* silently ignore this junk */ return; #if defined(Q2963_1) || defined(DYNAMIC_UNI) /* * Buglet ahead: should actually test "call_state" */ case ATM_MSG_MODIFY_REQ: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_connected || sock->owner) break; sock->new_qos = sock->qos; if (q_present(&in_dsc,QF_fw_pcr_01)) sock->new_qos.rxtp.max_pcr = q_fetch(&in_dsc,QF_fw_pcr_01); if (q_present(&in_dsc,QF_bw_pcr_01)) sock->new_qos.txtp.max_pcr = q_fetch(&in_dsc,QF_bw_pcr_01); send_kernel(sock->id,kptr_null,as_modify, ATM_MF_INC_RSV | ATM_MF_DEC_RSV | ATM_MF_DEC_SHP, NULL,NULL,NULL,NULL,&sock->new_qos); new_state(sock,ss_mod_rcv); return; case ATM_MSG_MODIFY_ACK: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_mod_req) break; STOP_TIMER(sock); sock->qos = sock->new_qos; if (q_present(&in_dsc,QG_bbrt)) send_conn_avail(sock); send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL, NULL,&sock->qos); new_state(sock,ss_mod_fin_ok); return; case ATM_MSG_MODIFY_REJ: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_mod_req) break; STOP_TIMER(sock); sock->error = -EAGAIN; send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL, NULL,&sock->qos); new_state(sock,ss_mod_fin_fail); return; case ATM_MSG_CONN_AVAIL: if (!(sock->sig->uni & S_Q2963_1)) goto _default; if (sock->state != ss_connected || sock->owner) break; STOP_TIMER(sock); send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL, NULL,&sock->qos); new_state(sock,ss_mod_fin_ack); return; _default: /* jump here if we don't want to understand a message */ #endif default: diag(COMPONENT,DIAG_WARN,"Bad signaling message %d",mid); send_status(sock->sig,sock,0,ATM_CV_UNKNOWN_MSG_TYPE,mid); return; } diag(COMPONENT,DIAG_WARN, "Signaling message %s is incompatible with state %s/%s (%d?%d)", mid2name(mid),state_name[sock->state],cs_name[sock->call_state], (int) sock->state,(int) sock->call_state); send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,mid); }