cl2llc.pre
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * NET An implementation of the IEEE 802.2 LLC protocol for the
  3.  * LINUX operating system.  LLC is implemented as a set of 
  4.  * state machines and callbacks for higher networking layers.
  5.  *
  6.  * Class 2 llc algorithm.
  7.  * Pseudocode interpreter, transition table lookup,
  8.  * data_request & indicate primitives...
  9.  *
  10.  * Code for initialization, termination, registration and 
  11.  * MAC layer glue.
  12.  *
  13.  * Copyright Tim Alpaerts, 
  14.  * <Tim_Alpaerts@toyota-motor-europe.com>
  15.  *
  16.  * This program is free software; you can redistribute it and/or
  17.  * modify it under the terms of the GNU General Public License
  18.  * as published by the Free Software Foundation; either version
  19.  * 2 of the License, or (at your option) any later version.
  20.  *
  21.  * Changes
  22.  * Alan Cox : Chainsawed into Linux format
  23.  * Modified to use llc_ names
  24.  * Changed callbacks
  25.  *
  26.  * This file must be processed by sed before it can be compiled.
  27.  */
  28. #include <linux/types.h>
  29. #include <linux/kernel.h>
  30. #include <linux/slab.h>
  31. #include <linux/netdevice.h>
  32. #include <linux/skbuff.h>
  33. #include <net/p8022.h>
  34. #include <linux/proc_fs.h>
  35. #include <linux/stat.h>
  36. #include <asm/byteorder.h>
  37. #include "pseudo/pseudocode.h"
  38. #include "transit/pdutr.h"
  39. #include "transit/timertr.h"
  40. #include <net/llc_frame.h>
  41. #include <net/llc.h>
  42. /*
  43.  * Data_request() is called by the client to present a data unit
  44.  * to the llc for transmission.
  45.  * In the future this function should also check if the transmit window
  46.  * allows the sending of another pdu, and if not put the skb on the atq
  47.  * for deferred sending.
  48.  */
  49. int llc_data_request(llcptr lp, struct sk_buff *skb)
  50. {
  51. if (skb_headroom(skb) < (lp->dev->hard_header_len +4)){
  52. printk("cl2llc: data_request() not enough headroom in skbn");
  53. return -1;
  54. };
  55. skb_push(skb, 4);
  56. if ((lp->state != NORMAL) && (lp->state != BUSY) && (lp->state != REJECT))
  57. {
  58. printk("cl2llc: data_request() while no llc connectionn"); 
  59. return -1;  
  60. }
  61. if (lp->remote_busy)
  62. {     /* if the remote llc is BUSY, */
  63. ADD_TO_ATQ(skb);      /* save skb in the await transmit queue */
  64. return 0;
  65. }                           
  66. else
  67. {
  68. /*
  69.  * Else proceed with xmit 
  70.  */
  71. switch(lp->state)
  72. {
  73. case NORMAL:
  74. if(lp->p_flag)
  75. llc_interpret_pseudo_code(lp, NORMAL2, skb, NO_FRAME);
  76. else
  77. llc_interpret_pseudo_code(lp, NORMAL1, skb, NO_FRAME);
  78. break;
  79. case BUSY:
  80. if (lp->p_flag)
  81. llc_interpret_pseudo_code(lp, BUSY2, skb, NO_FRAME);
  82. else
  83. llc_interpret_pseudo_code(lp, BUSY1, skb, NO_FRAME);
  84. break;
  85. case REJECT:
  86. if (lp->p_flag)
  87. llc_interpret_pseudo_code(lp, REJECT2, skb, NO_FRAME);
  88. else
  89. llc_interpret_pseudo_code(lp, REJECT1, skb, NO_FRAME);
  90. break;
  91. default:
  92. }
  93. if(lp->llc_callbacks)
  94. {
  95. lp->llc_event(lp);
  96. lp->llc_callbacks=0;
  97. }
  98. return 0;  
  99. }              
  100. }
  101. /* 
  102.  * Disconnect_request() requests that the llc to terminate a connection
  103.  */
  104. void disconnect_request(llcptr lp)
  105. {
  106. if ((lp->state == NORMAL) ||
  107.      (lp->state == BUSY) ||
  108. (lp->state == REJECT) ||
  109. (lp->state == AWAIT) ||
  110. (lp->state == AWAIT_BUSY) ||
  111. (lp->state == AWAIT_REJECT))
  112. {
  113. lp->state = D_CONN;
  114. llc_interpret_pseudo_code(lp, SH1, NULL, NO_FRAME);
  115. if(lp->llc_callbacks)
  116. {
  117. lp->llc_event(lp);
  118. lp->llc_callbacks=0;
  119. }
  120. /*
  121.    * lp may be invalid after the callback
  122.  */
  123. }
  124. }
  125. /*
  126.  * Connect_request() requests that the llc to start a connection
  127.  */
  128. void connect_request(llcptr lp)
  129. {
  130. if (lp->state == ADM)
  131. {
  132. lp->state = SETUP;
  133. llc_interpret_pseudo_code(lp, ADM1, NULL, NO_FRAME);
  134. if(lp->llc_callbacks)
  135. {
  136. lp->llc_event(lp);
  137. lp->llc_callbacks=0;
  138. }
  139. /*
  140.    * lp may be invalid after the callback
  141.  */
  142. }
  143. }
  144. /*
  145.  * Interpret_pseudo_code() executes the actions in the connection component
  146.  * state transition table. Table 4 in document on p88.
  147.  *
  148.  * If this function is called to handle an incoming pdu, skb will point
  149.  * to the buffer with the pdu and type will contain the decoded pdu type.
  150.  *
  151.  * If called by data_request skb points to an skb that was skb_alloc-ed by 
  152.  * the llc client to hold the information unit to be transmitted, there is
  153.  * no valid type in this case.  
  154.  *
  155.  * If called because a timer expired no skb is passed, and there is no 
  156.  * type.
  157.  */
  158. void llc_interpret_pseudo_code(llcptr lp, int pc_label, struct sk_buff *skb, 
  159. char type)
  160. {    
  161. short int pc; /* program counter in pseudo code array */ 
  162. char p_flag_received;
  163. frameptr fr;
  164. int resend_count;   /* number of pdus resend by llc_resend_ipdu() */
  165. int ack_count;      /* number of pdus acknowledged */
  166. struct sk_buff *skb2;
  167. if (skb != NULL) 
  168. {
  169. fr = (frameptr) skb->data;
  170. }
  171. else
  172. fr = NULL;
  173. pc = pseudo_code_idx[pc_label];
  174. while(pseudo_code[pc])
  175. {
  176. switch(pseudo_code[pc])
  177. {
  178. case IF_F=1_CLEAR_REMOTE_BUSY:
  179. if ((type != I_CMD) || (fr->i_hdr.i_pflag == 0))
  180. break;
  181. case CLEAR_REMOTE_BUSY:
  182. lp->remote_busy = 0;
  183. llc_stop_timer(lp, BUSY_TIMER);
  184. if ((lp->state == NORMAL) ||
  185. (lp->state == REJECT) ||
  186. (lp->state == BUSY))
  187. {
  188. skb2 = llc_pull_from_atq(lp);
  189. if (skb2 != NULL) 
  190. llc_start_timer(lp, ACK_TIMER);
  191. while (skb2 != NULL)
  192. {
  193. llc_sendipdu( lp, I_CMD, 0, skb2);
  194. skb2 = llc_pull_from_atq(lp);
  195. }
  196. }    
  197. break;
  198. case CONNECT_INDICATION:
  199. lp->state = NORMAL;  /* needed to eliminate connect_response() */
  200. lp->llc_mode = MODE_ABM;
  201. lp->llc_callbacks|=LLC_CONN_INDICATION;
  202. break;
  203. case CONNECT_CONFIRM:
  204. lp->llc_mode = MODE_ABM;
  205. lp->llc_callbacks|=LLC_CONN_CONFIRM;
  206. break;
  207. case DATA_INDICATION:
  208. skb_pull(skb, 4);
  209. lp->inc_skb=skb;
  210. lp->llc_callbacks|=LLC_DATA_INDIC;
  211. break;
  212. case DISCONNECT_INDICATION:
  213. lp->llc_mode = MODE_ADM;
  214. lp->llc_callbacks|=LLC_DISC_INDICATION;
  215. break;
  216. case RESET_INDICATION(LOCAL):
  217. lp->llc_callbacks|=LLC_RESET_INDIC_LOC;
  218. break;
  219. case RESET_INDICATION(REMOTE):
  220. lp->llc_callbacks|=LLC_RESET_INDIC_REM;
  221. break;
  222. case RESET_CONFIRM:
  223. lp->llc_callbacks|=LLC_RST_CONFIRM;
  224. break;
  225. case REPORT_STATUS(FRMR_RECEIVED):
  226. lp->llc_callbacks|=LLC_FRMR_RECV;
  227. break;
  228. case REPORT_STATUS(FRMR_SENT):
  229. lp->llc_callbacks|=LLC_FRMR_SENT;
  230. break;
  231. case REPORT_STATUS(REMOTE_BUSY):
  232. lp->llc_callbacks|=LLC_REMOTE_BUSY;
  233. break;
  234. case REPORT_STATUS(REMOTE_NOT_BUSY):
  235. lp->llc_callbacks|=LLC_REMOTE_NOTBUSY;
  236. break;
  237. case SEND_DISC_CMD(P=X):
  238. llc_sendpdu(lp, DISC_CMD, lp->f_flag, 0, NULL);
  239. break;
  240. case SEND_DM_RSP(F=X):
  241. llc_sendpdu(lp, DM_RSP, 0, 0, NULL);
  242. break;
  243. case SEND_FRMR_RSP(F=X):                        
  244. lp->frmr_info_fld.cntl1 = fr->pdu_cntl.byte1;
  245. lp->frmr_info_fld.cntl2 = fr->pdu_cntl.byte2;
  246. lp->frmr_info_fld.vs = lp->vs;
  247. lp->frmr_info_fld.vr_cr = lp->vr;
  248. llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);
  249. break;
  250. case RE-SEND_FRMR_RSP(F=0):
  251. llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);
  252. break;
  253. case RE-SEND_FRMR_RSP(F=P):
  254. llc_sendpdu(lp, FRMR_RSP, lp->p_flag,
  255. 5, (char *) &lp->frmr_info_fld);
  256. break;
  257. case SEND_I_CMD(P=1):
  258. llc_sendipdu(lp, I_CMD, 1, skb);   
  259. break;
  260. case RE-SEND_I_CMD(P=1):
  261. resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);
  262. break;
  263. case RE-SEND_I_CMD(P=1)_OR_SEND_RR:
  264. resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);
  265. if (resend_count == 0) 
  266. {
  267. llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
  268. }    
  269. break;
  270. case SEND_I_XXX(X=0):
  271. llc_sendipdu(lp, I_CMD, 0, skb);   
  272. break;
  273. case RE-SEND_I_XXX(X=0):
  274. resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);
  275. break;
  276. case RE-SEND_I_XXX(X=0)_OR_SEND_RR:
  277. resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);
  278. if (resend_count == 0) 
  279. {
  280. llc_sendpdu(lp, RR_CMD, 0, 0, NULL);
  281. }    
  282. break;
  283. case RE-SEND_I_RSP(F=1):
  284. resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_RSP, 1);
  285. break;
  286. case SEND_REJ_CMD(P=1):
  287. llc_sendpdu(lp, REJ_CMD, 1, 0, NULL);
  288. break;
  289. case SEND_REJ_RSP(F=1):
  290. llc_sendpdu(lp, REJ_RSP, 1, 0, NULL);
  291. break;
  292. case SEND_REJ_XXX(X=0):
  293. if (IS_RSP(fr))
  294. llc_sendpdu(lp, REJ_CMD, 0, 0, NULL);
  295. else
  296. llc_sendpdu(lp, REJ_RSP, 0, 0, NULL);
  297. break;
  298. case SEND_RNR_CMD(F=1):
  299. llc_sendpdu(lp, RNR_CMD, 1, 0, NULL);
  300. break;
  301. case SEND_RNR_RSP(F=1):
  302. llc_sendpdu(lp, RNR_RSP, 1, 0, NULL);
  303. break;
  304. case SEND_RNR_XXX(X=0):
  305. if (IS_RSP(fr))
  306. llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);
  307. else
  308. llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);
  309. break;
  310. case SET_REMOTE_BUSY:
  311. if (lp->remote_busy == 0)
  312. {
  313. lp->remote_busy = 1;
  314. llc_start_timer(lp, BUSY_TIMER);
  315. lp->llc_callbacks|=LLC_REMOTE_BUSY;
  316. }
  317. else if (lp->timer_state[BUSY_TIMER] == TIMER_IDLE)
  318. {
  319. llc_start_timer(lp, BUSY_TIMER);
  320. }
  321. break;
  322. case OPTIONAL_SEND_RNR_XXX(X=0):
  323. if (IS_RSP(fr)) 
  324. llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);
  325. else
  326. llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);
  327. break;
  328. case SEND_RR_CMD(P=1):
  329. llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
  330. break;
  331. case SEND_ACKNOWLEDGE_CMD(P=1):
  332. llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
  333. break;
  334. case SEND_RR_RSP(F=1):
  335. llc_sendpdu(lp, RR_RSP, 1, 0, NULL);
  336. break;
  337. case SEND_ACKNOWLEDGE_RSP(F=1):
  338. llc_sendpdu(lp, RR_RSP, 1, 0, NULL);
  339. break;
  340. case SEND_RR_XXX(X=0):
  341. llc_sendpdu(lp, RR_RSP, 0, 0, NULL);
  342. break;
  343. case SEND_ACKNOWLEDGE_XXX(X=0):
  344. if (IS_RSP(fr)) 
  345. llc_sendpdu(lp, RR_CMD, 0, 0, NULL);
  346. else
  347. llc_sendpdu(lp, RR_RSP, 0, 0, NULL);
  348. break;
  349. case SEND_SABME_CMD(P=X):
  350. llc_sendpdu(lp, SABME_CMD, 0, 0, NULL);
  351. lp->f_flag = 0;
  352. break;
  353. case SEND_UA_RSP(F=X):
  354. llc_sendpdu(lp, UA_RSP, lp->f_flag, 0, NULL);
  355. break;
  356. case S_FLAG:=0:
  357. lp->s_flag = 0;
  358. break;
  359. case S_FLAG:=1:
  360. lp->s_flag = 1;
  361. break;
  362. case START_P_TIMER:
  363. if(lp->timer_state[P_TIMER] == TIMER_RUNNING)
  364. llc_stop_timer(lp, P_TIMER);
  365. llc_start_timer(lp, P_TIMER);
  366. if (lp->p_flag == 0)
  367. {
  368. lp->retry_count = 0;
  369. lp->p_flag = 1;
  370. }
  371. break;
  372. case START_ACK_TIMER_IF_NOT_RUNNING:
  373. if (lp->timer_state[ACK_TIMER] == TIMER_IDLE)
  374. llc_start_timer(lp, ACK_TIMER);
  375. break;
  376. case START_ACK_TIMER:
  377. llc_start_timer(lp, ACK_TIMER);
  378. break;
  379. case START_REJ_TIMER:
  380. llc_start_timer(lp, REJ_TIMER);
  381. break;
  382. case STOP_ACK_TIMER:
  383. llc_stop_timer(lp, ACK_TIMER);
  384. break;
  385. case STOP_P_TIMER:
  386. llc_stop_timer(lp, ACK_TIMER);
  387. lp->p_flag = 0;
  388. break;
  389. case IF_DATA_FLAG=2_STOP_REJ_TIMER:
  390. if (lp->data_flag == 2)
  391. llc_stop_timer(lp, REJ_TIMER);
  392. break;
  393. case STOP_REJ_TIMER:
  394. llc_stop_timer(lp, REJ_TIMER);
  395. break;
  396. case STOP_ALL_TIMERS:
  397. llc_stop_timer(lp, ACK_TIMER);
  398. llc_stop_timer(lp, P_TIMER);
  399. llc_stop_timer(lp, REJ_TIMER);
  400. llc_stop_timer(lp, BUSY_TIMER);
  401. break;
  402. case STOP_OTHER_TIMERS:
  403. llc_stop_timer(lp, P_TIMER);
  404. llc_stop_timer(lp, REJ_TIMER);
  405. llc_stop_timer(lp, BUSY_TIMER);
  406. break;
  407. case UPDATE_N(R)_RECEIVED:             
  408. ack_count = llc_free_acknowledged_skbs(lp,
  409. (unsigned char) fr->s_hdr.nr);
  410. if (ack_count > 0)
  411. {
  412. lp->retry_count = 0;
  413. llc_stop_timer(lp, ACK_TIMER);  
  414. if (skb_peek(&lp->rtq) != NULL)
  415. {
  416. /*
  417.    * Re-transmit queue not empty 
  418.  */
  419. llc_start_timer(lp, ACK_TIMER);  
  420. }
  421. }        
  422. break;
  423. case UPDATE_P_FLAG:
  424. if (IS_UFRAME(fr)) 
  425. p_flag_received = fr->u_hdr.u_pflag;
  426. else
  427. p_flag_received = fr->i_hdr.i_pflag;
  428. if ((fr->pdu_hdr.ssap & 0x01) && (p_flag_received))
  429. {
  430. lp->p_flag = 0;
  431. llc_stop_timer(lp, P_TIMER);  
  432. }
  433. break;
  434. case DATA_FLAG:=2:
  435. lp->data_flag = 2;
  436. break;
  437. case DATA_FLAG:=0:
  438. lp->data_flag = 0;
  439. break;
  440. case DATA_FLAG:=1:
  441. lp->data_flag = 1;
  442. break;
  443. case IF_DATA_FLAG_=0_THEN_DATA_FLAG:=1:
  444. if (lp->data_flag == 0)
  445. lp->data_flag = 1;
  446. break;
  447. case P_FLAG:=0:
  448. lp->p_flag = 0;
  449. break;
  450. case P_FLAG:=P:
  451. lp->p_flag = lp->f_flag;
  452. break;
  453. case REMOTE_BUSY:=0:
  454. lp->remote_busy = 0;
  455. break;
  456. case RETRY_COUNT:=0:
  457. lp->retry_count = 0;
  458. break;
  459. case RETRY_COUNT:=RETRY_COUNT+1:
  460. lp->retry_count++;
  461. break;
  462. case V(R):=0:
  463. lp->vr = 0;
  464. break;
  465. case V(R):=V(R)+1:
  466. lp->vr++;
  467. break;
  468. case V(S):=0:
  469. lp->vs = 0;
  470. break;
  471. case V(S):=N(R):
  472. lp->vs = fr->i_hdr.nr;
  473. break;
  474. case F_FLAG:=P:
  475. if (IS_UFRAME(fr)) 
  476. lp->f_flag = fr->u_hdr.u_pflag;
  477. else
  478. lp->f_flag = fr->i_hdr.i_pflag;
  479. break;
  480. default:
  481. }
  482. pc++;
  483. }
  484. }
  485. /*
  486.  * Process_otype2_frame will handle incoming frames
  487.  * for 802.2 Type 2 Procedure.
  488.  */
  489. void llc_process_otype2_frame(llcptr lp, struct sk_buff *skb, char type)
  490. {
  491. int idx; /* index in transition table */
  492. int pc_label; /* action to perform, from tr tbl */
  493. int validation; /* result of validate_seq_nos */
  494. int p_flag_received; /* p_flag in received frame */
  495. frameptr fr;
  496. fr = (frameptr) skb->data;
  497. if (IS_UFRAME(fr))
  498. p_flag_received = fr->u_hdr.u_pflag;
  499. else
  500. p_flag_received = fr->i_hdr.i_pflag;
  501. switch(lp->state)
  502. {
  503. /* Compute index in transition table: */
  504. case ADM:
  505. idx = type;
  506. idx = (idx << 1) + p_flag_received;
  507. break;
  508. case CONN:
  509. case RESET_WAIT:
  510. case RESET_CHECK:
  511. case ERROR:
  512. idx = type;
  513. break;
  514. case SETUP:
  515. case RESET:
  516. case D_CONN:
  517. idx = type;
  518. idx = (idx << 1) + lp->p_flag;
  519. break;
  520. case NORMAL:
  521. case BUSY:
  522. case REJECT:
  523. case AWAIT:
  524. case AWAIT_BUSY:
  525. case AWAIT_REJECT:
  526. validation = llc_validate_seq_nos(lp, fr);
  527. if (validation > 3) 
  528. type = BAD_FRAME;
  529. idx = type;
  530. idx = (idx << 1);
  531. if (validation & 1) 
  532. idx = idx +1;
  533. idx = (idx << 1) + p_flag_received;
  534. idx = (idx << 1) + lp->p_flag;
  535. default:
  536. printk("llc_proc: bad staten");
  537. return;
  538. }
  539. idx = (idx << 1) + pdutr_offset[lp->state];
  540. lp->state = pdutr_entry[idx +1]; 
  541. pc_label = pdutr_entry[idx];
  542. if (pc_label != NOP)
  543. llc_interpret_pseudo_code(lp, pc_label, skb, type);
  544. if(lp->llc_callbacks)
  545. {
  546. lp->llc_event(lp);
  547. lp->llc_callbacks=0;
  548. }
  549. /*
  550.    * lp may no longer be valid after this point. Be
  551.  * careful what is added!
  552.  */
  553. }
  554. }
  555. void llc_timer_expired(llcptr lp, int t)
  556. {
  557. int idx; /* index in transition table */
  558. int pc_label;        /* action to perform, from tr tbl */
  559. lp->timer_state[t] = TIMER_EXPIRED;
  560. idx = lp->state;            /* Compute index in transition table: */
  561. idx = (idx << 2) + t;
  562. idx = idx << 1;
  563. if (lp->retry_count >= lp->n2) 
  564. idx = idx + 1;
  565. idx = (idx << 1) + lp->s_flag;
  566. idx = (idx << 1) + lp->p_flag;
  567. idx = idx << 1;             /* 2 bytes per entry: action & newstate */
  568. pc_label = timertr_entry[idx];
  569. if (pc_label != NOP)
  570. {
  571. llc_interpret_pseudo_code(lp, pc_label, NULL, NO_FRAME);
  572. lp->state = timertr_entry[idx +1];
  573. }
  574. lp->timer_state[t] = TIMER_IDLE;
  575. if(lp->llc_callbacks)
  576. {
  577. lp->llc_event(lp);
  578. lp->llc_callbacks=0;
  579. }
  580. /*
  581.    * And lp may have vanished in the event callback
  582.    */
  583. }