11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * llc_station.c - station component of LLC 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1997 by Procom Technology, Inc. 51da177e4SLinus Torvalds * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program can be redistributed or modified under the terms of the 81da177e4SLinus Torvalds * GNU General Public License as published by the Free Software Foundation. 91da177e4SLinus Torvalds * This program is distributed without any warranty or implied warranty 101da177e4SLinus Torvalds * of merchantability or fitness for a particular purpose. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * See the GNU General Public License for more details. 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds #include <linux/config.h> 151da177e4SLinus Torvalds #include <linux/init.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <net/llc.h> 181da177e4SLinus Torvalds #include <net/llc_sap.h> 191da177e4SLinus Torvalds #include <net/llc_conn.h> 201da177e4SLinus Torvalds #include <net/llc_c_ac.h> 211da177e4SLinus Torvalds #include <net/llc_s_ac.h> 221da177e4SLinus Torvalds #include <net/llc_c_ev.h> 231da177e4SLinus Torvalds #include <net/llc_c_st.h> 241da177e4SLinus Torvalds #include <net/llc_s_ev.h> 251da177e4SLinus Torvalds #include <net/llc_s_st.h> 261da177e4SLinus Torvalds #include <net/llc_pdu.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /** 291da177e4SLinus Torvalds * struct llc_station - LLC station component 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * SAP and connection resource manager, one per adapter. 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * @state - state of station 341da177e4SLinus Torvalds * @xid_r_count - XID response PDU counter 351da177e4SLinus Torvalds * @mac_sa - MAC source address 361da177e4SLinus Torvalds * @sap_list - list of related SAPs 371da177e4SLinus Torvalds * @ev_q - events entering state mach. 381da177e4SLinus Torvalds * @mac_pdu_q - PDUs ready to send to MAC 391da177e4SLinus Torvalds */ 401da177e4SLinus Torvalds struct llc_station { 411da177e4SLinus Torvalds u8 state; 421da177e4SLinus Torvalds u8 xid_r_count; 431da177e4SLinus Torvalds struct timer_list ack_timer; 441da177e4SLinus Torvalds u8 retry_count; 451da177e4SLinus Torvalds u8 maximum_retry; 461da177e4SLinus Torvalds struct { 471da177e4SLinus Torvalds struct sk_buff_head list; 481da177e4SLinus Torvalds spinlock_t lock; 491da177e4SLinus Torvalds } ev_q; 501da177e4SLinus Torvalds struct sk_buff_head mac_pdu_q; 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* Types of events (possible values in 'ev->type') */ 541da177e4SLinus Torvalds #define LLC_STATION_EV_TYPE_SIMPLE 1 551da177e4SLinus Torvalds #define LLC_STATION_EV_TYPE_CONDITION 2 561da177e4SLinus Torvalds #define LLC_STATION_EV_TYPE_PRIM 3 571da177e4SLinus Torvalds #define LLC_STATION_EV_TYPE_PDU 4 /* command/response PDU */ 581da177e4SLinus Torvalds #define LLC_STATION_EV_TYPE_ACK_TMR 5 591da177e4SLinus Torvalds #define LLC_STATION_EV_TYPE_RPT_STATUS 6 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* Events */ 621da177e4SLinus Torvalds #define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK 1 631da177e4SLinus Torvalds #define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK 2 641da177e4SLinus Torvalds #define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY 3 651da177e4SLinus Torvalds #define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY 4 661da177e4SLinus Torvalds #define LLC_STATION_EV_RX_NULL_DSAP_XID_C 5 671da177e4SLinus Torvalds #define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ 6 681da177e4SLinus Torvalds #define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ 7 691da177e4SLinus Torvalds #define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8 701da177e4SLinus Torvalds #define LLC_STATION_EV_DISABLE_REQ 9 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds struct llc_station_state_ev { 731da177e4SLinus Torvalds u8 type; 741da177e4SLinus Torvalds u8 prim; 751da177e4SLinus Torvalds u8 prim_type; 761da177e4SLinus Torvalds u8 reason; 771da177e4SLinus Torvalds struct list_head node; /* node in station->ev_q.list */ 781da177e4SLinus Torvalds }; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds static __inline__ struct llc_station_state_ev * 811da177e4SLinus Torvalds llc_station_ev(struct sk_buff *skb) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds return (struct llc_station_state_ev *)skb->cb; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds typedef int (*llc_station_ev_t)(struct sk_buff *skb); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds #define LLC_STATION_STATE_DOWN 1 /* initial state */ 891da177e4SLinus Torvalds #define LLC_STATION_STATE_DUP_ADDR_CHK 2 901da177e4SLinus Torvalds #define LLC_STATION_STATE_UP 3 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds #define LLC_NBR_STATION_STATES 3 /* size of state table */ 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds typedef int (*llc_station_action_t)(struct sk_buff *skb); 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds /* Station component state table structure */ 971da177e4SLinus Torvalds struct llc_station_state_trans { 981da177e4SLinus Torvalds llc_station_ev_t ev; 991da177e4SLinus Torvalds u8 next_state; 1001da177e4SLinus Torvalds llc_station_action_t *ev_actions; 1011da177e4SLinus Torvalds }; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds struct llc_station_state { 1041da177e4SLinus Torvalds u8 curr_state; 1051da177e4SLinus Torvalds struct llc_station_state_trans **transitions; 1061da177e4SLinus Torvalds }; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds static struct llc_station llc_main_station; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static int llc_stat_ev_enable_with_dup_addr_check(struct sk_buff *skb) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_SIMPLE && 1151da177e4SLinus Torvalds ev->prim_type == 1161da177e4SLinus Torvalds LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds static int llc_stat_ev_enable_without_dup_addr_check(struct sk_buff *skb) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_SIMPLE && 1241da177e4SLinus Torvalds ev->prim_type == 1251da177e4SLinus Torvalds LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds static int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct sk_buff *skb) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_ACK_TMR && 1331da177e4SLinus Torvalds llc_main_station.retry_count < 1341da177e4SLinus Torvalds llc_main_station.maximum_retry ? 0 : 1; 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds static int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct sk_buff *skb) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_ACK_TMR && 1421da177e4SLinus Torvalds llc_main_station.retry_count == 1431da177e4SLinus Torvalds llc_main_station.maximum_retry ? 0 : 1; 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1491da177e4SLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_PDU && 1521da177e4SLinus Torvalds LLC_PDU_IS_CMD(pdu) && /* command PDU */ 1531da177e4SLinus Torvalds LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ 1541da177e4SLinus Torvalds LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && 1551da177e4SLinus Torvalds !pdu->dsap ? 0 : 1; /* NULL DSAP value */ 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds static int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct sk_buff *skb) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1611da177e4SLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_PDU && 1641da177e4SLinus Torvalds LLC_PDU_IS_RSP(pdu) && /* response PDU */ 1651da177e4SLinus Torvalds LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ 1661da177e4SLinus Torvalds LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && 1671da177e4SLinus Torvalds !pdu->dsap && /* NULL DSAP value */ 1681da177e4SLinus Torvalds !llc_main_station.xid_r_count ? 0 : 1; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds static int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct sk_buff *skb) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1741da177e4SLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_PDU && 1771da177e4SLinus Torvalds LLC_PDU_IS_RSP(pdu) && /* response PDU */ 1781da177e4SLinus Torvalds LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ 1791da177e4SLinus Torvalds LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && 1801da177e4SLinus Torvalds !pdu->dsap && /* NULL DSAP value */ 1811da177e4SLinus Torvalds llc_main_station.xid_r_count == 1 ? 0 : 1; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1871da177e4SLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_PDU && 1901da177e4SLinus Torvalds LLC_PDU_IS_CMD(pdu) && /* command PDU */ 1911da177e4SLinus Torvalds LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ 1921da177e4SLinus Torvalds LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && 1931da177e4SLinus Torvalds !pdu->dsap ? 0 : 1; /* NULL DSAP */ 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds static int llc_stat_ev_disable_req(struct sk_buff *skb) 1971da177e4SLinus Torvalds { 1981da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds return ev->type == LLC_STATION_EV_TYPE_PRIM && 2011da177e4SLinus Torvalds ev->prim == LLC_DISABLE_PRIM && 2021da177e4SLinus Torvalds ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds /** 2061da177e4SLinus Torvalds * llc_station_send_pdu - queues PDU to send 2071da177e4SLinus Torvalds * @skb: Address of the PDU 2081da177e4SLinus Torvalds * 2091da177e4SLinus Torvalds * Queues a PDU to send to the MAC layer. 2101da177e4SLinus Torvalds */ 2111da177e4SLinus Torvalds static void llc_station_send_pdu(struct sk_buff *skb) 2121da177e4SLinus Torvalds { 2131da177e4SLinus Torvalds skb_queue_tail(&llc_main_station.mac_pdu_q, skb); 2141da177e4SLinus Torvalds while ((skb = skb_dequeue(&llc_main_station.mac_pdu_q)) != NULL) 2151da177e4SLinus Torvalds if (dev_queue_xmit(skb)) 2161da177e4SLinus Torvalds break; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static int llc_station_ac_start_ack_timer(struct sk_buff *skb) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds mod_timer(&llc_main_station.ack_timer, jiffies + LLC_ACK_TIME * HZ); 2221da177e4SLinus Torvalds return 0; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static int llc_station_ac_set_retry_cnt_0(struct sk_buff *skb) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds llc_main_station.retry_count = 0; 2281da177e4SLinus Torvalds return 0; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds static int llc_station_ac_inc_retry_cnt_by_1(struct sk_buff *skb) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds llc_main_station.retry_count++; 2341da177e4SLinus Torvalds return 0; 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds static int llc_station_ac_set_xid_r_cnt_0(struct sk_buff *skb) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds llc_main_station.xid_r_count = 0; 2401da177e4SLinus Torvalds return 0; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds static int llc_station_ac_inc_xid_r_cnt_by_1(struct sk_buff *skb) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds llc_main_station.xid_r_count++; 2461da177e4SLinus Torvalds return 0; 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds int rc = 1; 2521d67e650SArnaldo Carvalho de Melo struct sk_buff *nskb = llc_alloc_frame(skb->dev); 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds if (!nskb) 2551da177e4SLinus Torvalds goto out; 2561da177e4SLinus Torvalds llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD); 2571da177e4SLinus Torvalds llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127); 2581da177e4SLinus Torvalds rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, llc_station_mac_sa); 2591da177e4SLinus Torvalds if (rc) 2601da177e4SLinus Torvalds goto free; 2611da177e4SLinus Torvalds llc_station_send_pdu(nskb); 2621da177e4SLinus Torvalds out: 2631da177e4SLinus Torvalds return rc; 2641da177e4SLinus Torvalds free: 2651da177e4SLinus Torvalds kfree_skb(skb); 2661da177e4SLinus Torvalds goto out; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds static int llc_station_ac_send_xid_r(struct sk_buff *skb) 2701da177e4SLinus Torvalds { 2711da177e4SLinus Torvalds u8 mac_da[ETH_ALEN], dsap; 2721da177e4SLinus Torvalds int rc = 1; 2731d67e650SArnaldo Carvalho de Melo struct sk_buff* nskb = llc_alloc_frame(skb->dev); 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds if (!nskb) 2761da177e4SLinus Torvalds goto out; 2771da177e4SLinus Torvalds rc = 0; 2781da177e4SLinus Torvalds llc_pdu_decode_sa(skb, mac_da); 2791da177e4SLinus Torvalds llc_pdu_decode_ssap(skb, &dsap); 2801da177e4SLinus Torvalds llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); 2811da177e4SLinus Torvalds llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127); 2821da177e4SLinus Torvalds rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da); 2831da177e4SLinus Torvalds if (rc) 2841da177e4SLinus Torvalds goto free; 2851da177e4SLinus Torvalds llc_station_send_pdu(nskb); 2861da177e4SLinus Torvalds out: 2871da177e4SLinus Torvalds return rc; 2881da177e4SLinus Torvalds free: 2891da177e4SLinus Torvalds kfree_skb(skb); 2901da177e4SLinus Torvalds goto out; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static int llc_station_ac_send_test_r(struct sk_buff *skb) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds u8 mac_da[ETH_ALEN], dsap; 2961da177e4SLinus Torvalds int rc = 1; 2971d67e650SArnaldo Carvalho de Melo struct sk_buff *nskb = llc_alloc_frame(skb->dev); 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds if (!nskb) 3001da177e4SLinus Torvalds goto out; 3011da177e4SLinus Torvalds rc = 0; 3021da177e4SLinus Torvalds llc_pdu_decode_sa(skb, mac_da); 3031da177e4SLinus Torvalds llc_pdu_decode_ssap(skb, &dsap); 3041da177e4SLinus Torvalds llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); 3051da177e4SLinus Torvalds llc_pdu_init_as_test_rsp(nskb, skb); 3061da177e4SLinus Torvalds rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da); 3071da177e4SLinus Torvalds if (rc) 3081da177e4SLinus Torvalds goto free; 3091da177e4SLinus Torvalds llc_station_send_pdu(nskb); 3101da177e4SLinus Torvalds out: 3111da177e4SLinus Torvalds return rc; 3121da177e4SLinus Torvalds free: 3131da177e4SLinus Torvalds kfree_skb(skb); 3141da177e4SLinus Torvalds goto out; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds static int llc_station_ac_report_status(struct sk_buff *skb) 3181da177e4SLinus Torvalds { 3191da177e4SLinus Torvalds return 0; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds /* COMMON STATION STATE transitions */ 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* dummy last-transition indicator; common to all state transition groups 3251da177e4SLinus Torvalds * last entry for this state 3261da177e4SLinus Torvalds * all members are zeros, .bss zeroes it 3271da177e4SLinus Torvalds */ 3281da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_state_trans_end; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds /* DOWN STATE transitions */ 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK event */ 3331da177e4SLinus Torvalds static llc_station_action_t llc_stat_down_state_actions_1[] = { 3341da177e4SLinus Torvalds [0] = llc_station_ac_start_ack_timer, 3351da177e4SLinus Torvalds [1] = llc_station_ac_set_retry_cnt_0, 3361da177e4SLinus Torvalds [2] = llc_station_ac_set_xid_r_cnt_0, 3371da177e4SLinus Torvalds [3] = llc_station_ac_send_null_dsap_xid_c, 3381da177e4SLinus Torvalds [4] = NULL, 3391da177e4SLinus Torvalds }; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_down_state_trans_1 = { 3421da177e4SLinus Torvalds .ev = llc_stat_ev_enable_with_dup_addr_check, 3431da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, 3441da177e4SLinus Torvalds .ev_actions = llc_stat_down_state_actions_1, 3451da177e4SLinus Torvalds }; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK event */ 3481da177e4SLinus Torvalds static llc_station_action_t llc_stat_down_state_actions_2[] = { 3491da177e4SLinus Torvalds [0] = llc_station_ac_report_status, /* STATION UP */ 3501da177e4SLinus Torvalds [1] = NULL, 3511da177e4SLinus Torvalds }; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_down_state_trans_2 = { 3541da177e4SLinus Torvalds .ev = llc_stat_ev_enable_without_dup_addr_check, 3551da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_UP, 3561da177e4SLinus Torvalds .ev_actions = llc_stat_down_state_actions_2, 3571da177e4SLinus Torvalds }; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds /* array of pointers; one to each transition */ 3601da177e4SLinus Torvalds static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = { 3611da177e4SLinus Torvalds [0] = &llc_stat_down_state_trans_1, 3621da177e4SLinus Torvalds [1] = &llc_stat_down_state_trans_2, 3631da177e4SLinus Torvalds [2] = &llc_stat_state_trans_end, 3641da177e4SLinus Torvalds }; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds /* UP STATE transitions */ 3671da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_DISABLE_REQ event */ 3681da177e4SLinus Torvalds static llc_station_action_t llc_stat_up_state_actions_1[] = { 3691da177e4SLinus Torvalds [0] = llc_station_ac_report_status, /* STATION DOWN */ 3701da177e4SLinus Torvalds [1] = NULL, 3711da177e4SLinus Torvalds }; 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_up_state_trans_1 = { 3741da177e4SLinus Torvalds .ev = llc_stat_ev_disable_req, 3751da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DOWN, 3761da177e4SLinus Torvalds .ev_actions = llc_stat_up_state_actions_1, 3771da177e4SLinus Torvalds }; 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */ 3801da177e4SLinus Torvalds static llc_station_action_t llc_stat_up_state_actions_2[] = { 3811da177e4SLinus Torvalds [0] = llc_station_ac_send_xid_r, 3821da177e4SLinus Torvalds [1] = NULL, 3831da177e4SLinus Torvalds }; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_up_state_trans_2 = { 3861da177e4SLinus Torvalds .ev = llc_stat_ev_rx_null_dsap_xid_c, 3871da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_UP, 3881da177e4SLinus Torvalds .ev_actions = llc_stat_up_state_actions_2, 3891da177e4SLinus Torvalds }; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */ 3921da177e4SLinus Torvalds static llc_station_action_t llc_stat_up_state_actions_3[] = { 3931da177e4SLinus Torvalds [0] = llc_station_ac_send_test_r, 3941da177e4SLinus Torvalds [1] = NULL, 3951da177e4SLinus Torvalds }; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_up_state_trans_3 = { 3981da177e4SLinus Torvalds .ev = llc_stat_ev_rx_null_dsap_test_c, 3991da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_UP, 4001da177e4SLinus Torvalds .ev_actions = llc_stat_up_state_actions_3, 4011da177e4SLinus Torvalds }; 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds /* array of pointers; one to each transition */ 4041da177e4SLinus Torvalds static struct llc_station_state_trans *llc_stat_up_state_trans [] = { 4051da177e4SLinus Torvalds [0] = &llc_stat_up_state_trans_1, 4061da177e4SLinus Torvalds [1] = &llc_stat_up_state_trans_2, 4071da177e4SLinus Torvalds [2] = &llc_stat_up_state_trans_3, 4081da177e4SLinus Torvalds [3] = &llc_stat_state_trans_end, 4091da177e4SLinus Torvalds }; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds /* DUP ADDR CHK STATE transitions */ 4121da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ 4131da177e4SLinus Torvalds * event 4141da177e4SLinus Torvalds */ 4151da177e4SLinus Torvalds static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = { 4161da177e4SLinus Torvalds [0] = llc_station_ac_inc_xid_r_cnt_by_1, 4171da177e4SLinus Torvalds [1] = NULL, 4181da177e4SLinus Torvalds }; 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = { 4211da177e4SLinus Torvalds .ev = llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq, 4221da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, 4231da177e4SLinus Torvalds .ev_actions = llc_stat_dupaddr_state_actions_1, 4241da177e4SLinus Torvalds }; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ 4271da177e4SLinus Torvalds * event 4281da177e4SLinus Torvalds */ 4291da177e4SLinus Torvalds static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = { 4301da177e4SLinus Torvalds [0] = llc_station_ac_report_status, /* DUPLICATE ADDRESS FOUND */ 4311da177e4SLinus Torvalds [1] = NULL, 4321da177e4SLinus Torvalds }; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = { 4351da177e4SLinus Torvalds .ev = llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq, 4361da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DOWN, 4371da177e4SLinus Torvalds .ev_actions = llc_stat_dupaddr_state_actions_2, 4381da177e4SLinus Torvalds }; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */ 4411da177e4SLinus Torvalds static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = { 4421da177e4SLinus Torvalds [0] = llc_station_ac_send_xid_r, 4431da177e4SLinus Torvalds [1] = NULL, 4441da177e4SLinus Torvalds }; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = { 4471da177e4SLinus Torvalds .ev = llc_stat_ev_rx_null_dsap_xid_c, 4481da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, 4491da177e4SLinus Torvalds .ev_actions = llc_stat_dupaddr_state_actions_3, 4501da177e4SLinus Torvalds }; 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY 4531da177e4SLinus Torvalds * event 4541da177e4SLinus Torvalds */ 4551da177e4SLinus Torvalds static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = { 4561da177e4SLinus Torvalds [0] = llc_station_ac_start_ack_timer, 4571da177e4SLinus Torvalds [1] = llc_station_ac_inc_retry_cnt_by_1, 4581da177e4SLinus Torvalds [2] = llc_station_ac_set_xid_r_cnt_0, 4591da177e4SLinus Torvalds [3] = llc_station_ac_send_null_dsap_xid_c, 4601da177e4SLinus Torvalds [4] = NULL, 4611da177e4SLinus Torvalds }; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = { 4641da177e4SLinus Torvalds .ev = llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry, 4651da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DUP_ADDR_CHK, 4661da177e4SLinus Torvalds .ev_actions = llc_stat_dupaddr_state_actions_4, 4671da177e4SLinus Torvalds }; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY 4701da177e4SLinus Torvalds * event 4711da177e4SLinus Torvalds */ 4721da177e4SLinus Torvalds static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = { 4731da177e4SLinus Torvalds [0] = llc_station_ac_report_status, /* STATION UP */ 4741da177e4SLinus Torvalds [1] = NULL, 4751da177e4SLinus Torvalds }; 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = { 4781da177e4SLinus Torvalds .ev = llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry, 4791da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_UP, 4801da177e4SLinus Torvalds .ev_actions = llc_stat_dupaddr_state_actions_5, 4811da177e4SLinus Torvalds }; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds /* state transition for LLC_STATION_EV_DISABLE_REQ event */ 4841da177e4SLinus Torvalds static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = { 4851da177e4SLinus Torvalds [0] = llc_station_ac_report_status, /* STATION DOWN */ 4861da177e4SLinus Torvalds [1] = NULL, 4871da177e4SLinus Torvalds }; 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = { 4901da177e4SLinus Torvalds .ev = llc_stat_ev_disable_req, 4911da177e4SLinus Torvalds .next_state = LLC_STATION_STATE_DOWN, 4921da177e4SLinus Torvalds .ev_actions = llc_stat_dupaddr_state_actions_6, 4931da177e4SLinus Torvalds }; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds /* array of pointers; one to each transition */ 4961da177e4SLinus Torvalds static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = { 4971da177e4SLinus Torvalds [0] = &llc_stat_dupaddr_state_trans_6, /* Request */ 4981da177e4SLinus Torvalds [1] = &llc_stat_dupaddr_state_trans_4, /* Timer */ 4991da177e4SLinus Torvalds [2] = &llc_stat_dupaddr_state_trans_5, 5001da177e4SLinus Torvalds [3] = &llc_stat_dupaddr_state_trans_1, /* Receive frame */ 5011da177e4SLinus Torvalds [4] = &llc_stat_dupaddr_state_trans_2, 5021da177e4SLinus Torvalds [5] = &llc_stat_dupaddr_state_trans_3, 5031da177e4SLinus Torvalds [6] = &llc_stat_state_trans_end, 5041da177e4SLinus Torvalds }; 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds static struct llc_station_state 5071da177e4SLinus Torvalds llc_station_state_table[LLC_NBR_STATION_STATES] = { 5081da177e4SLinus Torvalds [LLC_STATION_STATE_DOWN - 1] = { 5091da177e4SLinus Torvalds .curr_state = LLC_STATION_STATE_DOWN, 5101da177e4SLinus Torvalds .transitions = llc_stat_dwn_state_trans, 5111da177e4SLinus Torvalds }, 5121da177e4SLinus Torvalds [LLC_STATION_STATE_DUP_ADDR_CHK - 1] = { 5131da177e4SLinus Torvalds .curr_state = LLC_STATION_STATE_DUP_ADDR_CHK, 5141da177e4SLinus Torvalds .transitions = llc_stat_dupaddr_state_trans, 5151da177e4SLinus Torvalds }, 5161da177e4SLinus Torvalds [LLC_STATION_STATE_UP - 1] = { 5171da177e4SLinus Torvalds .curr_state = LLC_STATION_STATE_UP, 5181da177e4SLinus Torvalds .transitions = llc_stat_up_state_trans, 5191da177e4SLinus Torvalds }, 5201da177e4SLinus Torvalds }; 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds /** 5231da177e4SLinus Torvalds * llc_exec_station_trans_actions - executes actions for transition 5241da177e4SLinus Torvalds * @trans: Address of the transition 5251da177e4SLinus Torvalds * @skb: Address of the event that caused the transition 5261da177e4SLinus Torvalds * 5271da177e4SLinus Torvalds * Executes actions of a transition of the station state machine. Returns 5281da177e4SLinus Torvalds * 0 if all actions complete successfully, nonzero otherwise. 5291da177e4SLinus Torvalds */ 5301da177e4SLinus Torvalds static u16 llc_exec_station_trans_actions(struct llc_station_state_trans *trans, 5311da177e4SLinus Torvalds struct sk_buff *skb) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds u16 rc = 0; 5341da177e4SLinus Torvalds llc_station_action_t *next_action = trans->ev_actions; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds for (; next_action && *next_action; next_action++) 5371da177e4SLinus Torvalds if ((*next_action)(skb)) 5381da177e4SLinus Torvalds rc = 1; 5391da177e4SLinus Torvalds return rc; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds /** 5431da177e4SLinus Torvalds * llc_find_station_trans - finds transition for this event 5441da177e4SLinus Torvalds * @skb: Address of the event 5451da177e4SLinus Torvalds * 5461da177e4SLinus Torvalds * Search thru events of the current state of the station until list 5471da177e4SLinus Torvalds * exhausted or it's obvious that the event is not valid for the current 5481da177e4SLinus Torvalds * state. Returns the address of the transition if cound, %NULL otherwise. 5491da177e4SLinus Torvalds */ 5501da177e4SLinus Torvalds static struct llc_station_state_trans * 5511da177e4SLinus Torvalds llc_find_station_trans(struct sk_buff *skb) 5521da177e4SLinus Torvalds { 5531da177e4SLinus Torvalds int i = 0; 5541da177e4SLinus Torvalds struct llc_station_state_trans *rc = NULL; 5551da177e4SLinus Torvalds struct llc_station_state_trans **next_trans; 5561da177e4SLinus Torvalds struct llc_station_state *curr_state = 5571da177e4SLinus Torvalds &llc_station_state_table[llc_main_station.state - 1]; 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) 5601da177e4SLinus Torvalds if (!next_trans[i]->ev(skb)) { 5611da177e4SLinus Torvalds rc = next_trans[i]; 5621da177e4SLinus Torvalds break; 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds return rc; 5651da177e4SLinus Torvalds } 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds /** 5681da177e4SLinus Torvalds * llc_station_free_ev - frees an event 5691da177e4SLinus Torvalds * @skb: Address of the event 5701da177e4SLinus Torvalds * 5711da177e4SLinus Torvalds * Frees an event. 5721da177e4SLinus Torvalds */ 5731da177e4SLinus Torvalds static void llc_station_free_ev(struct sk_buff *skb) 5741da177e4SLinus Torvalds { 5751da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds if (ev->type == LLC_STATION_EV_TYPE_PDU) 5781da177e4SLinus Torvalds kfree_skb(skb); 5791da177e4SLinus Torvalds } 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds /** 5821da177e4SLinus Torvalds * llc_station_next_state - processes event and goes to the next state 5831da177e4SLinus Torvalds * @skb: Address of the event 5841da177e4SLinus Torvalds * 5851da177e4SLinus Torvalds * Processes an event, executes any transitions related to that event and 5861da177e4SLinus Torvalds * updates the state of the station. 5871da177e4SLinus Torvalds */ 5881da177e4SLinus Torvalds static u16 llc_station_next_state(struct sk_buff *skb) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds u16 rc = 1; 5911da177e4SLinus Torvalds struct llc_station_state_trans *trans; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds if (llc_main_station.state > LLC_NBR_STATION_STATES) 5941da177e4SLinus Torvalds goto out; 5951da177e4SLinus Torvalds trans = llc_find_station_trans(skb); 5961da177e4SLinus Torvalds if (trans) { 5971da177e4SLinus Torvalds /* got the state to which we next transition; perform the 5981da177e4SLinus Torvalds * actions associated with this transition before actually 5991da177e4SLinus Torvalds * transitioning to the next state 6001da177e4SLinus Torvalds */ 6011da177e4SLinus Torvalds rc = llc_exec_station_trans_actions(trans, skb); 6021da177e4SLinus Torvalds if (!rc) 6031da177e4SLinus Torvalds /* transition station to next state if all actions 6041da177e4SLinus Torvalds * execute successfully; done; wait for next event 6051da177e4SLinus Torvalds */ 6061da177e4SLinus Torvalds llc_main_station.state = trans->next_state; 6071da177e4SLinus Torvalds } else 6081da177e4SLinus Torvalds /* event not recognized in current state; re-queue it for 6091da177e4SLinus Torvalds * processing again at a later time; return failure 6101da177e4SLinus Torvalds */ 6111da177e4SLinus Torvalds rc = 0; 6121da177e4SLinus Torvalds out: 6131da177e4SLinus Torvalds llc_station_free_ev(skb); 6141da177e4SLinus Torvalds return rc; 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds /** 6181da177e4SLinus Torvalds * llc_station_service_events - service events in the queue 6191da177e4SLinus Torvalds * 6201da177e4SLinus Torvalds * Get an event from the station event queue (if any); attempt to service 6211da177e4SLinus Torvalds * the event; if event serviced, get the next event (if any) on the event 6221da177e4SLinus Torvalds * queue; if event not service, re-queue the event on the event queue and 6231da177e4SLinus Torvalds * attempt to service the next event; when serviced all events in queue, 6241da177e4SLinus Torvalds * finished; if don't transition to different state, just service all 6251da177e4SLinus Torvalds * events once; if transition to new state, service all events again. 6261da177e4SLinus Torvalds * Caller must hold llc_main_station.ev_q.lock. 6271da177e4SLinus Torvalds */ 6281da177e4SLinus Torvalds static void llc_station_service_events(void) 6291da177e4SLinus Torvalds { 6301da177e4SLinus Torvalds struct sk_buff *skb; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds while ((skb = skb_dequeue(&llc_main_station.ev_q.list)) != NULL) 6331da177e4SLinus Torvalds llc_station_next_state(skb); 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds /** 6371da177e4SLinus Torvalds * llc_station_state_process: queue event and try to process queue. 6381da177e4SLinus Torvalds * @skb: Address of the event 6391da177e4SLinus Torvalds * 6401da177e4SLinus Torvalds * Queues an event (on the station event queue) for handling by the 6411da177e4SLinus Torvalds * station state machine and attempts to process any queued-up events. 6421da177e4SLinus Torvalds */ 6431da177e4SLinus Torvalds static void llc_station_state_process(struct sk_buff *skb) 6441da177e4SLinus Torvalds { 6451da177e4SLinus Torvalds spin_lock_bh(&llc_main_station.ev_q.lock); 6461da177e4SLinus Torvalds skb_queue_tail(&llc_main_station.ev_q.list, skb); 6471da177e4SLinus Torvalds llc_station_service_events(); 6481da177e4SLinus Torvalds spin_unlock_bh(&llc_main_station.ev_q.lock); 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds static void llc_station_ack_tmr_cb(unsigned long timeout_data) 6521da177e4SLinus Torvalds { 6531da177e4SLinus Torvalds struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds if (skb) { 6561da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds ev->type = LLC_STATION_EV_TYPE_ACK_TMR; 6591da177e4SLinus Torvalds llc_station_state_process(skb); 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds /* 6641da177e4SLinus Torvalds * llc_station_rcv - send received pdu to the station state machine 6651da177e4SLinus Torvalds * @skb: received frame. 6661da177e4SLinus Torvalds * 6671da177e4SLinus Torvalds * Sends data unit to station state machine. 6681da177e4SLinus Torvalds */ 6691da177e4SLinus Torvalds static void llc_station_rcv(struct sk_buff *skb) 6701da177e4SLinus Torvalds { 6711da177e4SLinus Torvalds struct llc_station_state_ev *ev = llc_station_ev(skb); 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds ev->type = LLC_STATION_EV_TYPE_PDU; 6741da177e4SLinus Torvalds ev->reason = 0; 6751da177e4SLinus Torvalds llc_station_state_process(skb); 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds int __init llc_station_init(void) 6791da177e4SLinus Torvalds { 6801da177e4SLinus Torvalds u16 rc = -ENOBUFS; 6811da177e4SLinus Torvalds struct sk_buff *skb; 6821da177e4SLinus Torvalds struct llc_station_state_ev *ev; 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds skb_queue_head_init(&llc_main_station.mac_pdu_q); 6851da177e4SLinus Torvalds skb_queue_head_init(&llc_main_station.ev_q.list); 6861da177e4SLinus Torvalds spin_lock_init(&llc_main_station.ev_q.lock); 6871da177e4SLinus Torvalds init_timer(&llc_main_station.ack_timer); 6881da177e4SLinus Torvalds llc_main_station.ack_timer.data = (unsigned long)&llc_main_station; 6891da177e4SLinus Torvalds llc_main_station.ack_timer.function = llc_station_ack_tmr_cb; 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds skb = alloc_skb(0, GFP_ATOMIC); 6921da177e4SLinus Torvalds if (!skb) 6931da177e4SLinus Torvalds goto out; 6941da177e4SLinus Torvalds rc = 0; 6951da177e4SLinus Torvalds llc_set_station_handler(llc_station_rcv); 6961da177e4SLinus Torvalds ev = llc_station_ev(skb); 6971da177e4SLinus Torvalds memset(ev, 0, sizeof(*ev)); 6981da177e4SLinus Torvalds llc_main_station.ack_timer.expires = jiffies + 3 * HZ; 6991da177e4SLinus Torvalds llc_main_station.maximum_retry = 1; 7001da177e4SLinus Torvalds llc_main_station.state = LLC_STATION_STATE_DOWN; 7011da177e4SLinus Torvalds ev->type = LLC_STATION_EV_TYPE_SIMPLE; 7021da177e4SLinus Torvalds ev->prim_type = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK; 7031da177e4SLinus Torvalds rc = llc_station_next_state(skb); 7041da177e4SLinus Torvalds out: 7051da177e4SLinus Torvalds return rc; 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds void __exit llc_station_exit(void) 7091da177e4SLinus Torvalds { 7101da177e4SLinus Torvalds llc_set_station_handler(NULL); 7111da177e4SLinus Torvalds } 712