/* ITU-T G.964 Section 14.1.3.2.2 ISDN user port FSM - LE */ /***********************************************************************/ /* internal data structures */ /***********************************************************************/ #include #include #include "v5x_internal.h" #include "v5x_protocol.h" #include "v5x_le_ctrl_fsm.h" #include "v5x_le_management.h" #include "logging.h" #define S(x) (1 << (x)) /***********************************************************************/ /* state names, event names, primitives, ... */ /***********************************************************************/ /* 14.1.3.2.2 ISDN user port FSM - LE(ISDN port) */ enum v5x_le_isdn_port_state { V5X_LE_UP_I_S_LE10_NOP_BLOCKED, /* LE1.0 */ V5X_LE_UP_I_S_LE11_NOP_LOCAL_UNBLOCK, /* LE1.1 */ V5X_LE_UP_I_S_LE12_NOP_REMOTE_UNBLOCK, /* LE1.2 */ V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, /* LE2.0 */ V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED, /* LE2.1 */ V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED, /* LE2.2 */ }; /* 14.2.3.2.2 PSTN user port FSM - LE(PSTN port) */ enum v5x_le_pstn_port_state { V5X_LE_UP_P_S_LE10_NOP_BLOCKED, /* LE1.0 */ V5X_LE_UP_P_S_LE11_NOP_LOCAL_UNBLOCK, /* LE1.1 */ V5X_LE_UP_P_S_LE12_NOP_REMOTE_UNBLOCK, /* LE1.2 */ V5X_LE_UP_P_S_LE20_OPERATIONAL, /* LE2.0 */ }; enum v5x_le_ctrl_port_fsm_event { /* inbound function elements from AN (Table 34/G.964) */ V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND, V5X_CUP_LE_FE103_DS_ACTIVATED_IND, V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND, V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND, V5X_CUP_LE_FE202_UNBLOCK, V5X_CUP_LE_FE204_BLOCK_CMD, V5X_CUP_LE_FE205_BLOCK_REQ, V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND, /* inbound primitives from Mgmt (Table 35/G.964) */ V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ, V5X_CUP_LE_MPH_BI_BLOCK_CMD, V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ, V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ, V5X_CUP_LE_MPH_DB_BLOCK_DCHAN_REQ, V5X_CUP_LE_MPH_DU_BLOCK_DCHAN_REQ, }; static const struct value_string v5x_le_ctrl_port_fsm_event_names[] = { { V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND, "FE102 Activation by user indication" }, { V5X_CUP_LE_FE103_DS_ACTIVATED_IND, "FE103 DS Activated indication" }, { V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND, "FE104 Access activated indication" }, { V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND, "FE106 Access deactivated indication" }, { V5X_CUP_LE_FE202_UNBLOCK, "FE202 Unblock request or ack" }, { V5X_CUP_LE_FE204_BLOCK_CMD, "FE204 Block command" }, { V5X_CUP_LE_FE205_BLOCK_REQ, "FE205 Block request" }, { V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND, "FE206 Performance grading info" }, { V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ, "MPH-UBR Unblock request" }, { V5X_CUP_LE_MPH_BI_BLOCK_CMD, "MPH-BI Block command" }, { V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ, "MPH-AR Activate access" }, { V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ, "MPH-DR Deactivate access" }, { V5X_CUP_LE_MPH_DB_BLOCK_DCHAN_REQ, "MPH-DB Block D-channel" }, { V5X_CUP_LE_MPH_DU_BLOCK_DCHAN_REQ, "MPH-DU Unblock D-channel" }, { 0, NULL } }; /***********************************************************************/ /* Messages to other layers */ /***********************************************************************/ /* send message to management layer */ static void mph_rcv(struct osmo_fsm_inst *fi, enum v5x_mph_prim prim, uint8_t perf_grading) { struct v5x_user_port *v5up = fi->priv; v5x_le_port_mph_rcv(v5up, prim, perf_grading); } static void ctrl_snd(struct osmo_fsm_inst *fi, enum v5x_ctrl_func_el prim) { struct v5x_user_port *v5up = fi->priv; v5x_le_ctrl_port_snd(v5up, prim); } /***********************************************************************/ /* ISDN port state FSM */ /***********************************************************************/ static void isdn_up_le10_blocked(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND: case V5X_CUP_LE_FE103_DS_ACTIVATED_IND: case V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND: case V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ: case V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE11_NOP_LOCAL_UNBLOCK, 0, 0); /* Send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: /* Send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE12_NOP_REMOTE_UNBLOCK, 0, 0); /* Send MPU-UBR */ mph_rcv(fi, MPH_UBR, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: case V5X_CUP_LE_FE205_BLOCK_REQ: /* ignore */ break; default: OSMO_ASSERT(0); } } static void isdn_up_le11_local_unblock(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED, 0, 0); /* send MPG-AWI */ mph_rcv(fi, MPH_AWI, 0); break; case V5X_CUP_LE_FE103_DS_ACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED, 0, 0); /* send MPH-AI */ mph_rcv(fi, MPH_AI, 0); break; case V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ: case V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: /* send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, 0, 0); /* send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* send MPH-BI */ mph_rcv(fi, MPH_BI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* ignore */ break; default: OSMO_ASSERT(0); } } static void isdn_up_le12_remote_unblock(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_FE103_DS_ACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ: case V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, 0, 0); /* send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); /* send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: /* send MPH-UBR */ mph_rcv(fi, MPH_UBR, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* send MPH-BI */ mph_rcv(fi, MPH_BI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* ignore */ break; default: OSMO_ASSERT(0); } } /* LE 2.0 Operational deactivated */ static void isdn_up_le20_op_deact(struct osmo_fsm_inst *fi, uint32_t event, void *data) { switch (event) { case V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED, 0, 0); /* Send FE101 */ ctrl_snd(fi, V5X_CTRL_FE101_ACTIVATE_ACCESS); break; case V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED, 0, 0); /* Send MPH-AWI */ mph_rcv(fi, MPH_AWI, 0); break; case V5X_CUP_LE_FE103_DS_ACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED, 0, 0); /* Send MPH-AI */ mph_rcv(fi, MPH_AI, 0); break; case V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ: /* Send FE105 */ ctrl_snd(fi, V5X_CTRL_FE105_DEACTIVATE_ACCESS); break; case V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND: /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: /* Send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* Send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: /* Send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* Send MPH-BI */ mph_rcv(fi, MPH_BI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* Send MPH-BR */ mph_rcv(fi, MPH_BR, 0); break; case V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND: /* Send MPH-GI */ mph_rcv(fi, MPH_GI, *(uint8_t *)data); break; default: OSMO_ASSERT(0); } } /* LE 2.1 Access initiated */ static void isdn_up_le21_op_act_init(struct osmo_fsm_inst *fi, uint32_t event, void *data) { switch (event) { case V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ: case V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND: /* ignore */ break; case V5X_CUP_LE_FE103_DS_ACTIVATED_IND: /* Send MPH-DSAI */ mph_rcv(fi, MPH_DSAI, 0); break; case V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED, 0, 0); /* Send MPH-AI */ mph_rcv(fi, MPH_AI, 0); break; case V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, 0, 0); /* Send FE105 */ ctrl_snd(fi, V5X_CTRL_FE105_DEACTIVATE_ACCESS); /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, 0, 0); /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: /* Send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* Send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: /* Send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* Send MPH-BI */ mph_rcv(fi, MPH_BI, 0); /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* Send MPH-BR */ mph_rcv(fi, MPH_BR, 0); break; case V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND: /* Send MPH-GI */ mph_rcv(fi, MPH_GI, *(uint8_t *)data); break; default: OSMO_ASSERT(0); } } /* LE 2.2 Access activated */ static void isdn_up_le22_op_acc_act(struct osmo_fsm_inst *fi, uint32_t event, void *data) { switch (event) { case V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND: /* ignore */ break; case V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, 0, 0); /* Send FE105 */ ctrl_snd(fi, V5X_CTRL_FE105_DEACTIVATE_ACCESS); /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED, 0, 0); /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: /* Send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); /* Send MPH-AI */ mph_rcv(fi, MPH_AI, 0); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* Send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: /* Send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_I_S_LE10_NOP_BLOCKED, 0, 0); /* Send MPH-BI */ mph_rcv(fi, MPH_BI, 0); /* Send MPH-DI */ mph_rcv(fi, MPH_DI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* Send MPH-BR */ mph_rcv(fi, MPH_BR, 0); break; case V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND: /* Send MPH-GI */ mph_rcv(fi, MPH_GI, *(uint8_t *)data); break; case V5X_CUP_LE_MPH_DB_BLOCK_DCHAN_REQ: /* Send FE207 */ ctrl_snd(fi, V5X_CTRL_FE207_D_CHANNEL_BLOCK); break; case V5X_CUP_LE_MPH_DU_BLOCK_DCHAN_REQ: /* Send FE208 */ ctrl_snd(fi, V5X_CTRL_FE208_D_CHANNEL_UNBLOCK); break; default: OSMO_ASSERT(0); } } /* Table 38/G.964 LE (ISDN port) FSM for ISDN basic access user ports */ static const struct osmo_fsm_state v5x_le_ctrl_isdn_port_fsm_states[] = { [V5X_LE_UP_I_S_LE10_NOP_BLOCKED] = { .name = "Blocked (LE1.0)", .in_event_mask = S(V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND) | S(V5X_CUP_LE_FE103_DS_ACTIVATED_IND) | S(V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND) | S(V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND) | S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_I_S_LE11_NOP_LOCAL_UNBLOCK) | S(V5X_LE_UP_I_S_LE12_NOP_REMOTE_UNBLOCK), .action = isdn_up_le10_blocked, }, [V5X_LE_UP_I_S_LE11_NOP_LOCAL_UNBLOCK] = { .name = "Local unblock (LE1.1)", .in_event_mask = S(V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND) | S(V5X_CUP_LE_FE103_DS_ACTIVATED_IND) | S(V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND) | S(V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND) | S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED) | S(V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED) | S(V5X_LE_UP_I_S_LE10_NOP_BLOCKED) | S(V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED), .action = isdn_up_le11_local_unblock, }, [V5X_LE_UP_I_S_LE12_NOP_REMOTE_UNBLOCK] = { .name = "Remote unblock (LE1.2)", .in_event_mask = S(V5X_CUP_LE_FE103_DS_ACTIVATED_IND) | S(V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND) | S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED) | S(V5X_LE_UP_I_S_LE10_NOP_BLOCKED), .action = isdn_up_le12_remote_unblock, }, [V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED] = { .name = "Operational deactivated (LE2.0)", .in_event_mask = S(V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND) | S(V5X_CUP_LE_FE103_DS_ACTIVATED_IND) | S(V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND) | S(V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND) | S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ) | S(V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND), .out_state_mask = S(V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED) | S(V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED) | S(V5X_LE_UP_I_S_LE10_NOP_BLOCKED), .action = isdn_up_le20_op_deact, }, [V5X_LE_UP_I_S_LE21_OP_ACTIVATION_INITIATED] = { .name = "Activation initiated (LE2.1)", .in_event_mask = S(V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND) | S(V5X_CUP_LE_FE103_DS_ACTIVATED_IND) | S(V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND) | S(V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND) | S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED) | S(V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED) | S(V5X_LE_UP_I_S_LE10_NOP_BLOCKED), .action = isdn_up_le21_op_act_init, }, [V5X_LE_UP_I_S_LE22_OP_ACCESS_ACTIVATED] = { .name = "Access activated (LE2.2)", .in_event_mask = S(V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND) | S(V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ) | S(V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND) | S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ) | S(V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND) | S(V5X_CUP_LE_MPH_DB_BLOCK_DCHAN_REQ) | S(V5X_CUP_LE_MPH_DU_BLOCK_DCHAN_REQ), .out_state_mask = S(V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED) | S(V5X_LE_UP_I_S_LE10_NOP_BLOCKED), .action = isdn_up_le22_op_acc_act, }, }; struct osmo_fsm v5x_le_ctrl_isdn_port_fsm = { .name = "V5X_CTRL_ISDN", .states = v5x_le_ctrl_isdn_port_fsm_states, .num_states = ARRAY_SIZE(v5x_le_ctrl_isdn_port_fsm_states), .allstate_event_mask = 0, .allstate_action = NULL, .cleanup = NULL, .log_subsys = DV5PORT, .event_names = v5x_le_ctrl_port_fsm_event_names, }; struct osmo_fsm_inst *v5x_le_port_isdn_create(struct v5x_user_port *v5up, uint16_t nr) { struct osmo_fsm_inst *fi; OSMO_ASSERT(v5up); fi = osmo_fsm_inst_alloc(&v5x_le_ctrl_isdn_port_fsm, v5up, v5up, LOGL_DEBUG, NULL); if (!fi) return NULL; osmo_fsm_inst_update_id_f(fi, "%d", nr); return fi; } bool v5x_le_port_isdn_is_operational(struct osmo_fsm_inst *fi) { return (fi->state >= V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED); } void v5x_le_port_isdn_block(struct osmo_fsm_inst *fi) { LOGP(DV5PORT, LOGL_DEBUG, "Put ISDN port into blocked state\n"); fi->state = V5X_LE_UP_I_S_LE10_NOP_BLOCKED; } void v5x_le_port_isdn_unblock(struct osmo_fsm_inst *fi) { LOGP(DV5PORT, LOGL_DEBUG, "Put ISDN port into unblocked state\n"); fi->state = V5X_LE_UP_I_S_LE20_OP_OPERATIONAL_DEACTIVTED; } const char *v5x_le_port_isdn_state_name(struct osmo_fsm_inst *fi) { return v5x_le_ctrl_isdn_port_fsm_states[fi->state].name; } /***********************************************************************/ /* PSTN port state FSM */ /***********************************************************************/ static void pstn_up_le10_blocked(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE11_NOP_LOCAL_UNBLOCK, 0, 0); /* Send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: /* Send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE12_NOP_REMOTE_UNBLOCK, 0, 0); /* Send MPU-UBR */ mph_rcv(fi, MPH_UBR, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: case V5X_CUP_LE_FE205_BLOCK_REQ: /* ignore */ break; default: OSMO_ASSERT(0); } } static void pstn_up_le11_local_unblock(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: /* send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE10_NOP_BLOCKED, 0, 0); /* send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE20_OPERATIONAL, 0, 0); /* send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE10_NOP_BLOCKED, 0, 0); /* send MPH-BI */ mph_rcv(fi, MPH_BI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* ignore */ break; default: OSMO_ASSERT(0); } } static void pstn_up_le12_remote_unblock(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE20_OPERATIONAL, 0, 0); /* send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); /* send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE10_NOP_BLOCKED, 0, 0); /* send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: /* send MPH-UBR */ mph_rcv(fi, MPH_UBR, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE10_NOP_BLOCKED, 0, 0); /* send MPH-BI */ mph_rcv(fi, MPH_BI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* ignore */ break; default: OSMO_ASSERT(0); } } /* LE 2.0 Operational deactivated */ static void pstn_up_le20_operational(struct osmo_fsm_inst *fi, uint32_t event, void __attribute__((unused)) *data) { switch (event) { case V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ: /* Send FE201 */ ctrl_snd(fi, V5X_CTRL_FE201_UNBLOCK); break; case V5X_CUP_LE_MPH_BI_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE10_NOP_BLOCKED, 0, 0); /* Send FE203 */ ctrl_snd(fi, V5X_CTRL_FE203_BLOCK); break; case V5X_CUP_LE_FE202_UNBLOCK: /* Send MPH-UBI */ mph_rcv(fi, MPH_UBI, 0); break; case V5X_CUP_LE_FE204_BLOCK_CMD: osmo_fsm_inst_state_chg(fi, V5X_LE_UP_P_S_LE10_NOP_BLOCKED, 0, 0); /* Send MPH-BI */ mph_rcv(fi, MPH_BI, 0); break; case V5X_CUP_LE_FE205_BLOCK_REQ: /* Send MPH-BR */ mph_rcv(fi, MPH_BR, 0); break; default: OSMO_ASSERT(0); } } /* Table 43/G.964 LE (ISDN port) FSM for PSTN user ports */ static const struct osmo_fsm_state v5x_le_ctrl_pstn_port_fsm_states[] = { [V5X_LE_UP_P_S_LE10_NOP_BLOCKED] = { .name = "Blocked (LE1.0)", .in_event_mask = S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_P_S_LE11_NOP_LOCAL_UNBLOCK) | S(V5X_LE_UP_P_S_LE12_NOP_REMOTE_UNBLOCK), .action = pstn_up_le10_blocked, }, [V5X_LE_UP_P_S_LE11_NOP_LOCAL_UNBLOCK] = { .name = "Local unblock (LE1.1)", .in_event_mask = S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_P_S_LE10_NOP_BLOCKED) | S(V5X_LE_UP_P_S_LE20_OPERATIONAL), .action = pstn_up_le11_local_unblock, }, [V5X_LE_UP_P_S_LE12_NOP_REMOTE_UNBLOCK] = { .name = "Remote unblock (LE1.2)", .in_event_mask = S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_P_S_LE20_OPERATIONAL) | S(V5X_LE_UP_P_S_LE10_NOP_BLOCKED), .action = pstn_up_le12_remote_unblock, }, [V5X_LE_UP_P_S_LE20_OPERATIONAL] = { .name = "Operational (LE2.0)", .in_event_mask = S(V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ) | S(V5X_CUP_LE_MPH_BI_BLOCK_CMD) | S(V5X_CUP_LE_FE202_UNBLOCK) | S(V5X_CUP_LE_FE204_BLOCK_CMD) | S(V5X_CUP_LE_FE205_BLOCK_REQ), .out_state_mask = S(V5X_LE_UP_P_S_LE10_NOP_BLOCKED), .action = pstn_up_le20_operational, }, }; struct osmo_fsm v5x_le_ctrl_pstn_port_fsm = { .name = "V5X_CTRL_PSTN", .states = v5x_le_ctrl_pstn_port_fsm_states, .num_states = ARRAY_SIZE(v5x_le_ctrl_pstn_port_fsm_states), .allstate_event_mask = 0, .allstate_action = NULL, .cleanup = NULL, .log_subsys = DV5PORT, .event_names = v5x_le_ctrl_port_fsm_event_names, }; struct osmo_fsm_inst *v5x_le_port_pstn_create(struct v5x_user_port *v5up, uint16_t nr) { struct osmo_fsm_inst *fi; OSMO_ASSERT(v5up); fi = osmo_fsm_inst_alloc(&v5x_le_ctrl_pstn_port_fsm, v5up, v5up, LOGL_DEBUG, NULL); if (!fi) return NULL; osmo_fsm_inst_update_id_f(fi, "%d", nr); return fi; } void v5x_le_port_init(void) { int rc; rc = osmo_fsm_register(&v5x_le_ctrl_isdn_port_fsm); OSMO_ASSERT(!rc); rc = osmo_fsm_register(&v5x_le_ctrl_pstn_port_fsm); OSMO_ASSERT(!rc); LOGP(DV5PORT, LOGL_NOTICE, "Using V5x port control protocol\n"); } bool v5x_le_port_pstn_is_operational(struct osmo_fsm_inst *fi) { return (fi->state >= V5X_LE_UP_P_S_LE20_OPERATIONAL); } void v5x_le_port_pstn_block(struct osmo_fsm_inst *fi) { LOGP(DV5PORT, LOGL_DEBUG, "Put PSTN port into blocked state\n"); fi->state = V5X_LE_UP_P_S_LE10_NOP_BLOCKED; } void v5x_le_port_pstn_unblock(struct osmo_fsm_inst *fi) { LOGP(DV5PORT, LOGL_DEBUG, "Put PSTN port into unblocked state\n"); fi->state = V5X_LE_UP_P_S_LE20_OPERATIONAL; } const char *v5x_le_port_pstn_state_name(struct osmo_fsm_inst *fi) { return v5x_le_ctrl_pstn_port_fsm_states[fi->state].name; } /*********************************************************************** * Messages from other layers ***********************************************************************/ /* message from DL layer */ void v5x_le_port_pstn_fe_rcv(struct v5x_user_port *v5up, uint8_t cfe) { struct osmo_fsm_inst *fi = v5up->port_fi; enum v5x_le_ctrl_port_fsm_event event; switch (cfe) { case V5X_CTRL_FE201_UNBLOCK: // actually FE202 event = V5X_CUP_LE_FE202_UNBLOCK; break; case V5X_CTRL_FE203_BLOCK: // actually FE204 event = V5X_CUP_LE_FE204_BLOCK_CMD; break; case V5X_CTRL_FE205_BLOCK_REQ: event = V5X_CUP_LE_FE205_BLOCK_REQ; break; default: LOGP(DV5PORT, LOGL_NOTICE, "Received cfe %d not valid at this protocol\n", cfe); } /* send event to FSM */ osmo_fsm_inst_dispatch(fi, event, NULL); } /* message from DL layer */ void v5x_le_port_isdn_fe_rcv(struct v5x_user_port *v5up, uint8_t cfe, uint8_t perf_grading) { enum v5x_le_ctrl_port_fsm_event event; switch (cfe) { case V5X_CTRL_FE102_ACT_INIT_BY_USER: event = V5X_CUP_LE_FE102_ACTIV_INIT_USER_IND; break; case V5X_CTRL_FE103_DS_ACTIVATED: event = V5X_CUP_LE_FE103_DS_ACTIVATED_IND; break; case V5X_CTRL_FE104_ACCESS_ACTIVATED: event = V5X_CUP_LE_FE104_ACCESS_ACTIVATED_IND; break; case V5X_CTRL_FE106_ACCESS_DEACTIVATED: event = V5X_CUP_LE_FE106_ACCESS_DEACTIVATED_IND; break; case V5X_CTRL_FE201_UNBLOCK: // actually FE202 event = V5X_CUP_LE_FE202_UNBLOCK; break; case V5X_CTRL_FE203_BLOCK: // actually FE204 event = V5X_CUP_LE_FE204_BLOCK_CMD; break; case V5X_CTRL_FE205_BLOCK_REQ: event = V5X_CUP_LE_FE205_BLOCK_REQ; break; case V5X_CTRL_FE206_PERFORMANCE_GRADING: event = V5X_CUP_LE_FE206_PREFORMANCE_GRADING_IND; break; default: LOGP(DV5PORT, LOGL_NOTICE, "Received cfe %d not valid at this protocol\n", cfe); break; } /* send event to FSM */ osmo_fsm_inst_dispatch(v5up->port_fi, event, &perf_grading); } /* message from management layer */ void v5x_port_mph_snd(struct v5x_user_port *v5up, enum v5x_mph_prim prim) { struct osmo_fsm_inst *fi = v5up->port_fi; enum v5x_le_ctrl_port_fsm_event event; switch (prim) { case MPH_UBR: event = V5X_CUP_LE_MPH_UBR_UNBLOCK_REQ; break; case MPH_BI: event = V5X_CUP_LE_MPH_BI_BLOCK_CMD; break; case MPH_AR: event = V5X_CUP_LE_MPH_AR_ACTIVATE_ACCESS_REQ; break; case MPH_DR: event = V5X_CUP_LE_MPH_DR_DEACTIVATE_ACCESS_REQ; break; case MPH_DB: event = V5X_CUP_LE_MPH_DB_BLOCK_DCHAN_REQ; break; case MPH_DU: event = V5X_CUP_LE_MPH_DU_BLOCK_DCHAN_REQ; break; default: LOGP(DV5PORT, LOGL_NOTICE, "Got invalid prim %d at this protocol\n", prim); return; } /* send event to FSM */ osmo_fsm_inst_dispatch(fi, event, NULL); }