blob: 860140caa6e0ea9aa0a2b61114456e6d74a0db6b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * llc_c_ac.c - actions performed during connection state transition.
3 *
4 * Description:
5 * Functions in this module are implementation of connection component actions
6 * Details of actions can be found in IEEE-802.2 standard document.
7 * All functions have one connection and one event as input argument. All of
8 * them return 0 On success and 1 otherwise.
9 *
10 * Copyright (c) 1997 by Procom Technology, Inc.
11 * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
12 *
13 * This program can be redistributed or modified under the terms of the
14 * GNU General Public License as published by the Free Software Foundation.
15 * This program is distributed without any warranty or implied warranty
16 * of merchantability or fitness for a particular purpose.
17 *
18 * See the GNU General Public License for more details.
19 */
20#include <linux/netdevice.h>
21#include <net/llc_conn.h>
22#include <net/llc_sap.h>
23#include <net/sock.h>
24#include <net/llc_c_ev.h>
25#include <net/llc_c_ac.h>
26#include <net/llc_c_st.h>
27#include <net/llc_pdu.h>
28#include <net/llc.h>
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
32static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
33static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev);
34
35static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb);
36
37static int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk,
38 struct sk_buff *skb);
39
40static int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb);
41
42#define INCORRECT 0
43
44int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb)
45{
46 struct llc_sock *llc = llc_sk(sk);
47
48 if (llc->remote_busy_flag) {
49 u8 nr;
50 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
51
52 llc->remote_busy_flag = 0;
53 del_timer(&llc->busy_state_timer.timer);
54 nr = LLC_I_GET_NR(pdu);
55 llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
56 }
57 return 0;
58}
59
60int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
61{
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -030062 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -030064 ev->ind_prim = LLC_CONN_PRIM;
65 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066}
67
68int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
69{
70 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
71
72 ev->cfm_prim = LLC_CONN_PRIM;
73 return 0;
74}
75
76static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
77{
78 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
79
80 ev->cfm_prim = LLC_DATA_PRIM;
81 return 0;
82}
83
84int llc_conn_ac_data_ind(struct sock *sk, struct sk_buff *skb)
85{
86 llc_conn_rtn_pdu(sk, skb);
87 return 0;
88}
89
90int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
91{
92 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
93 u8 reason = 0;
94 int rc = 0;
95
96 if (ev->type == LLC_CONN_EV_TYPE_PDU) {
97 struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
98
99 if (LLC_PDU_IS_RSP(pdu) &&
100 LLC_PDU_TYPE_IS_U(pdu) &&
101 LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM)
102 reason = LLC_DISC_REASON_RX_DM_RSP_PDU;
103 else if (LLC_PDU_IS_CMD(pdu) &&
104 LLC_PDU_TYPE_IS_U(pdu) &&
105 LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC)
106 reason = LLC_DISC_REASON_RX_DISC_CMD_PDU;
107 } else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR)
108 reason = LLC_DISC_REASON_ACK_TMR_EXP;
Arnaldo Carvalho de Melobdcc66c2005-09-22 03:38:15 -0300109 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 if (!rc) {
112 ev->reason = reason;
113 ev->ind_prim = LLC_DISC_PRIM;
114 }
115 return rc;
116}
117
118int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
119{
120 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
121
122 ev->reason = ev->status;
123 ev->cfm_prim = LLC_DISC_PRIM;
124 return 0;
125}
126
127int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
128{
129 u8 reason = 0;
130 int rc = 1;
131 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
132 struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
133 struct llc_sock *llc = llc_sk(sk);
134
135 switch (ev->type) {
136 case LLC_CONN_EV_TYPE_PDU:
137 if (LLC_PDU_IS_RSP(pdu) &&
138 LLC_PDU_TYPE_IS_U(pdu) &&
139 LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR) {
140 reason = LLC_RESET_REASON_LOCAL;
141 rc = 0;
142 } else if (LLC_PDU_IS_CMD(pdu) &&
143 LLC_PDU_TYPE_IS_U(pdu) &&
144 LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME) {
145 reason = LLC_RESET_REASON_REMOTE;
146 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 }
148 break;
149 case LLC_CONN_EV_TYPE_ACK_TMR:
150 case LLC_CONN_EV_TYPE_P_TMR:
151 case LLC_CONN_EV_TYPE_REJ_TMR:
152 case LLC_CONN_EV_TYPE_BUSY_TMR:
153 if (llc->retry_count > llc->n2) {
154 reason = LLC_RESET_REASON_LOCAL;
155 rc = 0;
Arnaldo Carvalho de Melobdcc66c2005-09-22 03:38:15 -0300156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 break;
158 }
159 if (!rc) {
160 ev->reason = reason;
161 ev->ind_prim = LLC_RESET_PRIM;
162 }
163 return rc;
164}
165
166int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb)
167{
168 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
169
170 ev->reason = 0;
171 ev->cfm_prim = LLC_RESET_PRIM;
172 return 0;
173}
174
175int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk,
176 struct sk_buff *skb)
177{
178 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
179
180 if (LLC_PDU_IS_RSP(pdu) &&
181 LLC_PDU_TYPE_IS_I(pdu) &&
182 LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf)
183 llc_conn_ac_clear_remote_busy(sk, skb);
184 return 0;
185}
186
187int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
188 struct sk_buff *skb)
189{
190 struct llc_sock *llc = llc_sk(sk);
191
192 if (llc->data_flag == 2)
193 del_timer(&llc->rej_sent_timer.timer);
194 return 0;
195}
196
197int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
198{
199 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300200 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300201 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 struct llc_sap *sap = llc->sap;
205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
207 llc->daddr.lsap, LLC_PDU_CMD);
208 llc_pdu_init_as_disc_cmd(nskb, 1);
209 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300210 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 goto free;
212 llc_conn_send_pdu(sk, nskb);
213 llc_conn_ac_set_p_flag_1(sk, skb);
214 }
215out:
216 return rc;
217free:
218 kfree_skb(nskb);
219 goto out;
220}
221
222int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
223{
224 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300225 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300226 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 struct llc_sap *sap = llc->sap;
230 u8 f_bit;
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 llc_pdu_decode_pf_bit(skb, &f_bit);
233 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
234 llc->daddr.lsap, LLC_PDU_RSP);
235 llc_pdu_init_as_dm_rsp(nskb, f_bit);
236 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300237 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 goto free;
239 llc_conn_send_pdu(sk, nskb);
240 }
241out:
242 return rc;
243free:
244 kfree_skb(nskb);
245 goto out;
246}
247
248int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
249{
250 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300251 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300252 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 struct llc_sap *sap = llc->sap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
258 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300259 llc_pdu_init_as_dm_rsp(nskb, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300261 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 goto free;
263 llc_conn_send_pdu(sk, nskb);
264 }
265out:
266 return rc;
267free:
268 kfree_skb(nskb);
269 goto out;
270}
271
272int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb)
273{
274 u8 f_bit;
275 int rc = -ENOBUFS;
276 struct sk_buff *nskb;
277 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
278 struct llc_sock *llc = llc_sk(sk);
279
280 llc->rx_pdu_hdr = *((u32 *)pdu);
281 if (LLC_PDU_IS_CMD(pdu))
282 llc_pdu_decode_pf_bit(skb, &f_bit);
283 else
284 f_bit = 0;
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300285 nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (nskb) {
287 struct llc_sap *sap = llc->sap;
288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
290 llc->daddr.lsap, LLC_PDU_RSP);
291 llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
292 llc->vR, INCORRECT);
293 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300294 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 goto free;
296 llc_conn_send_pdu(sk, nskb);
297 }
298out:
299 return rc;
300free:
301 kfree_skb(nskb);
302 goto out;
303}
304
305int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb)
306{
307 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300308 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300309 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct llc_sap *sap = llc->sap;
313 struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)&llc->rx_pdu_hdr;
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
316 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300317 llc_pdu_init_as_frmr_rsp(nskb, pdu, 0, llc->vS,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 llc->vR, INCORRECT);
319 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300320 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 goto free;
322 llc_conn_send_pdu(sk, nskb);
323 }
324out:
325 return rc;
326free:
327 kfree_skb(nskb);
328 goto out;
329}
330
331int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
332{
333 u8 f_bit;
334 int rc = -ENOBUFS;
335 struct sk_buff *nskb;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300336 struct llc_sock *llc = llc_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 llc_pdu_decode_pf_bit(skb, &f_bit);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300339 nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 struct llc_sap *sap = llc->sap;
342 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
345 llc->daddr.lsap, LLC_PDU_RSP);
346 llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
347 llc->vR, INCORRECT);
348 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300349 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 goto free;
351 llc_conn_send_pdu(sk, nskb);
352 }
353out:
354 return rc;
355free:
356 kfree_skb(nskb);
357 goto out;
358}
359
360int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
361{
362 int rc;
363 struct llc_sock *llc = llc_sk(sk);
364 struct llc_sap *sap = llc->sap;
365
366 llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
367 llc->daddr.lsap, LLC_PDU_CMD);
368 llc_pdu_init_as_i_cmd(skb, 1, llc->vS, llc->vR);
369 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300370 if (likely(!rc)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 llc_conn_send_pdu(sk, skb);
372 llc_conn_ac_inc_vs_by_1(sk, skb);
373 }
374 return rc;
375}
376
377static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
378{
379 int rc;
380 struct llc_sock *llc = llc_sk(sk);
381 struct llc_sap *sap = llc->sap;
382
383 llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
384 llc->daddr.lsap, LLC_PDU_CMD);
385 llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
386 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300387 if (likely(!rc)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 llc_conn_send_pdu(sk, skb);
389 llc_conn_ac_inc_vs_by_1(sk, skb);
390 }
391 return rc;
392}
393
394int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
395{
396 int rc;
397 struct llc_sock *llc = llc_sk(sk);
398 struct llc_sap *sap = llc->sap;
399
400 llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
401 llc->daddr.lsap, LLC_PDU_CMD);
402 llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
403 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300404 if (likely(!rc)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 llc_conn_send_pdu(sk, skb);
406 llc_conn_ac_inc_vs_by_1(sk, skb);
407 }
408 return 0;
409}
410
411int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
412{
413 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
414 u8 nr = LLC_I_GET_NR(pdu);
415
416 llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
417 return 0;
418}
419
420int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
421 struct sk_buff *skb)
422{
423 u8 nr;
424 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
425 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300426 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300427 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 struct llc_sap *sap = llc->sap;
431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
433 llc->daddr.lsap, LLC_PDU_RSP);
434 llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
435 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300436 if (likely(!rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 llc_conn_send_pdu(sk, nskb);
438 else
439 kfree_skb(skb);
440 }
441 if (rc) {
442 nr = LLC_I_GET_NR(pdu);
443 rc = 0;
444 llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
445 }
446 return rc;
447}
448
449int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
450{
451 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
452 u8 nr = LLC_I_GET_NR(pdu);
453
454 llc_conn_resend_i_pdu_as_rsp(sk, nr, 1);
455 return 0;
456}
457
458int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
459{
460 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300461 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300462 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 struct llc_sap *sap = llc->sap;
466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
468 llc->daddr.lsap, LLC_PDU_CMD);
469 llc_pdu_init_as_rej_cmd(nskb, 1, llc->vR);
470 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300471 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 goto free;
473 llc_conn_send_pdu(sk, nskb);
474 }
475out:
476 return rc;
477free:
478 kfree_skb(nskb);
479 goto out;
480}
481
482int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
483{
484 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300485 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300486 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 struct llc_sap *sap = llc->sap;
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
492 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300493 llc_pdu_init_as_rej_rsp(nskb, 1, llc->vR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300495 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 goto free;
497 llc_conn_send_pdu(sk, nskb);
498 }
499out:
500 return rc;
501free:
502 kfree_skb(nskb);
503 goto out;
504}
505
506int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
507{
508 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300509 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300510 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 struct llc_sap *sap = llc->sap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
516 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300517 llc_pdu_init_as_rej_rsp(nskb, 0, llc->vR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300519 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 goto free;
521 llc_conn_send_pdu(sk, nskb);
522 }
523out:
524 return rc;
525free:
526 kfree_skb(nskb);
527 goto out;
528}
529
530int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
531{
532 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300533 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300534 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 struct llc_sap *sap = llc->sap;
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
540 llc->daddr.lsap, LLC_PDU_CMD);
541 llc_pdu_init_as_rnr_cmd(nskb, 1, llc->vR);
542 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300543 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 goto free;
545 llc_conn_send_pdu(sk, nskb);
546 }
547out:
548 return rc;
549free:
550 kfree_skb(nskb);
551 goto out;
552}
553
554int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
555{
556 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300557 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300558 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 struct llc_sap *sap = llc->sap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
564 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300565 llc_pdu_init_as_rnr_rsp(nskb, 1, llc->vR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300567 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 goto free;
569 llc_conn_send_pdu(sk, nskb);
570 }
571out:
572 return rc;
573free:
574 kfree_skb(nskb);
575 goto out;
576}
577
578int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
579{
580 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300581 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300582 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
584 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 struct llc_sap *sap = llc->sap;
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
588 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300589 llc_pdu_init_as_rnr_rsp(nskb, 0, llc->vR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300591 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 goto free;
593 llc_conn_send_pdu(sk, nskb);
594 }
595out:
596 return rc;
597free:
598 kfree_skb(nskb);
599 goto out;
600}
601
602int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
603{
604 struct llc_sock *llc = llc_sk(sk);
605
606 if (!llc->remote_busy_flag) {
607 llc->remote_busy_flag = 1;
608 mod_timer(&llc->busy_state_timer.timer,
Arnaldo Carvalho de Melo590232a2005-09-22 04:30:44 -0300609 jiffies + llc->busy_state_timer.expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 }
611 return 0;
612}
613
614int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
615{
616 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300617 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300618 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 struct llc_sap *sap = llc->sap;
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
624 llc->daddr.lsap, LLC_PDU_RSP);
625 llc_pdu_init_as_rnr_rsp(nskb, 0, llc->vR);
626 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300627 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 goto free;
629 llc_conn_send_pdu(sk, nskb);
630 }
631out:
632 return rc;
633free:
634 kfree_skb(nskb);
635 goto out;
636}
637
638int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
639{
640 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300641 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300642 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 struct llc_sap *sap = llc->sap;
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
648 llc->daddr.lsap, LLC_PDU_CMD);
649 llc_pdu_init_as_rr_cmd(nskb, 1, llc->vR);
650 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300651 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 goto free;
653 llc_conn_send_pdu(sk, nskb);
654 }
655out:
656 return rc;
657free:
658 kfree_skb(nskb);
659 goto out;
660}
661
662int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
663{
664 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300665 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300666 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 struct llc_sap *sap = llc->sap;
670 u8 f_bit = 1;
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
673 llc->daddr.lsap, LLC_PDU_RSP);
674 llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
675 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300676 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 goto free;
678 llc_conn_send_pdu(sk, nskb);
679 }
680out:
681 return rc;
682free:
683 kfree_skb(nskb);
684 goto out;
685}
686
687int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
688{
689 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300690 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300691 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 struct llc_sap *sap = llc->sap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
697 llc->daddr.lsap, LLC_PDU_RSP);
Arnaldo Carvalho de Melo838a75d2005-09-22 03:44:23 -0300698 llc_pdu_init_as_rr_rsp(nskb, 1, llc->vR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300700 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 goto free;
702 llc_conn_send_pdu(sk, nskb);
703 }
704out:
705 return rc;
706free:
707 kfree_skb(nskb);
708 goto out;
709}
710
711int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
712{
713 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300714 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300715 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 struct llc_sap *sap = llc->sap;
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
721 llc->daddr.lsap, LLC_PDU_RSP);
722 llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
723 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300724 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 goto free;
726 llc_conn_send_pdu(sk, nskb);
727 }
728out:
729 return rc;
730free:
731 kfree_skb(nskb);
732 goto out;
733}
734
735int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
736{
737 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300738 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300739 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 struct llc_sap *sap = llc->sap;
743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
745 llc->daddr.lsap, LLC_PDU_RSP);
746 llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
747 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300748 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 goto free;
750 llc_conn_send_pdu(sk, nskb);
751 }
752out:
753 return rc;
754free:
755 kfree_skb(nskb);
756 goto out;
757}
758
759void llc_conn_set_p_flag(struct sock *sk, u8 value)
760{
761 int state_changed = llc_sk(sk)->p_flag && !value;
762
763 llc_sk(sk)->p_flag = value;
764
765 if (state_changed)
766 sk->sk_state_change(sk);
767}
768
769int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
770{
771 int rc = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300773 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 if (nskb) {
776 struct llc_sap *sap = llc->sap;
777 u8 *dmac = llc->daddr.mac;
778
779 if (llc->dev->flags & IFF_LOOPBACK)
780 dmac = llc->dev->dev_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
782 llc->daddr.lsap, LLC_PDU_CMD);
783 llc_pdu_init_as_sabme_cmd(nskb, 1);
784 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, dmac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300785 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 goto free;
787 llc_conn_send_pdu(sk, nskb);
788 llc_conn_set_p_flag(sk, 1);
789 }
790out:
791 return rc;
792free:
793 kfree_skb(nskb);
794 goto out;
795}
796
797int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
798{
799 u8 f_bit;
800 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300801 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300802 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 llc_pdu_decode_pf_bit(skb, &f_bit);
805 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 struct llc_sap *sap = llc->sap;
807
808 nskb->dev = llc->dev;
809 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
810 llc->daddr.lsap, LLC_PDU_RSP);
811 llc_pdu_init_as_ua_rsp(nskb, f_bit);
812 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300813 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 goto free;
815 llc_conn_send_pdu(sk, nskb);
816 }
817out:
818 return rc;
819free:
820 kfree_skb(nskb);
821 goto out;
822}
823
824int llc_conn_ac_set_s_flag_0(struct sock *sk, struct sk_buff *skb)
825{
826 llc_sk(sk)->s_flag = 0;
827 return 0;
828}
829
830int llc_conn_ac_set_s_flag_1(struct sock *sk, struct sk_buff *skb)
831{
832 llc_sk(sk)->s_flag = 1;
833 return 0;
834}
835
836int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
837{
838 struct llc_sock *llc = llc_sk(sk);
839
840 llc_conn_set_p_flag(sk, 1);
841 mod_timer(&llc->pf_cycle_timer.timer,
Arnaldo Carvalho de Melo590232a2005-09-22 04:30:44 -0300842 jiffies + llc->pf_cycle_timer.expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 return 0;
844}
845
846/**
847 * llc_conn_ac_send_ack_if_needed - check if ack is needed
848 * @sk: current connection structure
849 * @skb: current event
850 *
851 * Checks number of received PDUs which have not been acknowledged, yet,
852 * If number of them reaches to "npta"(Number of PDUs To Acknowledge) then
853 * sends an RR response as acknowledgement for them. Returns 0 for
854 * success, 1 otherwise.
855 */
856int llc_conn_ac_send_ack_if_needed(struct sock *sk, struct sk_buff *skb)
857{
858 u8 pf_bit;
859 struct llc_sock *llc = llc_sk(sk);
860
861 llc_pdu_decode_pf_bit(skb, &pf_bit);
862 llc->ack_pf |= pf_bit & 1;
863 if (!llc->ack_must_be_send) {
864 llc->first_pdu_Ns = llc->vR;
865 llc->ack_must_be_send = 1;
866 llc->ack_pf = pf_bit & 1;
867 }
Jochen Friedrich59c61962005-11-14 21:57:15 -0800868 if (((llc->vR - llc->first_pdu_Ns + 1 + LLC_2_SEQ_NBR_MODULO)
869 % LLC_2_SEQ_NBR_MODULO) >= llc->npta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, skb);
871 llc->ack_must_be_send = 0;
872 llc->ack_pf = 0;
873 llc_conn_ac_inc_npta_value(sk, skb);
874 }
875 return 0;
876}
877
878/**
879 * llc_conn_ac_rst_sendack_flag - resets ack_must_be_send flag
880 * @sk: current connection structure
881 * @skb: current event
882 *
883 * This action resets ack_must_be_send flag of given connection, this flag
884 * indicates if there is any PDU which has not been acknowledged yet.
885 * Returns 0 for success, 1 otherwise.
886 */
887int llc_conn_ac_rst_sendack_flag(struct sock *sk, struct sk_buff *skb)
888{
889 llc_sk(sk)->ack_must_be_send = llc_sk(sk)->ack_pf = 0;
890 return 0;
891}
892
893/**
894 * llc_conn_ac_send_i_rsp_f_set_ackpf - acknowledge received PDUs
895 * @sk: current connection structure
896 * @skb: current event
897 *
898 * Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to
899 * all received PDUs which have not been acknowledged, yet. ack_pf flag is
900 * set to one if one PDU with p-bit set to one is received. Returns 0 for
901 * success, 1 otherwise.
902 */
903static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
904 struct sk_buff *skb)
905{
906 int rc;
907 struct llc_sock *llc = llc_sk(sk);
908 struct llc_sap *sap = llc->sap;
909
910 llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
911 llc->daddr.lsap, LLC_PDU_RSP);
912 llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR);
913 rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300914 if (likely(!rc)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 llc_conn_send_pdu(sk, skb);
916 llc_conn_ac_inc_vs_by_1(sk, skb);
917 }
918 return rc;
919}
920
921/**
922 * llc_conn_ac_send_i_as_ack - sends an I-format PDU to acknowledge rx PDUs
923 * @sk: current connection structure.
924 * @skb: current event.
925 *
926 * This action sends an I-format PDU as acknowledge to received PDUs which
927 * have not been acknowledged, yet, if there is any. By using of this
928 * action number of acknowledgements decreases, this technic is called
929 * piggy backing. Returns 0 for success, 1 otherwise.
930 */
931int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
932{
933 struct llc_sock *llc = llc_sk(sk);
934
935 if (llc->ack_must_be_send) {
936 llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
937 llc->ack_must_be_send = 0 ;
938 llc->ack_pf = 0;
939 } else
940 llc_conn_ac_send_i_cmd_p_set_0(sk, skb);
941 return 0;
942}
943
944/**
945 * llc_conn_ac_send_rr_rsp_f_set_ackpf - ack all rx PDUs not yet acked
946 * @sk: current connection structure.
947 * @skb: current event.
948 *
949 * This action sends an RR response with f-bit set to ack_pf flag as
950 * acknowledge to all received PDUs which have not been acknowledged, yet,
951 * if there is any. ack_pf flag indicates if a PDU has been received with
952 * p-bit set to one. Returns 0 for success, 1 otherwise.
953 */
954static int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk,
955 struct sk_buff *skb)
956{
957 int rc = -ENOBUFS;
Arnaldo Carvalho de Melo1d67e652005-09-22 03:27:56 -0300958 struct llc_sock *llc = llc_sk(sk);
Arnaldo Carvalho de Melod3894242005-09-22 07:57:21 -0300959 struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 if (nskb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 struct llc_sap *sap = llc->sap;
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
965 llc->daddr.lsap, LLC_PDU_RSP);
966 llc_pdu_init_as_rr_rsp(nskb, llc->ack_pf, llc->vR);
967 rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
Arnaldo Carvalho de Melo249ff1c2005-09-22 04:32:10 -0300968 if (unlikely(rc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 goto free;
970 llc_conn_send_pdu(sk, nskb);
971 }
972out:
973 return rc;
974free:
975 kfree_skb(nskb);
976 goto out;
977}
978
979/**
980 * llc_conn_ac_inc_npta_value - tries to make value of npta greater
981 * @sk: current connection structure.
982 * @skb: current event.
983 *
984 * After "inc_cntr" times calling of this action, "npta" increase by one.
985 * this action tries to make vale of "npta" greater as possible; number of
986 * acknowledgements decreases by increasing of "npta". Returns 0 for
987 * success, 1 otherwise.
988 */
989static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb)
990{
991 struct llc_sock *llc = llc_sk(sk);
992
993 if (!llc->inc_cntr) {
994 llc->dec_step = 0;
995 llc->dec_cntr = llc->inc_cntr = 2;
996 ++llc->npta;
David S. Miller38199822005-11-17 15:17:42 -0800997 if (llc->npta > (u8) ~LLC_2_SEQ_NBR_MODULO)
998 llc->npta = (u8) ~LLC_2_SEQ_NBR_MODULO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 } else
1000 --llc->inc_cntr;
1001 return 0;
1002}
1003
1004/**
1005 * llc_conn_ac_adjust_npta_by_rr - decreases "npta" by one
1006 * @sk: current connection structure.
1007 * @skb: current event.
1008 *
1009 * After receiving "dec_cntr" times RR command, this action decreases
1010 * "npta" by one. Returns 0 for success, 1 otherwise.
1011 */
1012int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct sk_buff *skb)
1013{
1014 struct llc_sock *llc = llc_sk(sk);
1015
1016 if (!llc->connect_step && !llc->remote_busy_flag) {
1017 if (!llc->dec_step) {
1018 if (!llc->dec_cntr) {
1019 llc->inc_cntr = llc->dec_cntr = 2;
1020 if (llc->npta > 0)
1021 llc->npta = llc->npta - 1;
1022 } else
1023 llc->dec_cntr -=1;
1024 }
1025 } else
1026 llc->connect_step = 0 ;
1027 return 0;
1028}
1029
1030/**
1031 * llc_conn_ac_adjust_npta_by_rnr - decreases "npta" by one
1032 * @sk: current connection structure.
1033 * @skb: current event.
1034 *
1035 * After receiving "dec_cntr" times RNR command, this action decreases
1036 * "npta" by one. Returns 0 for success, 1 otherwise.
1037 */
1038int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk, struct sk_buff *skb)
1039{
1040 struct llc_sock *llc = llc_sk(sk);
1041
1042 if (llc->remote_busy_flag)
1043 if (!llc->dec_step) {
1044 if (!llc->dec_cntr) {
1045 llc->inc_cntr = llc->dec_cntr = 2;
1046 if (llc->npta > 0)
1047 --llc->npta;
1048 } else
1049 --llc->dec_cntr;
1050 }
1051 return 0;
1052}
1053
1054/**
1055 * llc_conn_ac_dec_tx_win_size - decreases tx window size
1056 * @sk: current connection structure.
1057 * @skb: current event.
1058 *
1059 * After receiving of a REJ command or response, transmit window size is
1060 * decreased by number of PDUs which are outstanding yet. Returns 0 for
1061 * success, 1 otherwise.
1062 */
1063int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct sk_buff *skb)
1064{
1065 struct llc_sock *llc = llc_sk(sk);
1066 u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q);
1067
Jochen Friedrich59c61962005-11-14 21:57:15 -08001068 if (llc->k - unacked_pdu < 1)
1069 llc->k = 1;
1070 else
1071 llc->k -= unacked_pdu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return 0;
1073}
1074
1075/**
1076 * llc_conn_ac_inc_tx_win_size - tx window size is inc by 1
1077 * @sk: current connection structure.
1078 * @skb: current event.
1079 *
1080 * After receiving an RR response with f-bit set to one, transmit window
1081 * size is increased by one. Returns 0 for success, 1 otherwise.
1082 */
1083int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
1084{
1085 struct llc_sock *llc = llc_sk(sk);
1086
1087 llc->k += 1;
David S. Miller38199822005-11-17 15:17:42 -08001088 if (llc->k > (u8) ~LLC_2_SEQ_NBR_MODULO)
1089 llc->k = (u8) ~LLC_2_SEQ_NBR_MODULO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 return 0;
1091}
1092
1093int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
1094{
1095 struct llc_sock *llc = llc_sk(sk);
1096
1097 del_timer(&llc->pf_cycle_timer.timer);
1098 del_timer(&llc->ack_timer.timer);
1099 del_timer(&llc->rej_sent_timer.timer);
1100 del_timer(&llc->busy_state_timer.timer);
1101 llc->ack_must_be_send = 0;
1102 llc->ack_pf = 0;
1103 return 0;
1104}
1105
1106int llc_conn_ac_stop_other_timers(struct sock *sk, struct sk_buff *skb)
1107{
1108 struct llc_sock *llc = llc_sk(sk);
1109
1110 del_timer(&llc->rej_sent_timer.timer);
1111 del_timer(&llc->pf_cycle_timer.timer);
1112 del_timer(&llc->busy_state_timer.timer);
1113 llc->ack_must_be_send = 0;
1114 llc->ack_pf = 0;
1115 return 0;
1116}
1117
1118int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb)
1119{
1120 struct llc_sock *llc = llc_sk(sk);
1121
Arnaldo Carvalho de Melo590232a2005-09-22 04:30:44 -03001122 mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 return 0;
1124}
1125
1126int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb)
1127{
1128 struct llc_sock *llc = llc_sk(sk);
1129
1130 mod_timer(&llc->rej_sent_timer.timer,
Arnaldo Carvalho de Melo590232a2005-09-22 04:30:44 -03001131 jiffies + llc->rej_sent_timer.expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 return 0;
1133}
1134
1135int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
1136 struct sk_buff *skb)
1137{
1138 struct llc_sock *llc = llc_sk(sk);
1139
1140 if (!timer_pending(&llc->ack_timer.timer))
1141 mod_timer(&llc->ack_timer.timer,
Arnaldo Carvalho de Melo590232a2005-09-22 04:30:44 -03001142 jiffies + llc->ack_timer.expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return 0;
1144}
1145
1146int llc_conn_ac_stop_ack_timer(struct sock *sk, struct sk_buff *skb)
1147{
1148 del_timer(&llc_sk(sk)->ack_timer.timer);
1149 return 0;
1150}
1151
1152int llc_conn_ac_stop_p_timer(struct sock *sk, struct sk_buff *skb)
1153{
1154 struct llc_sock *llc = llc_sk(sk);
1155
1156 del_timer(&llc->pf_cycle_timer.timer);
1157 llc_conn_set_p_flag(sk, 0);
1158 return 0;
1159}
1160
1161int llc_conn_ac_stop_rej_timer(struct sock *sk, struct sk_buff *skb)
1162{
1163 del_timer(&llc_sk(sk)->rej_sent_timer.timer);
1164 return 0;
1165}
1166
1167int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
1168{
1169 int acked;
1170 u16 unacked = 0;
1171 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1172 struct llc_sock *llc = llc_sk(sk);
1173
1174 llc->last_nr = PDU_SUPV_GET_Nr(pdu);
1175 acked = llc_conn_remove_acked_pdus(sk, llc->last_nr, &unacked);
1176 /* On loopback we don't queue I frames in unack_pdu_q queue. */
1177 if (acked > 0 || (llc->dev->flags & IFF_LOOPBACK)) {
1178 llc->retry_count = 0;
1179 del_timer(&llc->ack_timer.timer);
1180 if (llc->failed_data_req) {
1181 /* already, we did not accept data from upper layer
1182 * (tx_window full or unacceptable state). Now, we
1183 * can send data and must inform to upper layer.
1184 */
1185 llc->failed_data_req = 0;
1186 llc_conn_ac_data_confirm(sk, skb);
1187 }
1188 if (unacked)
1189 mod_timer(&llc->ack_timer.timer,
Arnaldo Carvalho de Melo590232a2005-09-22 04:30:44 -03001190 jiffies + llc->ack_timer.expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 } else if (llc->failed_data_req) {
1192 u8 f_bit;
1193
1194 llc_pdu_decode_pf_bit(skb, &f_bit);
1195 if (f_bit == 1) {
1196 llc->failed_data_req = 0;
1197 llc_conn_ac_data_confirm(sk, skb);
1198 }
1199 }
1200 return 0;
1201}
1202
1203int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb)
1204{
1205 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1206
1207 if (LLC_PDU_IS_RSP(pdu)) {
1208 u8 f_bit;
1209
1210 llc_pdu_decode_pf_bit(skb, &f_bit);
1211 if (f_bit) {
1212 llc_conn_set_p_flag(sk, 0);
1213 llc_conn_ac_stop_p_timer(sk, skb);
1214 }
1215 }
1216 return 0;
1217}
1218
1219int llc_conn_ac_set_data_flag_2(struct sock *sk, struct sk_buff *skb)
1220{
1221 llc_sk(sk)->data_flag = 2;
1222 return 0;
1223}
1224
1225int llc_conn_ac_set_data_flag_0(struct sock *sk, struct sk_buff *skb)
1226{
1227 llc_sk(sk)->data_flag = 0;
1228 return 0;
1229}
1230
1231int llc_conn_ac_set_data_flag_1(struct sock *sk, struct sk_buff *skb)
1232{
1233 llc_sk(sk)->data_flag = 1;
1234 return 0;
1235}
1236
1237int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock *sk,
1238 struct sk_buff *skb)
1239{
1240 if (!llc_sk(sk)->data_flag)
1241 llc_sk(sk)->data_flag = 1;
1242 return 0;
1243}
1244
1245int llc_conn_ac_set_p_flag_0(struct sock *sk, struct sk_buff *skb)
1246{
1247 llc_conn_set_p_flag(sk, 0);
1248 return 0;
1249}
1250
1251static int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb)
1252{
1253 llc_conn_set_p_flag(sk, 1);
1254 return 0;
1255}
1256
1257int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct sk_buff *skb)
1258{
1259 llc_sk(sk)->remote_busy_flag = 0;
1260 return 0;
1261}
1262
1263int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct sk_buff *skb)
1264{
1265 llc_sk(sk)->cause_flag = 0;
1266 return 0;
1267}
1268
1269int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct sk_buff *skb)
1270{
1271 llc_sk(sk)->cause_flag = 1;
1272 return 0;
1273}
1274
1275int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct sk_buff *skb)
1276{
1277 llc_sk(sk)->retry_count = 0;
1278 return 0;
1279}
1280
1281int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk, struct sk_buff *skb)
1282{
1283 llc_sk(sk)->retry_count++;
1284 return 0;
1285}
1286
1287int llc_conn_ac_set_vr_0(struct sock *sk, struct sk_buff *skb)
1288{
1289 llc_sk(sk)->vR = 0;
1290 return 0;
1291}
1292
1293int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct sk_buff *skb)
1294{
1295 llc_sk(sk)->vR = PDU_GET_NEXT_Vr(llc_sk(sk)->vR);
1296 return 0;
1297}
1298
1299int llc_conn_ac_set_vs_0(struct sock *sk, struct sk_buff *skb)
1300{
1301 llc_sk(sk)->vS = 0;
1302 return 0;
1303}
1304
1305int llc_conn_ac_set_vs_nr(struct sock *sk, struct sk_buff *skb)
1306{
1307 llc_sk(sk)->vS = llc_sk(sk)->last_nr;
1308 return 0;
1309}
1310
Arnaldo Carvalho de Melo2928c192005-09-22 05:14:33 -03001311static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
Jochen Friedrich59c61962005-11-14 21:57:15 -08001313 llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 return 0;
1315}
1316
Arnaldo Carvalho de Meloe0dd5512005-09-22 03:50:15 -03001317static void llc_conn_tmr_common_cb(unsigned long timeout_data, u8 type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 struct sock *sk = (struct sock *)timeout_data;
1320 struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
1321
1322 bh_lock_sock(sk);
1323 if (skb) {
1324 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
1325
Arnaldo Carvalho de Melo04e42232005-09-22 04:40:59 -03001326 skb_set_owner_r(skb, sk);
Arnaldo Carvalho de Meloe0dd5512005-09-22 03:50:15 -03001327 ev->type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 llc_process_tmr_ev(sk, skb);
1329 }
1330 bh_unlock_sock(sk);
1331}
1332
Arnaldo Carvalho de Meloe0dd5512005-09-22 03:50:15 -03001333void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
1334{
1335 llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_P_TMR);
1336}
1337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338void llc_conn_busy_tmr_cb(unsigned long timeout_data)
1339{
Arnaldo Carvalho de Meloe0dd5512005-09-22 03:50:15 -03001340 llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_BUSY_TMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341}
1342
1343void llc_conn_ack_tmr_cb(unsigned long timeout_data)
1344{
Arnaldo Carvalho de Meloe0dd5512005-09-22 03:50:15 -03001345 llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_ACK_TMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346}
1347
1348void llc_conn_rej_tmr_cb(unsigned long timeout_data)
1349{
Arnaldo Carvalho de Meloe0dd5512005-09-22 03:50:15 -03001350 llc_conn_tmr_common_cb(timeout_data, LLC_CONN_EV_TYPE_REJ_TMR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351}
1352
1353int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
1354{
1355 llc_sk(sk)->X = llc_sk(sk)->vS;
1356 llc_conn_ac_set_vs_nr(sk, skb);
1357 return 0;
1358}
1359
1360int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb)
1361{
1362 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1363 u8 nr = PDU_SUPV_GET_Nr(pdu);
1364
1365 if (llc_circular_between(llc_sk(sk)->vS, nr, llc_sk(sk)->X))
1366 llc_conn_ac_set_vs_nr(sk, skb);
1367 return 0;
1368}
1369
1370/*
1371 * Non-standard actions; these not contained in IEEE specification; for
1372 * our own usage
1373 */
1374/**
1375 * llc_conn_disc - removes connection from SAP list and frees it
1376 * @sk: closed connection
1377 * @skb: occurred event
1378 */
1379int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
1380{
1381 /* FIXME: this thing seems to want to die */
1382 return 0;
1383}
1384
1385/**
1386 * llc_conn_reset - resets connection
1387 * @sk : reseting connection.
1388 * @skb: occurred event.
1389 *
1390 * Stop all timers, empty all queues and reset all flags.
1391 */
1392int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
1393{
1394 llc_sk_reset(sk);
1395 return 0;
1396}
1397
1398/**
1399 * llc_circular_between - designates that b is between a and c or not
1400 * @a: lower bound
1401 * @b: element to see if is between a and b
1402 * @c: upper bound
1403 *
1404 * This function designates that b is between a and c or not (for example,
1405 * 0 is between 127 and 1). Returns 1 if b is between a and c, 0
1406 * otherwise.
1407 */
1408u8 llc_circular_between(u8 a, u8 b, u8 c)
1409{
1410 b = b - a;
1411 c = c - a;
1412 return b <= c;
1413}
1414
1415/**
1416 * llc_process_tmr_ev - timer backend
1417 * @sk: active connection
1418 * @skb: occurred event
1419 *
1420 * This function is called from timer callback functions. When connection
1421 * is busy (during sending a data frame) timer expiration event must be
1422 * queued. Otherwise this event can be sent to connection state machine.
1423 * Queued events will process by llc_backlog_rcv function after sending
1424 * data frame.
1425 */
1426static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
1427{
1428 if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
1429 printk(KERN_WARNING "%s: timer called on closed connection\n",
1430 __FUNCTION__);
1431 kfree_skb(skb);
1432 } else {
1433 if (!sock_owned_by_user(sk))
1434 llc_conn_state_process(sk, skb);
1435 else {
1436 llc_set_backlog_type(skb, LLC_EVENT);
1437 sk_add_backlog(sk, skb);
1438 }
1439 }
1440}