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