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.
6 * Class 2 llc algorithm.
7 * Pseudocode interpreter, transition table lookup,
8 * data_request & indicate primitives...
10 * Code for initialization, termination, registration and
13 * Copyright Tim Alpaerts,
14 * <Tim_Alpaerts@toyota-motor-europe.com>
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.
22 * Alan Cox : Chainsawed into Linux format
23 * Modified to use llc_ names
26 * This file must be processed by sed before it can be compiled.
29 #include <linux/types.h>
30 #include <linux/kernel.h>
31 #include <linux/slab.h>
32 #include <linux/netdevice.h>
33 #include <linux/skbuff.h>
34 #include <net/p8022.h>
35 #include <linux/proc_fs.h>
36 #include <linux/stat.h>
37 #include <asm/byteorder.h>
39 #include "pseudo/pseudocode.h"
40 #include "transit/pdutr.h"
41 #include "transit/timertr.h"
42 #include <net/llc_frame.h>
46 * Data_request() is called by the client to present a data unit
47 * to the llc for transmission.
48 * In the future this function should also check if the transmit window
49 * allows the sending of another pdu, and if not put the skb on the atq
50 * for deferred sending.
53 int llc_data_request(llcptr lp, struct sk_buff *skb)
55 if (skb_headroom(skb) < (lp->dev->hard_header_len +4)){
56 printk("cl2llc: data_request() not enough headroom in skb\n");
62 if ((lp->state != NORMAL) && (lp->state != BUSY) && (lp->state != REJECT))
64 printk("cl2llc: data_request() while no llc connection\n");
69 { /* if the remote llc is BUSY, */
70 ADD_TO_ATQ(skb); /* save skb in the await transmit queue */
76 * Else proceed with xmit
83 llc_interpret_pseudo_code(lp, NORMAL2, skb, NO_FRAME);
85 llc_interpret_pseudo_code(lp, NORMAL1, skb, NO_FRAME);
89 llc_interpret_pseudo_code(lp, BUSY2, skb, NO_FRAME);
91 llc_interpret_pseudo_code(lp, BUSY1, skb, NO_FRAME);
95 llc_interpret_pseudo_code(lp, REJECT2, skb, NO_FRAME);
97 llc_interpret_pseudo_code(lp, REJECT1, skb, NO_FRAME);
101 if(lp->llc_callbacks)
113 * Disconnect_request() requests that the llc to terminate a connection
116 void disconnect_request(llcptr lp)
118 if ((lp->state == NORMAL) ||
119 (lp->state == BUSY) ||
120 (lp->state == REJECT) ||
121 (lp->state == AWAIT) ||
122 (lp->state == AWAIT_BUSY) ||
123 (lp->state == AWAIT_REJECT))
126 llc_interpret_pseudo_code(lp, SH1, NULL, NO_FRAME);
127 if(lp->llc_callbacks)
133 * lp may be invalid after the callback
140 * Connect_request() requests that the llc to start a connection
143 void connect_request(llcptr lp)
145 if (lp->state == ADM)
148 llc_interpret_pseudo_code(lp, ADM1, NULL, NO_FRAME);
149 if(lp->llc_callbacks)
155 * lp may be invalid after the callback
162 * Interpret_pseudo_code() executes the actions in the connection component
163 * state transition table. Table 4 in document on p88.
165 * If this function is called to handle an incoming pdu, skb will point
166 * to the buffer with the pdu and type will contain the decoded pdu type.
168 * If called by data_request skb points to an skb that was skb_alloc-ed by
169 * the llc client to hold the information unit to be transmitted, there is
170 * no valid type in this case.
172 * If called because a timer expired no skb is passed, and there is no
176 void llc_interpret_pseudo_code(llcptr lp, int pc_label, struct sk_buff *skb,
179 short int pc; /* program counter in pseudo code array */
180 char p_flag_received;
182 int resend_count; /* number of pdus resend by llc_resend_ipdu() */
183 int ack_count; /* number of pdus acknowledged */
184 struct sk_buff *skb2;
188 fr = (frameptr) skb->data;
193 pc = pseudo_code_idx[pc_label];
194 while(pseudo_code[pc])
196 switch(pseudo_code[pc])
198 case IF_F=1_CLEAR_REMOTE_BUSY:
199 if ((type != I_CMD) || (fr->i_hdr.i_pflag == 0))
201 case CLEAR_REMOTE_BUSY:
203 llc_stop_timer(lp, BUSY_TIMER);
204 if ((lp->state == NORMAL) ||
205 (lp->state == REJECT) ||
208 skb2 = llc_pull_from_atq(lp);
210 llc_start_timer(lp, ACK_TIMER);
213 llc_sendipdu( lp, I_CMD, 0, skb2);
214 skb2 = llc_pull_from_atq(lp);
218 case CONNECT_INDICATION:
219 lp->state = NORMAL; /* needed to eliminate connect_response() */
220 lp->llc_mode = MODE_ABM;
221 lp->llc_callbacks|=LLC_CONN_INDICATION;
223 case CONNECT_CONFIRM:
224 lp->llc_mode = MODE_ABM;
225 lp->llc_callbacks|=LLC_CONN_CONFIRM;
227 case DATA_INDICATION:
230 lp->llc_callbacks|=LLC_DATA_INDIC;
232 case DISCONNECT_INDICATION:
233 lp->llc_mode = MODE_ADM;
234 lp->llc_callbacks|=LLC_DISC_INDICATION;
236 case RESET_INDICATION(LOCAL):
237 lp->llc_callbacks|=LLC_RESET_INDIC_LOC;
239 case RESET_INDICATION(REMOTE):
240 lp->llc_callbacks|=LLC_RESET_INDIC_REM;
243 lp->llc_callbacks|=LLC_RST_CONFIRM;
245 case REPORT_STATUS(FRMR_RECEIVED):
246 lp->llc_callbacks|=LLC_FRMR_RECV;
248 case REPORT_STATUS(FRMR_SENT):
249 lp->llc_callbacks|=LLC_FRMR_SENT;
251 case REPORT_STATUS(REMOTE_BUSY):
252 lp->llc_callbacks|=LLC_REMOTE_BUSY;
254 case REPORT_STATUS(REMOTE_NOT_BUSY):
255 lp->llc_callbacks|=LLC_REMOTE_NOTBUSY;
257 case SEND_DISC_CMD(P=X):
258 llc_sendpdu(lp, DISC_CMD, lp->f_flag, 0, NULL);
260 case SEND_DM_RSP(F=X):
261 llc_sendpdu(lp, DM_RSP, 0, 0, NULL);
263 case SEND_FRMR_RSP(F=X):
264 lp->frmr_info_fld.cntl1 = fr->pdu_cntl.byte1;
265 lp->frmr_info_fld.cntl2 = fr->pdu_cntl.byte2;
266 lp->frmr_info_fld.vs = lp->vs;
267 lp->frmr_info_fld.vr_cr = lp->vr;
268 llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);
270 case RE-SEND_FRMR_RSP(F=0):
271 llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);
273 case RE-SEND_FRMR_RSP(F=P):
274 llc_sendpdu(lp, FRMR_RSP, lp->p_flag,
275 5, (char *) &lp->frmr_info_fld);
277 case SEND_I_CMD(P=1):
278 llc_sendipdu(lp, I_CMD, 1, skb);
280 case RE-SEND_I_CMD(P=1):
281 resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);
283 case RE-SEND_I_CMD(P=1)_OR_SEND_RR:
284 resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);
285 if (resend_count == 0)
287 llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
290 case SEND_I_XXX(X=0):
291 llc_sendipdu(lp, I_CMD, 0, skb);
293 case RE-SEND_I_XXX(X=0):
294 resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);
296 case RE-SEND_I_XXX(X=0)_OR_SEND_RR:
297 resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);
298 if (resend_count == 0)
300 llc_sendpdu(lp, RR_CMD, 0, 0, NULL);
303 case RE-SEND_I_RSP(F=1):
304 resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_RSP, 1);
306 case SEND_REJ_CMD(P=1):
307 llc_sendpdu(lp, REJ_CMD, 1, 0, NULL);
309 case SEND_REJ_RSP(F=1):
310 llc_sendpdu(lp, REJ_RSP, 1, 0, NULL);
312 case SEND_REJ_XXX(X=0):
314 llc_sendpdu(lp, REJ_CMD, 0, 0, NULL);
316 llc_sendpdu(lp, REJ_RSP, 0, 0, NULL);
318 case SEND_RNR_CMD(F=1):
319 llc_sendpdu(lp, RNR_CMD, 1, 0, NULL);
321 case SEND_RNR_RSP(F=1):
322 llc_sendpdu(lp, RNR_RSP, 1, 0, NULL);
324 case SEND_RNR_XXX(X=0):
326 llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);
328 llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);
330 case SET_REMOTE_BUSY:
331 if (lp->remote_busy == 0)
334 llc_start_timer(lp, BUSY_TIMER);
335 lp->llc_callbacks|=LLC_REMOTE_BUSY;
337 else if (lp->timer_state[BUSY_TIMER] == TIMER_IDLE)
339 llc_start_timer(lp, BUSY_TIMER);
342 case OPTIONAL_SEND_RNR_XXX(X=0):
344 llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);
346 llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);
348 case SEND_RR_CMD(P=1):
349 llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
351 case SEND_ACKNOWLEDGE_CMD(P=1):
352 llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
354 case SEND_RR_RSP(F=1):
355 llc_sendpdu(lp, RR_RSP, 1, 0, NULL);
357 case SEND_ACKNOWLEDGE_RSP(F=1):
358 llc_sendpdu(lp, RR_RSP, 1, 0, NULL);
360 case SEND_RR_XXX(X=0):
361 llc_sendpdu(lp, RR_RSP, 0, 0, NULL);
363 case SEND_ACKNOWLEDGE_XXX(X=0):
365 llc_sendpdu(lp, RR_CMD, 0, 0, NULL);
367 llc_sendpdu(lp, RR_RSP, 0, 0, NULL);
369 case SEND_SABME_CMD(P=X):
370 llc_sendpdu(lp, SABME_CMD, 0, 0, NULL);
373 case SEND_UA_RSP(F=X):
374 llc_sendpdu(lp, UA_RSP, lp->f_flag, 0, NULL);
383 if(lp->timer_state[P_TIMER] == TIMER_RUNNING)
384 llc_stop_timer(lp, P_TIMER);
385 llc_start_timer(lp, P_TIMER);
392 case START_ACK_TIMER_IF_NOT_RUNNING:
393 if (lp->timer_state[ACK_TIMER] == TIMER_IDLE)
394 llc_start_timer(lp, ACK_TIMER);
396 case START_ACK_TIMER:
397 llc_start_timer(lp, ACK_TIMER);
399 case START_REJ_TIMER:
400 llc_start_timer(lp, REJ_TIMER);
403 llc_stop_timer(lp, ACK_TIMER);
406 llc_stop_timer(lp, ACK_TIMER);
409 case IF_DATA_FLAG=2_STOP_REJ_TIMER:
410 if (lp->data_flag == 2)
411 llc_stop_timer(lp, REJ_TIMER);
414 llc_stop_timer(lp, REJ_TIMER);
416 case STOP_ALL_TIMERS:
417 llc_stop_timer(lp, ACK_TIMER);
418 llc_stop_timer(lp, P_TIMER);
419 llc_stop_timer(lp, REJ_TIMER);
420 llc_stop_timer(lp, BUSY_TIMER);
422 case STOP_OTHER_TIMERS:
423 llc_stop_timer(lp, P_TIMER);
424 llc_stop_timer(lp, REJ_TIMER);
425 llc_stop_timer(lp, BUSY_TIMER);
427 case UPDATE_N(R)_RECEIVED:
428 ack_count = llc_free_acknowledged_skbs(lp,
429 (unsigned char) fr->s_hdr.nr);
433 llc_stop_timer(lp, ACK_TIMER);
434 if (skb_peek(&lp->rtq) != NULL)
437 * Re-transmit queue not empty
439 llc_start_timer(lp, ACK_TIMER);
445 p_flag_received = fr->u_hdr.u_pflag;
447 p_flag_received = fr->i_hdr.i_pflag;
448 if ((fr->pdu_hdr.ssap & 0x01) && (p_flag_received))
451 llc_stop_timer(lp, P_TIMER);
463 case IF_DATA_FLAG_=0_THEN_DATA_FLAG:=1:
464 if (lp->data_flag == 0)
471 lp->p_flag = lp->f_flag;
479 case RETRY_COUNT:=RETRY_COUNT+1:
492 lp->vs = fr->i_hdr.nr;
496 lp->f_flag = fr->u_hdr.u_pflag;
498 lp->f_flag = fr->i_hdr.i_pflag;
508 * Process_otype2_frame will handle incoming frames
509 * for 802.2 Type 2 Procedure.
512 void llc_process_otype2_frame(llcptr lp, struct sk_buff *skb, char type)
514 int idx; /* index in transition table */
515 int pc_label; /* action to perform, from tr tbl */
516 int validation; /* result of validate_seq_nos */
517 int p_flag_received; /* p_flag in received frame */
520 fr = (frameptr) skb->data;
523 p_flag_received = fr->u_hdr.u_pflag;
525 p_flag_received = fr->i_hdr.i_pflag;
529 /* Compute index in transition table: */
532 idx = (idx << 1) + p_flag_received;
544 idx = (idx << 1) + lp->p_flag;
552 validation = llc_validate_seq_nos(lp, fr);
559 idx = (idx << 1) + p_flag_received;
560 idx = (idx << 1) + lp->p_flag;
562 printk("llc_proc: bad state\n");
565 idx = (idx << 1) + pdutr_offset[lp->state];
566 lp->state = pdutr_entry[idx +1];
567 pc_label = pdutr_entry[idx];
570 llc_interpret_pseudo_code(lp, pc_label, skb, type);
571 if(lp->llc_callbacks)
577 * lp may no longer be valid after this point. Be
578 * careful what is added!
584 void llc_timer_expired(llcptr lp, int t)
586 int idx; /* index in transition table */
587 int pc_label; /* action to perform, from tr tbl */
589 lp->timer_state[t] = TIMER_EXPIRED;
590 idx = lp->state; /* Compute index in transition table: */
591 idx = (idx << 2) + t;
593 if (lp->retry_count >= lp->n2)
595 idx = (idx << 1) + lp->s_flag;
596 idx = (idx << 1) + lp->p_flag;
597 idx = idx << 1; /* 2 bytes per entry: action & newstate */
599 pc_label = timertr_entry[idx];
602 llc_interpret_pseudo_code(lp, pc_label, NULL, NO_FRAME);
603 lp->state = timertr_entry[idx +1];
605 lp->timer_state[t] = TIMER_IDLE;
606 if(lp->llc_callbacks)
612 * And lp may have vanished in the event callback