llc_station.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*
  2. * llc_station.c - station component of LLC
  3. *
  4. * Copyright (c) 1997 by Procom Technology, Inc.
  5. * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  6. *
  7. * This program can be redistributed or modified under the terms of the
  8. * GNU General Public License as published by the Free Software Foundation.
  9. * This program is distributed without any warranty or implied warranty
  10. * of merchantability or fitness for a particular purpose.
  11. *
  12. * See the GNU General Public License for more details.
  13. */
  14. #include <linux/config.h>
  15. #include <linux/init.h>
  16. #include <linux/module.h>
  17. #include <net/llc.h>
  18. #include <net/llc_sap.h>
  19. #include <net/llc_conn.h>
  20. #include <net/llc_c_ac.h>
  21. #include <net/llc_s_ac.h>
  22. #include <net/llc_c_ev.h>
  23. #include <net/llc_c_st.h>
  24. #include <net/llc_s_ev.h>
  25. #include <net/llc_s_st.h>
  26. #include <net/llc_pdu.h>
  27. /**
  28. * struct llc_station - LLC station component
  29. *
  30. * SAP and connection resource manager, one per adapter.
  31. *
  32. * @state - state of station
  33. * @xid_r_count - XID response PDU counter
  34. * @mac_sa - MAC source address
  35. * @sap_list - list of related SAPs
  36. * @ev_q - events entering state mach.
  37. * @mac_pdu_q - PDUs ready to send to MAC
  38. */
  39. struct llc_station {
  40. u8 state;
  41. u8 xid_r_count;
  42. struct timer_list ack_timer;
  43. u8 retry_count;
  44. u8 maximum_retry;
  45. struct {
  46. struct sk_buff_head list;
  47. spinlock_t lock;
  48. } ev_q;
  49. struct sk_buff_head mac_pdu_q;
  50. };
  51. /* Types of events (possible values in 'ev->type') */
  52. #define LLC_STATION_EV_TYPE_SIMPLE 1
  53. #define LLC_STATION_EV_TYPE_CONDITION 2
  54. #define LLC_STATION_EV_TYPE_PRIM 3
  55. #define LLC_STATION_EV_TYPE_PDU 4 /* command/response PDU */
  56. #define LLC_STATION_EV_TYPE_ACK_TMR 5
  57. #define LLC_STATION_EV_TYPE_RPT_STATUS 6
  58. /* Events */
  59. #define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK 1
  60. #define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK 2
  61. #define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY 3
  62. #define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY 4
  63. #define LLC_STATION_EV_RX_NULL_DSAP_XID_C 5
  64. #define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ 6
  65. #define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ 7
  66. #define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8
  67. #define LLC_STATION_EV_DISABLE_REQ 9
  68. struct llc_station_state_ev {
  69. u8 type;
  70. u8 prim;
  71. u8 prim_type;
  72. u8 reason;
  73. struct list_head node; /* node in station->ev_q.list */
  74. };
  75. static __inline__ struct llc_station_state_ev *
  76. llc_station_ev(struct sk_buff *skb)
  77. {
  78. return (struct llc_station_state_ev *)skb->cb;
  79. }
  80. typedef int (*llc_station_ev_t)(struct sk_buff *skb);
  81. #define LLC_STATION_STATE_DOWN 1 /* initial state */
  82. #define LLC_STATION_STATE_DUP_ADDR_CHK 2
  83. #define LLC_STATION_STATE_UP 3
  84. #define LLC_NBR_STATION_STATES 3 /* size of state table */
  85. typedef int (*llc_station_action_t)(struct sk_buff *skb);
  86. /* Station component state table structure */
  87. struct llc_station_state_trans {
  88. llc_station_ev_t ev;
  89. u8 next_state;
  90. llc_station_action_t *ev_actions;
  91. };
  92. struct llc_station_state {
  93. u8 curr_state;
  94. struct llc_station_state_trans **transitions;
  95. };
  96. static struct llc_station llc_main_station;
  97. static int llc_stat_ev_enable_with_dup_addr_check(struct sk_buff *skb)
  98. {
  99. struct llc_station_state_ev *ev = llc_station_ev(skb);
  100. return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
  101. ev->prim_type ==
  102. LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
  103. }
  104. static int llc_stat_ev_enable_without_dup_addr_check(struct sk_buff *skb)
  105. {
  106. struct llc_station_state_ev *ev = llc_station_ev(skb);
  107. return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
  108. ev->prim_type ==
  109. LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
  110. }
  111. static int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct sk_buff *skb)
  112. {
  113. struct llc_station_state_ev *ev = llc_station_ev(skb);
  114. return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
  115. llc_main_station.retry_count <
  116. llc_main_station.maximum_retry ? 0 : 1;
  117. }
  118. static int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct sk_buff *skb)
  119. {
  120. struct llc_station_state_ev *ev = llc_station_ev(skb);
  121. return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
  122. llc_main_station.retry_count ==
  123. llc_main_station.maximum_retry ? 0 : 1;
  124. }
  125. static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
  126. {
  127. struct llc_station_state_ev *ev = llc_station_ev(skb);
  128. struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
  129. return ev->type == LLC_STATION_EV_TYPE_PDU &&
  130. LLC_PDU_IS_CMD(pdu) && /* command PDU */
  131. LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
  132. LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
  133. !pdu->dsap ? 0 : 1; /* NULL DSAP value */
  134. }
  135. static int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct sk_buff *skb)
  136. {
  137. struct llc_station_state_ev *ev = llc_station_ev(skb);
  138. struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
  139. return ev->type == LLC_STATION_EV_TYPE_PDU &&
  140. LLC_PDU_IS_RSP(pdu) && /* response PDU */
  141. LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
  142. LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
  143. !pdu->dsap && /* NULL DSAP value */
  144. !llc_main_station.xid_r_count ? 0 : 1;
  145. }
  146. static int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct sk_buff *skb)
  147. {
  148. struct llc_station_state_ev *ev = llc_station_ev(skb);
  149. struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
  150. return ev->type == LLC_STATION_EV_TYPE_PDU &&
  151. LLC_PDU_IS_RSP(pdu) && /* response PDU */
  152. LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
  153. LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
  154. !pdu->dsap && /* NULL DSAP value */
  155. llc_main_station.xid_r_count == 1 ? 0 : 1;
  156. }
  157. static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
  158. {
  159. struct llc_station_state_ev *ev = llc_station_ev(skb);
  160. struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
  161. return ev->type == LLC_STATION_EV_TYPE_PDU &&
  162. LLC_PDU_IS_CMD(pdu) && /* command PDU */
  163. LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
  164. LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
  165. !pdu->dsap ? 0 : 1; /* NULL DSAP */
  166. }
  167. static int llc_stat_ev_disable_req(struct sk_buff *skb)
  168. {
  169. struct llc_station_state_ev *ev = llc_station_ev(skb);
  170. return ev->type == LLC_STATION_EV_TYPE_PRIM &&
  171. ev->prim == LLC_DISABLE_PRIM &&
  172. ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
  173. }
  174. /**
  175. * llc_station_send_pdu - queues PDU to send
  176. * @skb: Address of the PDU
  177. *
  178. * Queues a PDU to send to the MAC layer.
  179. */
  180. static void llc_station_send_pdu(struct sk_buff *skb)
  181. {
  182. skb_queue_tail(&llc_main_station.mac_pdu_q, skb);
  183. while ((skb = skb_dequeue(&llc_main_station.mac_pdu_q)) != NULL)
  184. if (dev_queue_xmit(skb))
  185. break;
  186. }
  187. static int llc_station_ac_start_ack_timer(struct sk_buff *skb)
  188. {
  189. mod_timer(&llc_main_station.ack_timer, jiffies + LLC_ACK_TIME * HZ);
  190. return 0;
  191. }
  192. static int llc_station_ac_set_retry_cnt_0(struct sk_buff *skb)
  193. {
  194. llc_main_station.retry_count = 0;
  195. return 0;
  196. }
  197. static int llc_station_ac_inc_retry_cnt_by_1(struct sk_buff *skb)
  198. {
  199. llc_main_station.retry_count++;
  200. return 0;
  201. }
  202. static int llc_station_ac_set_xid_r_cnt_0(struct sk_buff *skb)
  203. {
  204. llc_main_station.xid_r_count = 0;
  205. return 0;
  206. }
  207. static int llc_station_ac_inc_xid_r_cnt_by_1(struct sk_buff *skb)
  208. {
  209. llc_main_station.xid_r_count++;
  210. return 0;
  211. }
  212. static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb)
  213. {
  214. int rc = 1;
  215. struct sk_buff *nskb = llc_alloc_frame(skb->dev);
  216. if (!nskb)
  217. goto out;
  218. llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
  219. llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127);
  220. rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, llc_station_mac_sa);
  221. if (rc)
  222. goto free;
  223. llc_station_send_pdu(nskb);
  224. out:
  225. return rc;
  226. free:
  227. kfree_skb(skb);
  228. goto out;
  229. }
  230. static int llc_station_ac_send_xid_r(struct sk_buff *skb)
  231. {
  232. u8 mac_da[ETH_ALEN], dsap;
  233. int rc = 1;
  234. struct sk_buff* nskb = llc_alloc_frame(skb->dev);
  235. if (!nskb)
  236. goto out;
  237. rc = 0;
  238. llc_pdu_decode_sa(skb, mac_da);
  239. llc_pdu_decode_ssap(skb, &dsap);
  240. llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
  241. llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
  242. rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da);
  243. if (rc)
  244. goto free;
  245. llc_station_send_pdu(nskb);
  246. out:
  247. return rc;
  248. free:
  249. kfree_skb(skb);
  250. goto out;
  251. }
  252. static int llc_station_ac_send_test_r(struct sk_buff *skb)
  253. {
  254. u8 mac_da[ETH_ALEN], dsap;
  255. int rc = 1;
  256. struct sk_buff *nskb = llc_alloc_frame(skb->dev);
  257. if (!nskb)
  258. goto out;
  259. rc = 0;
  260. llc_pdu_decode_sa(skb, mac_da);
  261. llc_pdu_decode_ssap(skb, &dsap);
  262. llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
  263. llc_pdu_init_as_test_rsp(nskb, skb);
  264. rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da);
  265. if (rc)
  266. goto free;
  267. llc_station_send_pdu(nskb);
  268. out:
  269. return rc;
  270. free:
  271. kfree_skb(skb);
  272. goto out;
  273. }
  274. static int llc_station_ac_report_status(struct sk_buff *skb)
  275. {
  276. return 0;
  277. }
  278. /* COMMON STATION STATE transitions */
  279. /* dummy last-transition indicator; common to all state transition groups
  280. * last entry for this state
  281. * all members are zeros, .bss zeroes it
  282. */
  283. static struct llc_station_state_trans llc_stat_state_trans_end;
  284. /* DOWN STATE transitions */
  285. /* state transition for LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK event */
  286. static llc_station_action_t llc_stat_down_state_actions_1[] = {
  287. [0] = llc_station_ac_start_ack_timer,
  288. [1] = llc_station_ac_set_retry_cnt_0,
  289. [2] = llc_station_ac_set_xid_r_cnt_0,
  290. [3] = llc_station_ac_send_null_dsap_xid_c,
  291. [4] = NULL,
  292. };
  293. static struct llc_station_state_trans llc_stat_down_state_trans_1 = {
  294. .ev = llc_stat_ev_enable_with_dup_addr_check,
  295. .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
  296. .ev_actions = llc_stat_down_state_actions_1,
  297. };
  298. /* state transition for LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK event */
  299. static llc_station_action_t llc_stat_down_state_actions_2[] = {
  300. [0] = llc_station_ac_report_status, /* STATION UP */
  301. [1] = NULL,
  302. };
  303. static struct llc_station_state_trans llc_stat_down_state_trans_2 = {
  304. .ev = llc_stat_ev_enable_without_dup_addr_check,
  305. .next_state = LLC_STATION_STATE_UP,
  306. .ev_actions = llc_stat_down_state_actions_2,
  307. };
  308. /* array of pointers; one to each transition */
  309. static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = {
  310. [0] = &llc_stat_down_state_trans_1,
  311. [1] = &llc_stat_down_state_trans_2,
  312. [2] = &llc_stat_state_trans_end,
  313. };
  314. /* UP STATE transitions */
  315. /* state transition for LLC_STATION_EV_DISABLE_REQ event */
  316. static llc_station_action_t llc_stat_up_state_actions_1[] = {
  317. [0] = llc_station_ac_report_status, /* STATION DOWN */
  318. [1] = NULL,
  319. };
  320. static struct llc_station_state_trans llc_stat_up_state_trans_1 = {
  321. .ev = llc_stat_ev_disable_req,
  322. .next_state = LLC_STATION_STATE_DOWN,
  323. .ev_actions = llc_stat_up_state_actions_1,
  324. };
  325. /* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */
  326. static llc_station_action_t llc_stat_up_state_actions_2[] = {
  327. [0] = llc_station_ac_send_xid_r,
  328. [1] = NULL,
  329. };
  330. static struct llc_station_state_trans llc_stat_up_state_trans_2 = {
  331. .ev = llc_stat_ev_rx_null_dsap_xid_c,
  332. .next_state = LLC_STATION_STATE_UP,
  333. .ev_actions = llc_stat_up_state_actions_2,
  334. };
  335. /* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */
  336. static llc_station_action_t llc_stat_up_state_actions_3[] = {
  337. [0] = llc_station_ac_send_test_r,
  338. [1] = NULL,
  339. };
  340. static struct llc_station_state_trans llc_stat_up_state_trans_3 = {
  341. .ev = llc_stat_ev_rx_null_dsap_test_c,
  342. .next_state = LLC_STATION_STATE_UP,
  343. .ev_actions = llc_stat_up_state_actions_3,
  344. };
  345. /* array of pointers; one to each transition */
  346. static struct llc_station_state_trans *llc_stat_up_state_trans [] = {
  347. [0] = &llc_stat_up_state_trans_1,
  348. [1] = &llc_stat_up_state_trans_2,
  349. [2] = &llc_stat_up_state_trans_3,
  350. [3] = &llc_stat_state_trans_end,
  351. };
  352. /* DUP ADDR CHK STATE transitions */
  353. /* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ
  354. * event
  355. */
  356. static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = {
  357. [0] = llc_station_ac_inc_xid_r_cnt_by_1,
  358. [1] = NULL,
  359. };
  360. static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = {
  361. .ev = llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq,
  362. .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
  363. .ev_actions = llc_stat_dupaddr_state_actions_1,
  364. };
  365. /* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ
  366. * event
  367. */
  368. static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = {
  369. [0] = llc_station_ac_report_status, /* DUPLICATE ADDRESS FOUND */
  370. [1] = NULL,
  371. };
  372. static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = {
  373. .ev = llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq,
  374. .next_state = LLC_STATION_STATE_DOWN,
  375. .ev_actions = llc_stat_dupaddr_state_actions_2,
  376. };
  377. /* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */
  378. static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = {
  379. [0] = llc_station_ac_send_xid_r,
  380. [1] = NULL,
  381. };
  382. static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = {
  383. .ev = llc_stat_ev_rx_null_dsap_xid_c,
  384. .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
  385. .ev_actions = llc_stat_dupaddr_state_actions_3,
  386. };
  387. /* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY
  388. * event
  389. */
  390. static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = {
  391. [0] = llc_station_ac_start_ack_timer,
  392. [1] = llc_station_ac_inc_retry_cnt_by_1,
  393. [2] = llc_station_ac_set_xid_r_cnt_0,
  394. [3] = llc_station_ac_send_null_dsap_xid_c,
  395. [4] = NULL,
  396. };
  397. static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = {
  398. .ev = llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry,
  399. .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
  400. .ev_actions = llc_stat_dupaddr_state_actions_4,
  401. };
  402. /* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY
  403. * event
  404. */
  405. static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = {
  406. [0] = llc_station_ac_report_status, /* STATION UP */
  407. [1] = NULL,
  408. };
  409. static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = {
  410. .ev = llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry,
  411. .next_state = LLC_STATION_STATE_UP,
  412. .ev_actions = llc_stat_dupaddr_state_actions_5,
  413. };
  414. /* state transition for LLC_STATION_EV_DISABLE_REQ event */
  415. static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = {
  416. [0] = llc_station_ac_report_status, /* STATION DOWN */
  417. [1] = NULL,
  418. };
  419. static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = {
  420. .ev = llc_stat_ev_disable_req,
  421. .next_state = LLC_STATION_STATE_DOWN,
  422. .ev_actions = llc_stat_dupaddr_state_actions_6,
  423. };
  424. /* array of pointers; one to each transition */
  425. static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = {
  426. [0] = &llc_stat_dupaddr_state_trans_6, /* Request */
  427. [1] = &llc_stat_dupaddr_state_trans_4, /* Timer */
  428. [2] = &llc_stat_dupaddr_state_trans_5,
  429. [3] = &llc_stat_dupaddr_state_trans_1, /* Receive frame */
  430. [4] = &llc_stat_dupaddr_state_trans_2,
  431. [5] = &llc_stat_dupaddr_state_trans_3,
  432. [6] = &llc_stat_state_trans_end,
  433. };
  434. static struct llc_station_state
  435. llc_station_state_table[LLC_NBR_STATION_STATES] = {
  436. [LLC_STATION_STATE_DOWN - 1] = {
  437. .curr_state = LLC_STATION_STATE_DOWN,
  438. .transitions = llc_stat_dwn_state_trans,
  439. },
  440. [LLC_STATION_STATE_DUP_ADDR_CHK - 1] = {
  441. .curr_state = LLC_STATION_STATE_DUP_ADDR_CHK,
  442. .transitions = llc_stat_dupaddr_state_trans,
  443. },
  444. [LLC_STATION_STATE_UP - 1] = {
  445. .curr_state = LLC_STATION_STATE_UP,
  446. .transitions = llc_stat_up_state_trans,
  447. },
  448. };
  449. /**
  450. * llc_exec_station_trans_actions - executes actions for transition
  451. * @trans: Address of the transition
  452. * @skb: Address of the event that caused the transition
  453. *
  454. * Executes actions of a transition of the station state machine. Returns
  455. * 0 if all actions complete successfully, nonzero otherwise.
  456. */
  457. static u16 llc_exec_station_trans_actions(struct llc_station_state_trans *trans,
  458. struct sk_buff *skb)
  459. {
  460. u16 rc = 0;
  461. llc_station_action_t *next_action = trans->ev_actions;
  462. for (; next_action && *next_action; next_action++)
  463. if ((*next_action)(skb))
  464. rc = 1;
  465. return rc;
  466. }
  467. /**
  468. * llc_find_station_trans - finds transition for this event
  469. * @skb: Address of the event
  470. *
  471. * Search thru events of the current state of the station until list
  472. * exhausted or it's obvious that the event is not valid for the current
  473. * state. Returns the address of the transition if cound, %NULL otherwise.
  474. */
  475. static struct llc_station_state_trans *
  476. llc_find_station_trans(struct sk_buff *skb)
  477. {
  478. int i = 0;
  479. struct llc_station_state_trans *rc = NULL;
  480. struct llc_station_state_trans **next_trans;
  481. struct llc_station_state *curr_state =
  482. &llc_station_state_table[llc_main_station.state - 1];
  483. for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
  484. if (!next_trans[i]->ev(skb)) {
  485. rc = next_trans[i];
  486. break;
  487. }
  488. return rc;
  489. }
  490. /**
  491. * llc_station_free_ev - frees an event
  492. * @skb: Address of the event
  493. *
  494. * Frees an event.
  495. */
  496. static void llc_station_free_ev(struct sk_buff *skb)
  497. {
  498. struct llc_station_state_ev *ev = llc_station_ev(skb);
  499. if (ev->type == LLC_STATION_EV_TYPE_PDU)
  500. kfree_skb(skb);
  501. }
  502. /**
  503. * llc_station_next_state - processes event and goes to the next state
  504. * @skb: Address of the event
  505. *
  506. * Processes an event, executes any transitions related to that event and
  507. * updates the state of the station.
  508. */
  509. static u16 llc_station_next_state(struct sk_buff *skb)
  510. {
  511. u16 rc = 1;
  512. struct llc_station_state_trans *trans;
  513. if (llc_main_station.state > LLC_NBR_STATION_STATES)
  514. goto out;
  515. trans = llc_find_station_trans(skb);
  516. if (trans) {
  517. /* got the state to which we next transition; perform the
  518. * actions associated with this transition before actually
  519. * transitioning to the next state
  520. */
  521. rc = llc_exec_station_trans_actions(trans, skb);
  522. if (!rc)
  523. /* transition station to next state if all actions
  524. * execute successfully; done; wait for next event
  525. */
  526. llc_main_station.state = trans->next_state;
  527. } else
  528. /* event not recognized in current state; re-queue it for
  529. * processing again at a later time; return failure
  530. */
  531. rc = 0;
  532. out:
  533. llc_station_free_ev(skb);
  534. return rc;
  535. }
  536. /**
  537. * llc_station_service_events - service events in the queue
  538. *
  539. * Get an event from the station event queue (if any); attempt to service
  540. * the event; if event serviced, get the next event (if any) on the event
  541. * queue; if event not service, re-queue the event on the event queue and
  542. * attempt to service the next event; when serviced all events in queue,
  543. * finished; if don't transition to different state, just service all
  544. * events once; if transition to new state, service all events again.
  545. * Caller must hold llc_main_station.ev_q.lock.
  546. */
  547. static void llc_station_service_events(void)
  548. {
  549. struct sk_buff *skb;
  550. while ((skb = skb_dequeue(&llc_main_station.ev_q.list)) != NULL)
  551. llc_station_next_state(skb);
  552. }
  553. /**
  554. * llc_station_state_process: queue event and try to process queue.
  555. * @skb: Address of the event
  556. *
  557. * Queues an event (on the station event queue) for handling by the
  558. * station state machine and attempts to process any queued-up events.
  559. */
  560. static void llc_station_state_process(struct sk_buff *skb)
  561. {
  562. spin_lock_bh(&llc_main_station.ev_q.lock);
  563. skb_queue_tail(&llc_main_station.ev_q.list, skb);
  564. llc_station_service_events();
  565. spin_unlock_bh(&llc_main_station.ev_q.lock);
  566. }
  567. static void llc_station_ack_tmr_cb(unsigned long timeout_data)
  568. {
  569. struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
  570. if (skb) {
  571. struct llc_station_state_ev *ev = llc_station_ev(skb);
  572. ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
  573. llc_station_state_process(skb);
  574. }
  575. }
  576. /*
  577. * llc_station_rcv - send received pdu to the station state machine
  578. * @skb: received frame.
  579. *
  580. * Sends data unit to station state machine.
  581. */
  582. static void llc_station_rcv(struct sk_buff *skb)
  583. {
  584. struct llc_station_state_ev *ev = llc_station_ev(skb);
  585. ev->type = LLC_STATION_EV_TYPE_PDU;
  586. ev->reason = 0;
  587. llc_station_state_process(skb);
  588. }
  589. int __init llc_station_init(void)
  590. {
  591. u16 rc = -ENOBUFS;
  592. struct sk_buff *skb;
  593. struct llc_station_state_ev *ev;
  594. skb_queue_head_init(&llc_main_station.mac_pdu_q);
  595. skb_queue_head_init(&llc_main_station.ev_q.list);
  596. spin_lock_init(&llc_main_station.ev_q.lock);
  597. init_timer(&llc_main_station.ack_timer);
  598. llc_main_station.ack_timer.data = (unsigned long)&llc_main_station;
  599. llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
  600. skb = alloc_skb(0, GFP_ATOMIC);
  601. if (!skb)
  602. goto out;
  603. rc = 0;
  604. llc_set_station_handler(llc_station_rcv);
  605. ev = llc_station_ev(skb);
  606. memset(ev, 0, sizeof(*ev));
  607. llc_main_station.ack_timer.expires = jiffies + 3 * HZ;
  608. llc_main_station.maximum_retry = 1;
  609. llc_main_station.state = LLC_STATION_STATE_DOWN;
  610. ev->type = LLC_STATION_EV_TYPE_SIMPLE;
  611. ev->prim_type = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
  612. rc = llc_station_next_state(skb);
  613. out:
  614. return rc;
  615. }
  616. void __exit llc_station_exit(void)
  617. {
  618. llc_set_station_handler(NULL);
  619. }