📄 llc_station.c
字号:
.next_state = LLC_STATION_STATE_UP, .ev_actions = llc_stat_down_state_actions_2,};/* array of pointers; one to each transition */static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = { [0] = &llc_stat_down_state_trans_1, [1] = &llc_stat_down_state_trans_2, [2] = &llc_stat_state_trans_end,};/* UP STATE transitions *//* state transition for LLC_STATION_EV_DISABLE_REQ event */static llc_station_action_t llc_stat_up_state_actions_1[] = { [0] = llc_station_ac_report_status, /* STATION DOWN */ [1] = NULL,};static struct llc_station_state_trans llc_stat_up_state_trans_1 = { .ev = llc_stat_ev_disable_req, .next_state = LLC_STATION_STATE_DOWN, .ev_actions = llc_stat_up_state_actions_1,};/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */static llc_station_action_t llc_stat_up_state_actions_2[] = { [0] = llc_station_ac_send_xid_r, [1] = NULL,};static struct llc_station_state_trans llc_stat_up_state_trans_2 = { .ev = llc_stat_ev_rx_null_dsap_xid_c, .next_state = LLC_STATION_STATE_UP, .ev_actions = llc_stat_up_state_actions_2,};/* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */static llc_station_action_t llc_stat_up_state_actions_3[] = { [0] = llc_station_ac_send_test_r, [1] = NULL,};static struct llc_station_state_trans llc_stat_up_state_trans_3 = { .ev = llc_stat_ev_rx_null_dsap_test_c, .next_state = LLC_STATION_STATE_UP, .ev_actions = llc_stat_up_state_actions_3,};/* array of pointers; one to each transition */static struct llc_station_state_trans *llc_stat_up_state_trans [] = { [0] = &llc_stat_up_state_trans_1, [1] = &llc_stat_up_state_trans_2, [2] = &llc_stat_up_state_trans_3, [3] = &llc_stat_state_trans_end,};/* DUP ADDR CHK STATE transitions *//* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ * event */static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = { [0] = llc_station_ac_inc_xid_r_cnt_by_1, [1] = NULL,};static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = { .ev = llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq, .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, .ev_actions = llc_stat_dupaddr_state_actions_1,};/* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ * event */static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = { [0] = llc_station_ac_report_status, /* DUPLICATE ADDRESS FOUND */ [1] = NULL,};static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = { .ev = llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq, .next_state = LLC_STATION_STATE_DOWN, .ev_actions = llc_stat_dupaddr_state_actions_2,};/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = { [0] = llc_station_ac_send_xid_r, [1] = NULL,};static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = { .ev = llc_stat_ev_rx_null_dsap_xid_c, .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, .ev_actions = llc_stat_dupaddr_state_actions_3,};/* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY * event */static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = { [0] = llc_station_ac_start_ack_timer, [1] = llc_station_ac_inc_retry_cnt_by_1, [2] = llc_station_ac_set_xid_r_cnt_0, [3] = llc_station_ac_send_null_dsap_xid_c, [4] = NULL,};static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = { .ev = llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry, .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, .ev_actions = llc_stat_dupaddr_state_actions_4,};/* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY * event */static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = { [0] = llc_station_ac_report_status, /* STATION UP */ [1] = NULL,};static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = { .ev = llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry, .next_state = LLC_STATION_STATE_UP, .ev_actions = llc_stat_dupaddr_state_actions_5,};/* state transition for LLC_STATION_EV_DISABLE_REQ event */static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = { [0] = llc_station_ac_report_status, /* STATION DOWN */ [1] = NULL,};static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = { .ev = llc_stat_ev_disable_req, .next_state = LLC_STATION_STATE_DOWN, .ev_actions = llc_stat_dupaddr_state_actions_6,};/* array of pointers; one to each transition */static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = { [0] = &llc_stat_dupaddr_state_trans_6, /* Request */ [1] = &llc_stat_dupaddr_state_trans_4, /* Timer */ [2] = &llc_stat_dupaddr_state_trans_5, [3] = &llc_stat_dupaddr_state_trans_1, /* Receive frame */ [4] = &llc_stat_dupaddr_state_trans_2, [5] = &llc_stat_dupaddr_state_trans_3, [6] = &llc_stat_state_trans_end,};static struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = { [LLC_STATION_STATE_DOWN - 1] = { .curr_state = LLC_STATION_STATE_DOWN, .transitions = llc_stat_dwn_state_trans, }, [LLC_STATION_STATE_DUP_ADDR_CHK - 1] = { .curr_state = LLC_STATION_STATE_DUP_ADDR_CHK, .transitions = llc_stat_dupaddr_state_trans, }, [LLC_STATION_STATE_UP - 1] = { .curr_state = LLC_STATION_STATE_UP, .transitions = llc_stat_up_state_trans, },};/** * llc_exec_station_trans_actions - executes actions for transition * @trans: Address of the transition * @skb: Address of the event that caused the transition * * Executes actions of a transition of the station state machine. Returns * 0 if all actions complete successfully, nonzero otherwise. */static u16 llc_exec_station_trans_actions(struct llc_station_state_trans *trans, struct sk_buff *skb){ u16 rc = 0; llc_station_action_t *next_action = trans->ev_actions; for (; next_action && *next_action; next_action++) if ((*next_action)(skb)) rc = 1; return rc;}/** * llc_find_station_trans - finds transition for this event * @skb: Address of the event * * Search thru events of the current state of the station until list * exhausted or it's obvious that the event is not valid for the current * state. Returns the address of the transition if cound, %NULL otherwise. */static struct llc_station_state_trans * llc_find_station_trans(struct sk_buff *skb){ int i = 0; struct llc_station_state_trans *rc = NULL; struct llc_station_state_trans **next_trans; struct llc_station_state *curr_state = &llc_station_state_table[llc_main_station.state - 1]; for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) if (!next_trans[i]->ev(skb)) { rc = next_trans[i]; break; } return rc;}/** * llc_station_free_ev - frees an event * @skb: Address of the event * * Frees an event. */static void llc_station_free_ev(struct sk_buff *skb){ struct llc_station_state_ev *ev = llc_station_ev(skb); if (ev->type == LLC_STATION_EV_TYPE_PDU) kfree_skb(skb);}/** * llc_station_next_state - processes event and goes to the next state * @skb: Address of the event * * Processes an event, executes any transitions related to that event and * updates the state of the station. */static u16 llc_station_next_state(struct sk_buff *skb){ u16 rc = 1; struct llc_station_state_trans *trans; if (llc_main_station.state > LLC_NBR_STATION_STATES) goto out; trans = llc_find_station_trans(skb); if (trans) { /* got the state to which we next transition; perform the * actions associated with this transition before actually * transitioning to the next state */ rc = llc_exec_station_trans_actions(trans, skb); if (!rc) /* transition station to next state if all actions * execute successfully; done; wait for next event */ llc_main_station.state = trans->next_state; } else /* event not recognized in current state; re-queue it for * processing again at a later time; return failure */ rc = 0;out: llc_station_free_ev(skb); return rc;}/** * llc_station_service_events - service events in the queue * * Get an event from the station event queue (if any); attempt to service * the event; if event serviced, get the next event (if any) on the event * queue; if event not service, re-queue the event on the event queue and * attempt to service the next event; when serviced all events in queue, * finished; if don't transition to different state, just service all * events once; if transition to new state, service all events again. * Caller must hold llc_main_station.ev_q.lock. */static void llc_station_service_events(void){ struct sk_buff *skb; while ((skb = skb_dequeue(&llc_main_station.ev_q.list)) != NULL) llc_station_next_state(skb);}/** * llc_station_state_process: queue event and try to process queue. * @skb: Address of the event * * Queues an event (on the station event queue) for handling by the * station state machine and attempts to process any queued-up events. */static void llc_station_state_process(struct sk_buff *skb){ spin_lock_bh(&llc_main_station.ev_q.lock); skb_queue_tail(&llc_main_station.ev_q.list, skb); llc_station_service_events(); spin_unlock_bh(&llc_main_station.ev_q.lock);}static void llc_station_ack_tmr_cb(unsigned long timeout_data){ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); if (skb) { struct llc_station_state_ev *ev = llc_station_ev(skb); ev->type = LLC_STATION_EV_TYPE_ACK_TMR; llc_station_state_process(skb); }}/* * llc_station_rcv - send received pdu to the station state machine * @skb: received frame. * * Sends data unit to station state machine. */static void llc_station_rcv(struct sk_buff *skb){ struct llc_station_state_ev *ev = llc_station_ev(skb); ev->type = LLC_STATION_EV_TYPE_PDU; ev->reason = 0; llc_station_state_process(skb);}int __init llc_station_init(void){ u16 rc = -ENOBUFS; struct sk_buff *skb; struct llc_station_state_ev *ev; skb_queue_head_init(&llc_main_station.mac_pdu_q); skb_queue_head_init(&llc_main_station.ev_q.list); spin_lock_init(&llc_main_station.ev_q.lock); init_timer(&llc_main_station.ack_timer); llc_main_station.ack_timer.data = (unsigned long)&llc_main_station; llc_main_station.ack_timer.function = llc_station_ack_tmr_cb; llc_main_station.ack_timer.expires = jiffies + sysctl_llc_station_ack_timeout; skb = alloc_skb(0, GFP_ATOMIC); if (!skb) goto out; rc = 0; llc_set_station_handler(llc_station_rcv); ev = llc_station_ev(skb); memset(ev, 0, sizeof(*ev)); llc_main_station.maximum_retry = 1; llc_main_station.state = LLC_STATION_STATE_DOWN; ev->type = LLC_STATION_EV_TYPE_SIMPLE; ev->prim_type = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK; rc = llc_station_next_state(skb);out: return rc;}void __exit llc_station_exit(void){ llc_set_station_handler(NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -