xref: /linux/net/llc/llc_c_ac.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * llc_c_ac.c - actions performed during connection state transition.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Description:
51da177e4SLinus Torvalds  *   Functions in this module are implementation of connection component actions
61da177e4SLinus Torvalds  *   Details of actions can be found in IEEE-802.2 standard document.
71da177e4SLinus Torvalds  *   All functions have one connection and one event as input argument. All of
81da177e4SLinus Torvalds  *   them return 0 On success and 1 otherwise.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Copyright (c) 1997 by Procom Technology, Inc.
111da177e4SLinus Torvalds  * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * This program can be redistributed or modified under the terms of the
141da177e4SLinus Torvalds  * GNU General Public License as published by the Free Software Foundation.
151da177e4SLinus Torvalds  * This program is distributed without any warranty or implied warranty
161da177e4SLinus Torvalds  * of merchantability or fitness for a particular purpose.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * See the GNU General Public License for more details.
191da177e4SLinus Torvalds  */
201da177e4SLinus Torvalds #include <linux/netdevice.h>
215a0e3ad6STejun Heo #include <linux/slab.h>
221da177e4SLinus Torvalds #include <net/llc_conn.h>
231da177e4SLinus Torvalds #include <net/llc_sap.h>
241da177e4SLinus Torvalds #include <net/sock.h>
251da177e4SLinus Torvalds #include <net/llc_c_ev.h>
261da177e4SLinus Torvalds #include <net/llc_c_ac.h>
271da177e4SLinus Torvalds #include <net/llc_c_st.h>
281da177e4SLinus Torvalds #include <net/llc_pdu.h>
291da177e4SLinus Torvalds #include <net/llc.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
331da177e4SLinus Torvalds static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
341da177e4SLinus Torvalds static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev);
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb);
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds static int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk,
391da177e4SLinus Torvalds 					       struct sk_buff *skb);
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds static int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb);
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds #define INCORRECT 0
441da177e4SLinus Torvalds 
llc_conn_ac_clear_remote_busy(struct sock * sk,struct sk_buff * skb)451da177e4SLinus Torvalds int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 	if (llc->remote_busy_flag) {
501da177e4SLinus Torvalds 		u8 nr;
511da177e4SLinus Torvalds 		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 		llc->remote_busy_flag = 0;
541da177e4SLinus Torvalds 		del_timer(&llc->busy_state_timer.timer);
551da177e4SLinus Torvalds 		nr = LLC_I_GET_NR(pdu);
561da177e4SLinus Torvalds 		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
571da177e4SLinus Torvalds 	}
581da177e4SLinus Torvalds 	return 0;
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
llc_conn_ac_conn_ind(struct sock * sk,struct sk_buff * skb)611da177e4SLinus Torvalds int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	ev->ind_prim = LLC_CONN_PRIM;
66d389424eSArnaldo Carvalho de Melo 	return 0;
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
llc_conn_ac_conn_confirm(struct sock * sk,struct sk_buff * skb)691da177e4SLinus Torvalds int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	ev->cfm_prim = LLC_CONN_PRIM;
741da177e4SLinus Torvalds 	return 0;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
llc_conn_ac_data_confirm(struct sock * sk,struct sk_buff * skb)771da177e4SLinus Torvalds static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	ev->cfm_prim = LLC_DATA_PRIM;
821da177e4SLinus Torvalds 	return 0;
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds 
llc_conn_ac_data_ind(struct sock * sk,struct sk_buff * skb)851da177e4SLinus Torvalds int llc_conn_ac_data_ind(struct sock *sk, struct sk_buff *skb)
861da177e4SLinus Torvalds {
871da177e4SLinus Torvalds 	llc_conn_rtn_pdu(sk, skb);
881da177e4SLinus Torvalds 	return 0;
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds 
llc_conn_ac_disc_ind(struct sock * sk,struct sk_buff * skb)911da177e4SLinus Torvalds int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
921da177e4SLinus Torvalds {
931da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
941da177e4SLinus Torvalds 	u8 reason = 0;
951da177e4SLinus Torvalds 	int rc = 0;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	if (ev->type == LLC_CONN_EV_TYPE_PDU) {
981da177e4SLinus Torvalds 		struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 		if (LLC_PDU_IS_RSP(pdu) &&
1011da177e4SLinus Torvalds 		    LLC_PDU_TYPE_IS_U(pdu) &&
1021da177e4SLinus Torvalds 		    LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM)
1031da177e4SLinus Torvalds 			reason = LLC_DISC_REASON_RX_DM_RSP_PDU;
1041da177e4SLinus Torvalds 		else if (LLC_PDU_IS_CMD(pdu) &&
1051da177e4SLinus Torvalds 			   LLC_PDU_TYPE_IS_U(pdu) &&
1061da177e4SLinus Torvalds 			   LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC)
1071da177e4SLinus Torvalds 			reason = LLC_DISC_REASON_RX_DISC_CMD_PDU;
1081da177e4SLinus Torvalds 	} else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR)
1091da177e4SLinus Torvalds 		reason = LLC_DISC_REASON_ACK_TMR_EXP;
110bdcc66ccSArnaldo Carvalho de Melo 	else
1111da177e4SLinus Torvalds 		rc = -EINVAL;
1121da177e4SLinus Torvalds 	if (!rc) {
1131da177e4SLinus Torvalds 		ev->reason   = reason;
1141da177e4SLinus Torvalds 		ev->ind_prim = LLC_DISC_PRIM;
1151da177e4SLinus Torvalds 	}
1161da177e4SLinus Torvalds 	return rc;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds 
llc_conn_ac_disc_confirm(struct sock * sk,struct sk_buff * skb)1191da177e4SLinus Torvalds int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
1201da177e4SLinus Torvalds {
1211da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	ev->reason   = ev->status;
1241da177e4SLinus Torvalds 	ev->cfm_prim = LLC_DISC_PRIM;
1251da177e4SLinus Torvalds 	return 0;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds 
llc_conn_ac_rst_ind(struct sock * sk,struct sk_buff * skb)1281da177e4SLinus Torvalds int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
1291da177e4SLinus Torvalds {
1301da177e4SLinus Torvalds 	u8 reason = 0;
1311da177e4SLinus Torvalds 	int rc = 1;
1321da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
1331da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
1341da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 	switch (ev->type) {
1371da177e4SLinus Torvalds 	case LLC_CONN_EV_TYPE_PDU:
1381da177e4SLinus Torvalds 		if (LLC_PDU_IS_RSP(pdu) &&
1391da177e4SLinus Torvalds 		    LLC_PDU_TYPE_IS_U(pdu) &&
1401da177e4SLinus Torvalds 		    LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR) {
1411da177e4SLinus Torvalds 			reason = LLC_RESET_REASON_LOCAL;
1421da177e4SLinus Torvalds 			rc = 0;
1431da177e4SLinus Torvalds 		} else if (LLC_PDU_IS_CMD(pdu) &&
1441da177e4SLinus Torvalds 			   LLC_PDU_TYPE_IS_U(pdu) &&
1451da177e4SLinus Torvalds 			   LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME) {
1461da177e4SLinus Torvalds 			reason = LLC_RESET_REASON_REMOTE;
1471da177e4SLinus Torvalds 			rc = 0;
1481da177e4SLinus Torvalds 		}
1491da177e4SLinus Torvalds 		break;
1501da177e4SLinus Torvalds 	case LLC_CONN_EV_TYPE_ACK_TMR:
1511da177e4SLinus Torvalds 	case LLC_CONN_EV_TYPE_P_TMR:
1521da177e4SLinus Torvalds 	case LLC_CONN_EV_TYPE_REJ_TMR:
1531da177e4SLinus Torvalds 	case LLC_CONN_EV_TYPE_BUSY_TMR:
1541da177e4SLinus Torvalds 		if (llc->retry_count > llc->n2) {
1551da177e4SLinus Torvalds 			reason = LLC_RESET_REASON_LOCAL;
1561da177e4SLinus Torvalds 			rc = 0;
157bdcc66ccSArnaldo Carvalho de Melo 		}
1581da177e4SLinus Torvalds 		break;
1591da177e4SLinus Torvalds 	}
1601da177e4SLinus Torvalds 	if (!rc) {
1611da177e4SLinus Torvalds 		ev->reason   = reason;
1621da177e4SLinus Torvalds 		ev->ind_prim = LLC_RESET_PRIM;
1631da177e4SLinus Torvalds 	}
1641da177e4SLinus Torvalds 	return rc;
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds 
llc_conn_ac_rst_confirm(struct sock * sk,struct sk_buff * skb)1671da177e4SLinus Torvalds int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb)
1681da177e4SLinus Torvalds {
1691da177e4SLinus Torvalds 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	ev->reason   = 0;
1721da177e4SLinus Torvalds 	ev->cfm_prim = LLC_RESET_PRIM;
1731da177e4SLinus Torvalds 	return 0;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock * sk,struct sk_buff * skb)1761da177e4SLinus Torvalds int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk,
1771da177e4SLinus Torvalds 					    struct sk_buff *skb)
1781da177e4SLinus Torvalds {
1791da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	if (LLC_PDU_IS_RSP(pdu) &&
1821da177e4SLinus Torvalds 	    LLC_PDU_TYPE_IS_I(pdu) &&
1831da177e4SLinus Torvalds 	    LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf)
1841da177e4SLinus Torvalds 		llc_conn_ac_clear_remote_busy(sk, skb);
1851da177e4SLinus Torvalds 	return 0;
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds 
llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock * sk,struct sk_buff * skb)1881da177e4SLinus Torvalds int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
1891da177e4SLinus Torvalds 					       struct sk_buff *skb)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	if (llc->data_flag == 2)
1941da177e4SLinus Torvalds 		del_timer(&llc->rej_sent_timer.timer);
1951da177e4SLinus Torvalds 	return 0;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds 
llc_conn_ac_send_disc_cmd_p_set_x(struct sock * sk,struct sk_buff * skb)1981da177e4SLinus Torvalds int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
1991da177e4SLinus Torvalds {
2001da177e4SLinus Torvalds 	int rc = -ENOBUFS;
2011d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
202f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U, 0);
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	if (nskb) {
2051da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
2081da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_CMD);
2091da177e4SLinus Torvalds 		llc_pdu_init_as_disc_cmd(nskb, 1);
2101da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
211249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
2121da177e4SLinus Torvalds 			goto free;
2131da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
2141da177e4SLinus Torvalds 		llc_conn_ac_set_p_flag_1(sk, skb);
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds out:
2171da177e4SLinus Torvalds 	return rc;
2181da177e4SLinus Torvalds free:
2191da177e4SLinus Torvalds 	kfree_skb(nskb);
2201da177e4SLinus Torvalds 	goto out;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
llc_conn_ac_send_dm_rsp_f_set_p(struct sock * sk,struct sk_buff * skb)2231da177e4SLinus Torvalds int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
2241da177e4SLinus Torvalds {
2251da177e4SLinus Torvalds 	int rc = -ENOBUFS;
2261d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
227f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U, 0);
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	if (nskb) {
2301da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
2311da177e4SLinus Torvalds 		u8 f_bit;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 		llc_pdu_decode_pf_bit(skb, &f_bit);
2341da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
2351da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
2361da177e4SLinus Torvalds 		llc_pdu_init_as_dm_rsp(nskb, f_bit);
2371da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
238249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
2391da177e4SLinus Torvalds 			goto free;
2401da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
2411da177e4SLinus Torvalds 	}
2421da177e4SLinus Torvalds out:
2431da177e4SLinus Torvalds 	return rc;
2441da177e4SLinus Torvalds free:
2451da177e4SLinus Torvalds 	kfree_skb(nskb);
2461da177e4SLinus Torvalds 	goto out;
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
llc_conn_ac_send_dm_rsp_f_set_1(struct sock * sk,struct sk_buff * skb)2491da177e4SLinus Torvalds int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds 	int rc = -ENOBUFS;
2521d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
253f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U, 0);
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	if (nskb) {
2561da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
2591da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
260838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_dm_rsp(nskb, 1);
2611da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
262249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
2631da177e4SLinus Torvalds 			goto free;
2641da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
2651da177e4SLinus Torvalds 	}
2661da177e4SLinus Torvalds out:
2671da177e4SLinus Torvalds 	return rc;
2681da177e4SLinus Torvalds free:
2691da177e4SLinus Torvalds 	kfree_skb(nskb);
2701da177e4SLinus Torvalds 	goto out;
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds 
llc_conn_ac_send_frmr_rsp_f_set_x(struct sock * sk,struct sk_buff * skb)2731da177e4SLinus Torvalds int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb)
2741da177e4SLinus Torvalds {
2751da177e4SLinus Torvalds 	u8 f_bit;
2761da177e4SLinus Torvalds 	int rc = -ENOBUFS;
2771da177e4SLinus Torvalds 	struct sk_buff *nskb;
2781da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
2791da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	llc->rx_pdu_hdr = *((u32 *)pdu);
2821da177e4SLinus Torvalds 	if (LLC_PDU_IS_CMD(pdu))
2831da177e4SLinus Torvalds 		llc_pdu_decode_pf_bit(skb, &f_bit);
2841da177e4SLinus Torvalds 	else
2851da177e4SLinus Torvalds 		f_bit = 0;
286f83f1768SJoonwoo Park 	nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U,
287f83f1768SJoonwoo Park 			       sizeof(struct llc_frmr_info));
2881da177e4SLinus Torvalds 	if (nskb) {
2891da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
2921da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
2931da177e4SLinus Torvalds 		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
2941da177e4SLinus Torvalds 					 llc->vR, INCORRECT);
2951da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
296249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
2971da177e4SLinus Torvalds 			goto free;
2981da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
2991da177e4SLinus Torvalds 	}
3001da177e4SLinus Torvalds out:
3011da177e4SLinus Torvalds 	return rc;
3021da177e4SLinus Torvalds free:
3031da177e4SLinus Torvalds 	kfree_skb(nskb);
3041da177e4SLinus Torvalds 	goto out;
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock * sk,struct sk_buff * skb)3071da177e4SLinus Torvalds int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb)
3081da177e4SLinus Torvalds {
3091da177e4SLinus Torvalds 	int rc = -ENOBUFS;
3101d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
311f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U,
312f83f1768SJoonwoo Park 					       sizeof(struct llc_frmr_info));
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	if (nskb) {
3151da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
3161da177e4SLinus Torvalds 		struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)&llc->rx_pdu_hdr;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
3191da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
320838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_frmr_rsp(nskb, pdu, 0, llc->vS,
3211da177e4SLinus Torvalds 					 llc->vR, INCORRECT);
3221da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
323249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
3241da177e4SLinus Torvalds 			goto free;
3251da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
3261da177e4SLinus Torvalds 	}
3271da177e4SLinus Torvalds out:
3281da177e4SLinus Torvalds 	return rc;
3291da177e4SLinus Torvalds free:
3301da177e4SLinus Torvalds 	kfree_skb(nskb);
3311da177e4SLinus Torvalds 	goto out;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds 
llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock * sk,struct sk_buff * skb)3341da177e4SLinus Torvalds int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
3351da177e4SLinus Torvalds {
3361da177e4SLinus Torvalds 	u8 f_bit;
3371da177e4SLinus Torvalds 	int rc = -ENOBUFS;
3381da177e4SLinus Torvalds 	struct sk_buff *nskb;
3391d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	llc_pdu_decode_pf_bit(skb, &f_bit);
342f83f1768SJoonwoo Park 	nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U,
343f83f1768SJoonwoo Park 			       sizeof(struct llc_frmr_info));
3441da177e4SLinus Torvalds 	if (nskb) {
3451da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
3461da177e4SLinus Torvalds 		struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
3491da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
3501da177e4SLinus Torvalds 		llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
3511da177e4SLinus Torvalds 					 llc->vR, INCORRECT);
3521da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
353249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
3541da177e4SLinus Torvalds 			goto free;
3551da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
3561da177e4SLinus Torvalds 	}
3571da177e4SLinus Torvalds out:
3581da177e4SLinus Torvalds 	return rc;
3591da177e4SLinus Torvalds free:
3601da177e4SLinus Torvalds 	kfree_skb(nskb);
3611da177e4SLinus Torvalds 	goto out;
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds 
llc_conn_ac_send_i_cmd_p_set_1(struct sock * sk,struct sk_buff * skb)3641da177e4SLinus Torvalds int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
3651da177e4SLinus Torvalds {
3661da177e4SLinus Torvalds 	int rc;
3671da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
3681da177e4SLinus Torvalds 	struct llc_sap *sap = llc->sap;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
3711da177e4SLinus Torvalds 			    llc->daddr.lsap, LLC_PDU_CMD);
3721da177e4SLinus Torvalds 	llc_pdu_init_as_i_cmd(skb, 1, llc->vS, llc->vR);
3731da177e4SLinus Torvalds 	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
374249ff1c6SArnaldo Carvalho de Melo 	if (likely(!rc)) {
375b74555deSEric Biggers 		skb_get(skb);
3761da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, skb);
3771da177e4SLinus Torvalds 		llc_conn_ac_inc_vs_by_1(sk, skb);
3781da177e4SLinus Torvalds 	}
3791da177e4SLinus Torvalds 	return rc;
3801da177e4SLinus Torvalds }
3811da177e4SLinus Torvalds 
llc_conn_ac_send_i_cmd_p_set_0(struct sock * sk,struct sk_buff * skb)3821da177e4SLinus Torvalds static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
3831da177e4SLinus Torvalds {
3841da177e4SLinus Torvalds 	int rc;
3851da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
3861da177e4SLinus Torvalds 	struct llc_sap *sap = llc->sap;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
3891da177e4SLinus Torvalds 			    llc->daddr.lsap, LLC_PDU_CMD);
3901da177e4SLinus Torvalds 	llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
3911da177e4SLinus Torvalds 	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
392249ff1c6SArnaldo Carvalho de Melo 	if (likely(!rc)) {
393b74555deSEric Biggers 		skb_get(skb);
394b74555deSEric Biggers 		llc_conn_send_pdu(sk, skb);
3951da177e4SLinus Torvalds 		llc_conn_ac_inc_vs_by_1(sk, skb);
3961da177e4SLinus Torvalds 	}
3971da177e4SLinus Torvalds 	return rc;
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
llc_conn_ac_send_i_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)4001da177e4SLinus Torvalds int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
4011da177e4SLinus Torvalds {
4021da177e4SLinus Torvalds 	int rc;
4031da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
4041da177e4SLinus Torvalds 	struct llc_sap *sap = llc->sap;
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
4071da177e4SLinus Torvalds 			    llc->daddr.lsap, LLC_PDU_CMD);
4081da177e4SLinus Torvalds 	llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
4091da177e4SLinus Torvalds 	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
410249ff1c6SArnaldo Carvalho de Melo 	if (likely(!rc)) {
411b74555deSEric Biggers 		skb_get(skb);
4121da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, skb);
4131da177e4SLinus Torvalds 		llc_conn_ac_inc_vs_by_1(sk, skb);
4141da177e4SLinus Torvalds 	}
4151da177e4SLinus Torvalds 	return 0;
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds 
llc_conn_ac_resend_i_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)4181da177e4SLinus Torvalds int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
4191da177e4SLinus Torvalds {
4201da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
4211da177e4SLinus Torvalds 	u8 nr = LLC_I_GET_NR(pdu);
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 	llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
4241da177e4SLinus Torvalds 	return 0;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock * sk,struct sk_buff * skb)4271da177e4SLinus Torvalds int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
4281da177e4SLinus Torvalds 						struct sk_buff *skb)
4291da177e4SLinus Torvalds {
4301da177e4SLinus Torvalds 	u8 nr;
4311da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
4321da177e4SLinus Torvalds 	int rc = -ENOBUFS;
4331d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
434f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U, 0);
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 	if (nskb) {
4371da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
4401da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
4411da177e4SLinus Torvalds 		llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
4421da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
443249ff1c6SArnaldo Carvalho de Melo 		if (likely(!rc))
4441da177e4SLinus Torvalds 			llc_conn_send_pdu(sk, nskb);
4451da177e4SLinus Torvalds 		else
4461da177e4SLinus Torvalds 			kfree_skb(skb);
4471da177e4SLinus Torvalds 	}
4481da177e4SLinus Torvalds 	if (rc) {
4491da177e4SLinus Torvalds 		nr = LLC_I_GET_NR(pdu);
4501da177e4SLinus Torvalds 		rc = 0;
4511da177e4SLinus Torvalds 		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
4521da177e4SLinus Torvalds 	}
4531da177e4SLinus Torvalds 	return rc;
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds 
llc_conn_ac_resend_i_rsp_f_set_1(struct sock * sk,struct sk_buff * skb)4561da177e4SLinus Torvalds int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
4571da177e4SLinus Torvalds {
4581da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
4591da177e4SLinus Torvalds 	u8 nr = LLC_I_GET_NR(pdu);
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	llc_conn_resend_i_pdu_as_rsp(sk, nr, 1);
4621da177e4SLinus Torvalds 	return 0;
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds 
llc_conn_ac_send_rej_cmd_p_set_1(struct sock * sk,struct sk_buff * skb)4651da177e4SLinus Torvalds int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
4661da177e4SLinus Torvalds {
4671da177e4SLinus Torvalds 	int rc = -ENOBUFS;
4681d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
469f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	if (nskb) {
4721da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
4751da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_CMD);
4761da177e4SLinus Torvalds 		llc_pdu_init_as_rej_cmd(nskb, 1, llc->vR);
4771da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
478249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
4791da177e4SLinus Torvalds 			goto free;
4801da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
4811da177e4SLinus Torvalds 	}
4821da177e4SLinus Torvalds out:
4831da177e4SLinus Torvalds 	return rc;
4841da177e4SLinus Torvalds free:
4851da177e4SLinus Torvalds 	kfree_skb(nskb);
4861da177e4SLinus Torvalds 	goto out;
4871da177e4SLinus Torvalds }
4881da177e4SLinus Torvalds 
llc_conn_ac_send_rej_rsp_f_set_1(struct sock * sk,struct sk_buff * skb)4891da177e4SLinus Torvalds int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
4901da177e4SLinus Torvalds {
4911da177e4SLinus Torvalds 	int rc = -ENOBUFS;
4921d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
493f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	if (nskb) {
4961da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
4991da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
500838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_rej_rsp(nskb, 1, llc->vR);
5011da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
502249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
5031da177e4SLinus Torvalds 			goto free;
5041da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds out:
5071da177e4SLinus Torvalds 	return rc;
5081da177e4SLinus Torvalds free:
5091da177e4SLinus Torvalds 	kfree_skb(nskb);
5101da177e4SLinus Torvalds 	goto out;
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
llc_conn_ac_send_rej_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)5131da177e4SLinus Torvalds int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
5141da177e4SLinus Torvalds {
5151da177e4SLinus Torvalds 	int rc = -ENOBUFS;
5161d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
517f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	if (nskb) {
5201da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
5231da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
524838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_rej_rsp(nskb, 0, llc->vR);
5251da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
526249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
5271da177e4SLinus Torvalds 			goto free;
5281da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
5291da177e4SLinus Torvalds 	}
5301da177e4SLinus Torvalds out:
5311da177e4SLinus Torvalds 	return rc;
5321da177e4SLinus Torvalds free:
5331da177e4SLinus Torvalds 	kfree_skb(nskb);
5341da177e4SLinus Torvalds 	goto out;
5351da177e4SLinus Torvalds }
5361da177e4SLinus Torvalds 
llc_conn_ac_send_rnr_cmd_p_set_1(struct sock * sk,struct sk_buff * skb)5371da177e4SLinus Torvalds int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
5381da177e4SLinus Torvalds {
5391da177e4SLinus Torvalds 	int rc = -ENOBUFS;
5401d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
541f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 	if (nskb) {
5441da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
5471da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_CMD);
5481da177e4SLinus Torvalds 		llc_pdu_init_as_rnr_cmd(nskb, 1, llc->vR);
5491da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
550249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
5511da177e4SLinus Torvalds 			goto free;
5521da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
5531da177e4SLinus Torvalds 	}
5541da177e4SLinus Torvalds out:
5551da177e4SLinus Torvalds 	return rc;
5561da177e4SLinus Torvalds free:
5571da177e4SLinus Torvalds 	kfree_skb(nskb);
5581da177e4SLinus Torvalds 	goto out;
5591da177e4SLinus Torvalds }
5601da177e4SLinus Torvalds 
llc_conn_ac_send_rnr_rsp_f_set_1(struct sock * sk,struct sk_buff * skb)5611da177e4SLinus Torvalds int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
5621da177e4SLinus Torvalds {
5631da177e4SLinus Torvalds 	int rc = -ENOBUFS;
5641d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
565f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds 	if (nskb) {
5681da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
5711da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
572838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_rnr_rsp(nskb, 1, llc->vR);
5731da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
574249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
5751da177e4SLinus Torvalds 			goto free;
5761da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
5771da177e4SLinus Torvalds 	}
5781da177e4SLinus Torvalds out:
5791da177e4SLinus Torvalds 	return rc;
5801da177e4SLinus Torvalds free:
5811da177e4SLinus Torvalds 	kfree_skb(nskb);
5821da177e4SLinus Torvalds 	goto out;
5831da177e4SLinus Torvalds }
5841da177e4SLinus Torvalds 
llc_conn_ac_send_rnr_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)5851da177e4SLinus Torvalds int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
5861da177e4SLinus Torvalds {
5871da177e4SLinus Torvalds 	int rc = -ENOBUFS;
5881d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
589f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	if (nskb) {
5921da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
5951da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
596838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_rnr_rsp(nskb, 0, llc->vR);
5971da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
598249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
5991da177e4SLinus Torvalds 			goto free;
6001da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
6011da177e4SLinus Torvalds 	}
6021da177e4SLinus Torvalds out:
6031da177e4SLinus Torvalds 	return rc;
6041da177e4SLinus Torvalds free:
6051da177e4SLinus Torvalds 	kfree_skb(nskb);
6061da177e4SLinus Torvalds 	goto out;
6071da177e4SLinus Torvalds }
6081da177e4SLinus Torvalds 
llc_conn_ac_set_remote_busy(struct sock * sk,struct sk_buff * skb)6091da177e4SLinus Torvalds int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
6101da177e4SLinus Torvalds {
6111da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 	if (!llc->remote_busy_flag) {
6141da177e4SLinus Torvalds 		llc->remote_busy_flag = 1;
6151da177e4SLinus Torvalds 		mod_timer(&llc->busy_state_timer.timer,
616590232a7SArnaldo Carvalho de Melo 			 jiffies + llc->busy_state_timer.expire);
6171da177e4SLinus Torvalds 	}
6181da177e4SLinus Torvalds 	return 0;
6191da177e4SLinus Torvalds }
6201da177e4SLinus Torvalds 
llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)6211da177e4SLinus Torvalds int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
6221da177e4SLinus Torvalds {
6231da177e4SLinus Torvalds 	int rc = -ENOBUFS;
6241d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
625f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	if (nskb) {
6281da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
6311da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
6321da177e4SLinus Torvalds 		llc_pdu_init_as_rnr_rsp(nskb, 0, llc->vR);
6331da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
634249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
6351da177e4SLinus Torvalds 			goto free;
6361da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
6371da177e4SLinus Torvalds 	}
6381da177e4SLinus Torvalds out:
6391da177e4SLinus Torvalds 	return rc;
6401da177e4SLinus Torvalds free:
6411da177e4SLinus Torvalds 	kfree_skb(nskb);
6421da177e4SLinus Torvalds 	goto out;
6431da177e4SLinus Torvalds }
6441da177e4SLinus Torvalds 
llc_conn_ac_send_rr_cmd_p_set_1(struct sock * sk,struct sk_buff * skb)6451da177e4SLinus Torvalds int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
6461da177e4SLinus Torvalds {
6471da177e4SLinus Torvalds 	int rc = -ENOBUFS;
6481d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
649f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	if (nskb) {
6521da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
6551da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_CMD);
6561da177e4SLinus Torvalds 		llc_pdu_init_as_rr_cmd(nskb, 1, llc->vR);
6571da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
658249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
6591da177e4SLinus Torvalds 			goto free;
6601da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
6611da177e4SLinus Torvalds 	}
6621da177e4SLinus Torvalds out:
6631da177e4SLinus Torvalds 	return rc;
6641da177e4SLinus Torvalds free:
6651da177e4SLinus Torvalds 	kfree_skb(nskb);
6661da177e4SLinus Torvalds 	goto out;
6671da177e4SLinus Torvalds }
6681da177e4SLinus Torvalds 
llc_conn_ac_send_rr_rsp_f_set_1(struct sock * sk,struct sk_buff * skb)6691da177e4SLinus Torvalds int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
6701da177e4SLinus Torvalds {
6711da177e4SLinus Torvalds 	int rc = -ENOBUFS;
6721d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
673f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds 	if (nskb) {
6761da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
6771da177e4SLinus Torvalds 		u8 f_bit = 1;
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
6801da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
6811da177e4SLinus Torvalds 		llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
6821da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
683249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
6841da177e4SLinus Torvalds 			goto free;
6851da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds out:
6881da177e4SLinus Torvalds 	return rc;
6891da177e4SLinus Torvalds free:
6901da177e4SLinus Torvalds 	kfree_skb(nskb);
6911da177e4SLinus Torvalds 	goto out;
6921da177e4SLinus Torvalds }
6931da177e4SLinus Torvalds 
llc_conn_ac_send_ack_rsp_f_set_1(struct sock * sk,struct sk_buff * skb)6941da177e4SLinus Torvalds int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
6951da177e4SLinus Torvalds {
6961da177e4SLinus Torvalds 	int rc = -ENOBUFS;
6971d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
698f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	if (nskb) {
7011da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
7021da177e4SLinus Torvalds 
7031da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
7041da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
705838a75daSArnaldo Carvalho de Melo 		llc_pdu_init_as_rr_rsp(nskb, 1, llc->vR);
7061da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
707249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
7081da177e4SLinus Torvalds 			goto free;
7091da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
7101da177e4SLinus Torvalds 	}
7111da177e4SLinus Torvalds out:
7121da177e4SLinus Torvalds 	return rc;
7131da177e4SLinus Torvalds free:
7141da177e4SLinus Torvalds 	kfree_skb(nskb);
7151da177e4SLinus Torvalds 	goto out;
7161da177e4SLinus Torvalds }
7171da177e4SLinus Torvalds 
llc_conn_ac_send_rr_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)7181da177e4SLinus Torvalds int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
7191da177e4SLinus Torvalds {
7201da177e4SLinus Torvalds 	int rc = -ENOBUFS;
7211d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
722f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	if (nskb) {
7251da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
7281da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
7291da177e4SLinus Torvalds 		llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
7301da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
731249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
7321da177e4SLinus Torvalds 			goto free;
7331da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
7341da177e4SLinus Torvalds 	}
7351da177e4SLinus Torvalds out:
7361da177e4SLinus Torvalds 	return rc;
7371da177e4SLinus Torvalds free:
7381da177e4SLinus Torvalds 	kfree_skb(nskb);
7391da177e4SLinus Torvalds 	goto out;
7401da177e4SLinus Torvalds }
7411da177e4SLinus Torvalds 
llc_conn_ac_send_ack_xxx_x_set_0(struct sock * sk,struct sk_buff * skb)7421da177e4SLinus Torvalds int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
7431da177e4SLinus Torvalds {
7441da177e4SLinus Torvalds 	int rc = -ENOBUFS;
7451d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
746f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	if (nskb) {
7491da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
7521da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
7531da177e4SLinus Torvalds 		llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
7541da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
755249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
7561da177e4SLinus Torvalds 			goto free;
7571da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
7581da177e4SLinus Torvalds 	}
7591da177e4SLinus Torvalds out:
7601da177e4SLinus Torvalds 	return rc;
7611da177e4SLinus Torvalds free:
7621da177e4SLinus Torvalds 	kfree_skb(nskb);
7631da177e4SLinus Torvalds 	goto out;
7641da177e4SLinus Torvalds }
7651da177e4SLinus Torvalds 
llc_conn_set_p_flag(struct sock * sk,u8 value)7661da177e4SLinus Torvalds void llc_conn_set_p_flag(struct sock *sk, u8 value)
7671da177e4SLinus Torvalds {
7681da177e4SLinus Torvalds 	int state_changed = llc_sk(sk)->p_flag && !value;
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 	llc_sk(sk)->p_flag = value;
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 	if (state_changed)
7731da177e4SLinus Torvalds 		sk->sk_state_change(sk);
7741da177e4SLinus Torvalds }
7751da177e4SLinus Torvalds 
llc_conn_ac_send_sabme_cmd_p_set_x(struct sock * sk,struct sk_buff * skb)7761da177e4SLinus Torvalds int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
7771da177e4SLinus Torvalds {
7781da177e4SLinus Torvalds 	int rc = -ENOBUFS;
7791da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
780f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U, 0);
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	if (nskb) {
7831da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
784*2ef6db76SJakub Kicinski 		const u8 *dmac = llc->daddr.mac;
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 		if (llc->dev->flags & IFF_LOOPBACK)
7871da177e4SLinus Torvalds 			dmac = llc->dev->dev_addr;
7881da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
7891da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_CMD);
7901da177e4SLinus Torvalds 		llc_pdu_init_as_sabme_cmd(nskb, 1);
7911da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, dmac);
792249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
7931da177e4SLinus Torvalds 			goto free;
7941da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
7951da177e4SLinus Torvalds 		llc_conn_set_p_flag(sk, 1);
7961da177e4SLinus Torvalds 	}
7971da177e4SLinus Torvalds out:
7981da177e4SLinus Torvalds 	return rc;
7991da177e4SLinus Torvalds free:
8001da177e4SLinus Torvalds 	kfree_skb(nskb);
8011da177e4SLinus Torvalds 	goto out;
8021da177e4SLinus Torvalds }
8031da177e4SLinus Torvalds 
llc_conn_ac_send_ua_rsp_f_set_p(struct sock * sk,struct sk_buff * skb)8041da177e4SLinus Torvalds int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
8051da177e4SLinus Torvalds {
8061da177e4SLinus Torvalds 	u8 f_bit;
8071da177e4SLinus Torvalds 	int rc = -ENOBUFS;
8081d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
809f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_U, 0);
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 	llc_pdu_decode_pf_bit(skb, &f_bit);
8121da177e4SLinus Torvalds 	if (nskb) {
8131da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 		nskb->dev = llc->dev;
8161da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
8171da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
8181da177e4SLinus Torvalds 		llc_pdu_init_as_ua_rsp(nskb, f_bit);
8191da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
820249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
8211da177e4SLinus Torvalds 			goto free;
8221da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
8231da177e4SLinus Torvalds 	}
8241da177e4SLinus Torvalds out:
8251da177e4SLinus Torvalds 	return rc;
8261da177e4SLinus Torvalds free:
8271da177e4SLinus Torvalds 	kfree_skb(nskb);
8281da177e4SLinus Torvalds 	goto out;
8291da177e4SLinus Torvalds }
8301da177e4SLinus Torvalds 
llc_conn_ac_set_s_flag_0(struct sock * sk,struct sk_buff * skb)8311da177e4SLinus Torvalds int llc_conn_ac_set_s_flag_0(struct sock *sk, struct sk_buff *skb)
8321da177e4SLinus Torvalds {
8331da177e4SLinus Torvalds 	llc_sk(sk)->s_flag = 0;
8341da177e4SLinus Torvalds 	return 0;
8351da177e4SLinus Torvalds }
8361da177e4SLinus Torvalds 
llc_conn_ac_set_s_flag_1(struct sock * sk,struct sk_buff * skb)8371da177e4SLinus Torvalds int llc_conn_ac_set_s_flag_1(struct sock *sk, struct sk_buff *skb)
8381da177e4SLinus Torvalds {
8391da177e4SLinus Torvalds 	llc_sk(sk)->s_flag = 1;
8401da177e4SLinus Torvalds 	return 0;
8411da177e4SLinus Torvalds }
8421da177e4SLinus Torvalds 
llc_conn_ac_start_p_timer(struct sock * sk,struct sk_buff * skb)8431da177e4SLinus Torvalds int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
8441da177e4SLinus Torvalds {
8451da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds 	llc_conn_set_p_flag(sk, 1);
8481da177e4SLinus Torvalds 	mod_timer(&llc->pf_cycle_timer.timer,
849590232a7SArnaldo Carvalho de Melo 		  jiffies + llc->pf_cycle_timer.expire);
8501da177e4SLinus Torvalds 	return 0;
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds /**
8541da177e4SLinus Torvalds  *	llc_conn_ac_send_ack_if_needed - check if ack is needed
8551da177e4SLinus Torvalds  *	@sk: current connection structure
8561da177e4SLinus Torvalds  *	@skb: current event
8571da177e4SLinus Torvalds  *
8581da177e4SLinus Torvalds  *	Checks number of received PDUs which have not been acknowledged, yet,
8591da177e4SLinus Torvalds  *	If number of them reaches to "npta"(Number of PDUs To Acknowledge) then
8601da177e4SLinus Torvalds  *	sends an RR response as acknowledgement for them.  Returns 0 for
8611da177e4SLinus Torvalds  *	success, 1 otherwise.
8621da177e4SLinus Torvalds  */
llc_conn_ac_send_ack_if_needed(struct sock * sk,struct sk_buff * skb)8631da177e4SLinus Torvalds int llc_conn_ac_send_ack_if_needed(struct sock *sk, struct sk_buff *skb)
8641da177e4SLinus Torvalds {
8651da177e4SLinus Torvalds 	u8 pf_bit;
8661da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 	llc_pdu_decode_pf_bit(skb, &pf_bit);
8691da177e4SLinus Torvalds 	llc->ack_pf |= pf_bit & 1;
8701da177e4SLinus Torvalds 	if (!llc->ack_must_be_send) {
8711da177e4SLinus Torvalds 		llc->first_pdu_Ns = llc->vR;
8721da177e4SLinus Torvalds 		llc->ack_must_be_send = 1;
8731da177e4SLinus Torvalds 		llc->ack_pf = pf_bit & 1;
8741da177e4SLinus Torvalds 	}
87559c6196eSJochen Friedrich 	if (((llc->vR - llc->first_pdu_Ns + 1 + LLC_2_SEQ_NBR_MODULO)
87659c6196eSJochen Friedrich 			% LLC_2_SEQ_NBR_MODULO) >= llc->npta) {
8771da177e4SLinus Torvalds 		llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, skb);
8781da177e4SLinus Torvalds 		llc->ack_must_be_send	= 0;
8791da177e4SLinus Torvalds 		llc->ack_pf		= 0;
8801da177e4SLinus Torvalds 		llc_conn_ac_inc_npta_value(sk, skb);
8811da177e4SLinus Torvalds 	}
8821da177e4SLinus Torvalds 	return 0;
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds /**
8861da177e4SLinus Torvalds  *	llc_conn_ac_rst_sendack_flag - resets ack_must_be_send flag
8871da177e4SLinus Torvalds  *	@sk: current connection structure
8881da177e4SLinus Torvalds  *	@skb: current event
8891da177e4SLinus Torvalds  *
8901da177e4SLinus Torvalds  *	This action resets ack_must_be_send flag of given connection, this flag
8911da177e4SLinus Torvalds  *	indicates if there is any PDU which has not been acknowledged yet.
8921da177e4SLinus Torvalds  *	Returns 0 for success, 1 otherwise.
8931da177e4SLinus Torvalds  */
llc_conn_ac_rst_sendack_flag(struct sock * sk,struct sk_buff * skb)8941da177e4SLinus Torvalds int llc_conn_ac_rst_sendack_flag(struct sock *sk, struct sk_buff *skb)
8951da177e4SLinus Torvalds {
8961da177e4SLinus Torvalds 	llc_sk(sk)->ack_must_be_send = llc_sk(sk)->ack_pf = 0;
8971da177e4SLinus Torvalds 	return 0;
8981da177e4SLinus Torvalds }
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds /**
9011da177e4SLinus Torvalds  *	llc_conn_ac_send_i_rsp_f_set_ackpf - acknowledge received PDUs
9021da177e4SLinus Torvalds  *	@sk: current connection structure
9031da177e4SLinus Torvalds  *	@skb: current event
9041da177e4SLinus Torvalds  *
9051da177e4SLinus Torvalds  *	Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to
9061da177e4SLinus Torvalds  *	all received PDUs which have not been acknowledged, yet. ack_pf flag is
9071da177e4SLinus Torvalds  *	set to one if one PDU with p-bit set to one is received.  Returns 0 for
9081da177e4SLinus Torvalds  *	success, 1 otherwise.
9091da177e4SLinus Torvalds  */
llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock * sk,struct sk_buff * skb)9101da177e4SLinus Torvalds static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
9111da177e4SLinus Torvalds 					      struct sk_buff *skb)
9121da177e4SLinus Torvalds {
9131da177e4SLinus Torvalds 	int rc;
9141da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
9151da177e4SLinus Torvalds 	struct llc_sap *sap = llc->sap;
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds 	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
9181da177e4SLinus Torvalds 			    llc->daddr.lsap, LLC_PDU_RSP);
9191da177e4SLinus Torvalds 	llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR);
9201da177e4SLinus Torvalds 	rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
921249ff1c6SArnaldo Carvalho de Melo 	if (likely(!rc)) {
922b74555deSEric Biggers 		skb_get(skb);
923b74555deSEric Biggers 		llc_conn_send_pdu(sk, skb);
9241da177e4SLinus Torvalds 		llc_conn_ac_inc_vs_by_1(sk, skb);
9251da177e4SLinus Torvalds 	}
9261da177e4SLinus Torvalds 	return rc;
9271da177e4SLinus Torvalds }
9281da177e4SLinus Torvalds 
9291da177e4SLinus Torvalds /**
9301da177e4SLinus Torvalds  *	llc_conn_ac_send_i_as_ack - sends an I-format PDU to acknowledge rx PDUs
9311da177e4SLinus Torvalds  *	@sk: current connection structure.
9321da177e4SLinus Torvalds  *	@skb: current event.
9331da177e4SLinus Torvalds  *
9341da177e4SLinus Torvalds  *	This action sends an I-format PDU as acknowledge to received PDUs which
9351da177e4SLinus Torvalds  *	have not been acknowledged, yet, if there is any. By using of this
9361da177e4SLinus Torvalds  *	action number of acknowledgements decreases, this technic is called
9371da177e4SLinus Torvalds  *	piggy backing. Returns 0 for success, 1 otherwise.
9381da177e4SLinus Torvalds  */
llc_conn_ac_send_i_as_ack(struct sock * sk,struct sk_buff * skb)9391da177e4SLinus Torvalds int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
9401da177e4SLinus Torvalds {
9411da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
942b85ab56cSCong Wang 	int ret;
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	if (llc->ack_must_be_send) {
945b85ab56cSCong Wang 		ret = llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
9461da177e4SLinus Torvalds 		llc->ack_must_be_send = 0 ;
9471da177e4SLinus Torvalds 		llc->ack_pf = 0;
948b85ab56cSCong Wang 	} else {
949b85ab56cSCong Wang 		ret = llc_conn_ac_send_i_cmd_p_set_0(sk, skb);
950b85ab56cSCong Wang 	}
951b85ab56cSCong Wang 
952b85ab56cSCong Wang 	return ret;
9531da177e4SLinus Torvalds }
9541da177e4SLinus Torvalds 
9551da177e4SLinus Torvalds /**
9561da177e4SLinus Torvalds  *	llc_conn_ac_send_rr_rsp_f_set_ackpf - ack all rx PDUs not yet acked
9571da177e4SLinus Torvalds  *	@sk: current connection structure.
9581da177e4SLinus Torvalds  *	@skb: current event.
9591da177e4SLinus Torvalds  *
9601da177e4SLinus Torvalds  *	This action sends an RR response with f-bit set to ack_pf flag as
9611da177e4SLinus Torvalds  *	acknowledge to all received PDUs which have not been acknowledged, yet,
9621da177e4SLinus Torvalds  *	if there is any. ack_pf flag indicates if a PDU has been received with
9631da177e4SLinus Torvalds  *	p-bit set to one. Returns 0 for success, 1 otherwise.
9641da177e4SLinus Torvalds  */
llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock * sk,struct sk_buff * skb)9651da177e4SLinus Torvalds static int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk,
9661da177e4SLinus Torvalds 					       struct sk_buff *skb)
9671da177e4SLinus Torvalds {
9681da177e4SLinus Torvalds 	int rc = -ENOBUFS;
9691d67e650SArnaldo Carvalho de Melo 	struct llc_sock *llc = llc_sk(sk);
970f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(sk, llc->dev, LLC_PDU_TYPE_S, 0);
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	if (nskb) {
9731da177e4SLinus Torvalds 		struct llc_sap *sap = llc->sap;
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 		llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
9761da177e4SLinus Torvalds 				    llc->daddr.lsap, LLC_PDU_RSP);
9771da177e4SLinus Torvalds 		llc_pdu_init_as_rr_rsp(nskb, llc->ack_pf, llc->vR);
9781da177e4SLinus Torvalds 		rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
979249ff1c6SArnaldo Carvalho de Melo 		if (unlikely(rc))
9801da177e4SLinus Torvalds 			goto free;
9811da177e4SLinus Torvalds 		llc_conn_send_pdu(sk, nskb);
9821da177e4SLinus Torvalds 	}
9831da177e4SLinus Torvalds out:
9841da177e4SLinus Torvalds 	return rc;
9851da177e4SLinus Torvalds free:
9861da177e4SLinus Torvalds 	kfree_skb(nskb);
9871da177e4SLinus Torvalds 	goto out;
9881da177e4SLinus Torvalds }
9891da177e4SLinus Torvalds 
9901da177e4SLinus Torvalds /**
9911da177e4SLinus Torvalds  *	llc_conn_ac_inc_npta_value - tries to make value of npta greater
9921da177e4SLinus Torvalds  *	@sk: current connection structure.
9931da177e4SLinus Torvalds  *	@skb: current event.
9941da177e4SLinus Torvalds  *
9951da177e4SLinus Torvalds  *	After "inc_cntr" times calling of this action, "npta" increase by one.
9961da177e4SLinus Torvalds  *	this action tries to make vale of "npta" greater as possible; number of
9971da177e4SLinus Torvalds  *	acknowledgements decreases by increasing of "npta". Returns 0 for
9981da177e4SLinus Torvalds  *	success, 1 otherwise.
9991da177e4SLinus Torvalds  */
llc_conn_ac_inc_npta_value(struct sock * sk,struct sk_buff * skb)10001da177e4SLinus Torvalds static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb)
10011da177e4SLinus Torvalds {
10021da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 	if (!llc->inc_cntr) {
10051da177e4SLinus Torvalds 		llc->dec_step = 0;
10061da177e4SLinus Torvalds 		llc->dec_cntr = llc->inc_cntr = 2;
10071da177e4SLinus Torvalds 		++llc->npta;
100838199824SDavid S. Miller 		if (llc->npta > (u8) ~LLC_2_SEQ_NBR_MODULO)
100938199824SDavid S. Miller 			llc->npta = (u8) ~LLC_2_SEQ_NBR_MODULO;
10101da177e4SLinus Torvalds 	} else
10111da177e4SLinus Torvalds 		--llc->inc_cntr;
10121da177e4SLinus Torvalds 	return 0;
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds /**
10161da177e4SLinus Torvalds  *	llc_conn_ac_adjust_npta_by_rr - decreases "npta" by one
10171da177e4SLinus Torvalds  *	@sk: current connection structure.
10181da177e4SLinus Torvalds  *	@skb: current event.
10191da177e4SLinus Torvalds  *
10201da177e4SLinus Torvalds  *	After receiving "dec_cntr" times RR command, this action decreases
10211da177e4SLinus Torvalds  *	"npta" by one. Returns 0 for success, 1 otherwise.
10221da177e4SLinus Torvalds  */
llc_conn_ac_adjust_npta_by_rr(struct sock * sk,struct sk_buff * skb)10231da177e4SLinus Torvalds int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct sk_buff *skb)
10241da177e4SLinus Torvalds {
10251da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 	if (!llc->connect_step && !llc->remote_busy_flag) {
10281da177e4SLinus Torvalds 		if (!llc->dec_step) {
10291da177e4SLinus Torvalds 			if (!llc->dec_cntr) {
10301da177e4SLinus Torvalds 				llc->inc_cntr = llc->dec_cntr = 2;
10311da177e4SLinus Torvalds 				if (llc->npta > 0)
10321da177e4SLinus Torvalds 					llc->npta = llc->npta - 1;
10331da177e4SLinus Torvalds 			} else
10341da177e4SLinus Torvalds 				llc->dec_cntr -=1;
10351da177e4SLinus Torvalds 		}
10361da177e4SLinus Torvalds 	} else
10371da177e4SLinus Torvalds 		llc->connect_step = 0 ;
10381da177e4SLinus Torvalds 	return 0;
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds /**
10421da177e4SLinus Torvalds  *	llc_conn_ac_adjust_npta_by_rnr - decreases "npta" by one
10431da177e4SLinus Torvalds  *	@sk: current connection structure.
10441da177e4SLinus Torvalds  *	@skb: current event.
10451da177e4SLinus Torvalds  *
10461da177e4SLinus Torvalds  *	After receiving "dec_cntr" times RNR command, this action decreases
10471da177e4SLinus Torvalds  *	"npta" by one. Returns 0 for success, 1 otherwise.
10481da177e4SLinus Torvalds  */
llc_conn_ac_adjust_npta_by_rnr(struct sock * sk,struct sk_buff * skb)10491da177e4SLinus Torvalds int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk, struct sk_buff *skb)
10501da177e4SLinus Torvalds {
10511da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds 	if (llc->remote_busy_flag)
10541da177e4SLinus Torvalds 		if (!llc->dec_step) {
10551da177e4SLinus Torvalds 			if (!llc->dec_cntr) {
10561da177e4SLinus Torvalds 				llc->inc_cntr = llc->dec_cntr = 2;
10571da177e4SLinus Torvalds 				if (llc->npta > 0)
10581da177e4SLinus Torvalds 					--llc->npta;
10591da177e4SLinus Torvalds 			} else
10601da177e4SLinus Torvalds 				--llc->dec_cntr;
10611da177e4SLinus Torvalds 		}
10621da177e4SLinus Torvalds 	return 0;
10631da177e4SLinus Torvalds }
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds /**
10661da177e4SLinus Torvalds  *	llc_conn_ac_dec_tx_win_size - decreases tx window size
10671da177e4SLinus Torvalds  *	@sk: current connection structure.
10681da177e4SLinus Torvalds  *	@skb: current event.
10691da177e4SLinus Torvalds  *
10701da177e4SLinus Torvalds  *	After receiving of a REJ command or response, transmit window size is
10711da177e4SLinus Torvalds  *	decreased by number of PDUs which are outstanding yet. Returns 0 for
10721da177e4SLinus Torvalds  *	success, 1 otherwise.
10731da177e4SLinus Torvalds  */
llc_conn_ac_dec_tx_win_size(struct sock * sk,struct sk_buff * skb)10741da177e4SLinus Torvalds int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct sk_buff *skb)
10751da177e4SLinus Torvalds {
10761da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
10771da177e4SLinus Torvalds 	u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q);
10781da177e4SLinus Torvalds 
107959c6196eSJochen Friedrich 	if (llc->k - unacked_pdu < 1)
108059c6196eSJochen Friedrich 		llc->k = 1;
108159c6196eSJochen Friedrich 	else
10821da177e4SLinus Torvalds 		llc->k -= unacked_pdu;
10831da177e4SLinus Torvalds 	return 0;
10841da177e4SLinus Torvalds }
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds /**
10871da177e4SLinus Torvalds  *	llc_conn_ac_inc_tx_win_size - tx window size is inc by 1
10881da177e4SLinus Torvalds  *	@sk: current connection structure.
10891da177e4SLinus Torvalds  *	@skb: current event.
10901da177e4SLinus Torvalds  *
10911da177e4SLinus Torvalds  *	After receiving an RR response with f-bit set to one, transmit window
10921da177e4SLinus Torvalds  *	size is increased by one. Returns 0 for success, 1 otherwise.
10931da177e4SLinus Torvalds  */
llc_conn_ac_inc_tx_win_size(struct sock * sk,struct sk_buff * skb)10941da177e4SLinus Torvalds int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
10951da177e4SLinus Torvalds {
10961da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 	llc->k += 1;
109938199824SDavid S. Miller 	if (llc->k > (u8) ~LLC_2_SEQ_NBR_MODULO)
110038199824SDavid S. Miller 		llc->k = (u8) ~LLC_2_SEQ_NBR_MODULO;
11011da177e4SLinus Torvalds 	return 0;
11021da177e4SLinus Torvalds }
11031da177e4SLinus Torvalds 
llc_conn_ac_stop_all_timers(struct sock * sk,struct sk_buff * skb)11041da177e4SLinus Torvalds int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb)
11051da177e4SLinus Torvalds {
1106b905ef9aSCong Wang 	llc_sk_stop_all_timers(sk, false);
11071da177e4SLinus Torvalds 	return 0;
11081da177e4SLinus Torvalds }
11091da177e4SLinus Torvalds 
llc_conn_ac_stop_other_timers(struct sock * sk,struct sk_buff * skb)11101da177e4SLinus Torvalds int llc_conn_ac_stop_other_timers(struct sock *sk, struct sk_buff *skb)
11111da177e4SLinus Torvalds {
11121da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	del_timer(&llc->rej_sent_timer.timer);
11151da177e4SLinus Torvalds 	del_timer(&llc->pf_cycle_timer.timer);
11161da177e4SLinus Torvalds 	del_timer(&llc->busy_state_timer.timer);
11171da177e4SLinus Torvalds 	llc->ack_must_be_send = 0;
11181da177e4SLinus Torvalds 	llc->ack_pf = 0;
11191da177e4SLinus Torvalds 	return 0;
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds 
llc_conn_ac_start_ack_timer(struct sock * sk,struct sk_buff * skb)11221da177e4SLinus Torvalds int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb)
11231da177e4SLinus Torvalds {
11241da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
11251da177e4SLinus Torvalds 
1126590232a7SArnaldo Carvalho de Melo 	mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire);
11271da177e4SLinus Torvalds 	return 0;
11281da177e4SLinus Torvalds }
11291da177e4SLinus Torvalds 
llc_conn_ac_start_rej_timer(struct sock * sk,struct sk_buff * skb)11301da177e4SLinus Torvalds int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb)
11311da177e4SLinus Torvalds {
11321da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
11331da177e4SLinus Torvalds 
11341da177e4SLinus Torvalds 	mod_timer(&llc->rej_sent_timer.timer,
1135590232a7SArnaldo Carvalho de Melo 		  jiffies + llc->rej_sent_timer.expire);
11361da177e4SLinus Torvalds 	return 0;
11371da177e4SLinus Torvalds }
11381da177e4SLinus Torvalds 
llc_conn_ac_start_ack_tmr_if_not_running(struct sock * sk,struct sk_buff * skb)11391da177e4SLinus Torvalds int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
11401da177e4SLinus Torvalds 					     struct sk_buff *skb)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
11431da177e4SLinus Torvalds 
11441da177e4SLinus Torvalds 	if (!timer_pending(&llc->ack_timer.timer))
11451da177e4SLinus Torvalds 		mod_timer(&llc->ack_timer.timer,
1146590232a7SArnaldo Carvalho de Melo 			  jiffies + llc->ack_timer.expire);
11471da177e4SLinus Torvalds 	return 0;
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds 
llc_conn_ac_stop_ack_timer(struct sock * sk,struct sk_buff * skb)11501da177e4SLinus Torvalds int llc_conn_ac_stop_ack_timer(struct sock *sk, struct sk_buff *skb)
11511da177e4SLinus Torvalds {
11521da177e4SLinus Torvalds 	del_timer(&llc_sk(sk)->ack_timer.timer);
11531da177e4SLinus Torvalds 	return 0;
11541da177e4SLinus Torvalds }
11551da177e4SLinus Torvalds 
llc_conn_ac_stop_p_timer(struct sock * sk,struct sk_buff * skb)11561da177e4SLinus Torvalds int llc_conn_ac_stop_p_timer(struct sock *sk, struct sk_buff *skb)
11571da177e4SLinus Torvalds {
11581da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds 	del_timer(&llc->pf_cycle_timer.timer);
11611da177e4SLinus Torvalds 	llc_conn_set_p_flag(sk, 0);
11621da177e4SLinus Torvalds 	return 0;
11631da177e4SLinus Torvalds }
11641da177e4SLinus Torvalds 
llc_conn_ac_stop_rej_timer(struct sock * sk,struct sk_buff * skb)11651da177e4SLinus Torvalds int llc_conn_ac_stop_rej_timer(struct sock *sk, struct sk_buff *skb)
11661da177e4SLinus Torvalds {
11671da177e4SLinus Torvalds 	del_timer(&llc_sk(sk)->rej_sent_timer.timer);
11681da177e4SLinus Torvalds 	return 0;
11691da177e4SLinus Torvalds }
11701da177e4SLinus Torvalds 
llc_conn_ac_upd_nr_received(struct sock * sk,struct sk_buff * skb)11711da177e4SLinus Torvalds int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
11721da177e4SLinus Torvalds {
11731da177e4SLinus Torvalds 	int acked;
11741da177e4SLinus Torvalds 	u16 unacked = 0;
11751da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
11761da177e4SLinus Torvalds 	struct llc_sock *llc = llc_sk(sk);
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 	llc->last_nr = PDU_SUPV_GET_Nr(pdu);
11791da177e4SLinus Torvalds 	acked = llc_conn_remove_acked_pdus(sk, llc->last_nr, &unacked);
11801da177e4SLinus Torvalds 	/* On loopback we don't queue I frames in unack_pdu_q queue. */
11811da177e4SLinus Torvalds 	if (acked > 0 || (llc->dev->flags & IFF_LOOPBACK)) {
11821da177e4SLinus Torvalds 		llc->retry_count = 0;
11831da177e4SLinus Torvalds 		del_timer(&llc->ack_timer.timer);
11841da177e4SLinus Torvalds 		if (llc->failed_data_req) {
11851da177e4SLinus Torvalds 			/* already, we did not accept data from upper layer
11861da177e4SLinus Torvalds 			 * (tx_window full or unacceptable state). Now, we
11871da177e4SLinus Torvalds 			 * can send data and must inform to upper layer.
11881da177e4SLinus Torvalds 			 */
11891da177e4SLinus Torvalds 			llc->failed_data_req = 0;
11901da177e4SLinus Torvalds 			llc_conn_ac_data_confirm(sk, skb);
11911da177e4SLinus Torvalds 		}
11921da177e4SLinus Torvalds 		if (unacked)
11931da177e4SLinus Torvalds 			mod_timer(&llc->ack_timer.timer,
1194590232a7SArnaldo Carvalho de Melo 				  jiffies + llc->ack_timer.expire);
11951da177e4SLinus Torvalds 	} else if (llc->failed_data_req) {
11961da177e4SLinus Torvalds 		u8 f_bit;
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 		llc_pdu_decode_pf_bit(skb, &f_bit);
11991da177e4SLinus Torvalds 		if (f_bit == 1) {
12001da177e4SLinus Torvalds 			llc->failed_data_req = 0;
12011da177e4SLinus Torvalds 			llc_conn_ac_data_confirm(sk, skb);
12021da177e4SLinus Torvalds 		}
12031da177e4SLinus Torvalds 	}
12041da177e4SLinus Torvalds 	return 0;
12051da177e4SLinus Torvalds }
12061da177e4SLinus Torvalds 
llc_conn_ac_upd_p_flag(struct sock * sk,struct sk_buff * skb)12071da177e4SLinus Torvalds int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb)
12081da177e4SLinus Torvalds {
12091da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 	if (LLC_PDU_IS_RSP(pdu)) {
12121da177e4SLinus Torvalds 		u8 f_bit;
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds 		llc_pdu_decode_pf_bit(skb, &f_bit);
12151da177e4SLinus Torvalds 		if (f_bit) {
12161da177e4SLinus Torvalds 			llc_conn_set_p_flag(sk, 0);
12171da177e4SLinus Torvalds 			llc_conn_ac_stop_p_timer(sk, skb);
12181da177e4SLinus Torvalds 		}
12191da177e4SLinus Torvalds 	}
12201da177e4SLinus Torvalds 	return 0;
12211da177e4SLinus Torvalds }
12221da177e4SLinus Torvalds 
llc_conn_ac_set_data_flag_2(struct sock * sk,struct sk_buff * skb)12231da177e4SLinus Torvalds int llc_conn_ac_set_data_flag_2(struct sock *sk, struct sk_buff *skb)
12241da177e4SLinus Torvalds {
12251da177e4SLinus Torvalds 	llc_sk(sk)->data_flag = 2;
12261da177e4SLinus Torvalds 	return 0;
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds 
llc_conn_ac_set_data_flag_0(struct sock * sk,struct sk_buff * skb)12291da177e4SLinus Torvalds int llc_conn_ac_set_data_flag_0(struct sock *sk, struct sk_buff *skb)
12301da177e4SLinus Torvalds {
12311da177e4SLinus Torvalds 	llc_sk(sk)->data_flag = 0;
12321da177e4SLinus Torvalds 	return 0;
12331da177e4SLinus Torvalds }
12341da177e4SLinus Torvalds 
llc_conn_ac_set_data_flag_1(struct sock * sk,struct sk_buff * skb)12351da177e4SLinus Torvalds int llc_conn_ac_set_data_flag_1(struct sock *sk, struct sk_buff *skb)
12361da177e4SLinus Torvalds {
12371da177e4SLinus Torvalds 	llc_sk(sk)->data_flag = 1;
12381da177e4SLinus Torvalds 	return 0;
12391da177e4SLinus Torvalds }
12401da177e4SLinus Torvalds 
llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock * sk,struct sk_buff * skb)12411da177e4SLinus Torvalds int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock *sk,
12421da177e4SLinus Torvalds 						  struct sk_buff *skb)
12431da177e4SLinus Torvalds {
12441da177e4SLinus Torvalds 	if (!llc_sk(sk)->data_flag)
12451da177e4SLinus Torvalds 		llc_sk(sk)->data_flag = 1;
12461da177e4SLinus Torvalds 	return 0;
12471da177e4SLinus Torvalds }
12481da177e4SLinus Torvalds 
llc_conn_ac_set_p_flag_0(struct sock * sk,struct sk_buff * skb)12491da177e4SLinus Torvalds int llc_conn_ac_set_p_flag_0(struct sock *sk, struct sk_buff *skb)
12501da177e4SLinus Torvalds {
12511da177e4SLinus Torvalds 	llc_conn_set_p_flag(sk, 0);
12521da177e4SLinus Torvalds 	return 0;
12531da177e4SLinus Torvalds }
12541da177e4SLinus Torvalds 
llc_conn_ac_set_p_flag_1(struct sock * sk,struct sk_buff * skb)12551da177e4SLinus Torvalds static int llc_conn_ac_set_p_flag_1(struct sock *sk, struct sk_buff *skb)
12561da177e4SLinus Torvalds {
12571da177e4SLinus Torvalds 	llc_conn_set_p_flag(sk, 1);
12581da177e4SLinus Torvalds 	return 0;
12591da177e4SLinus Torvalds }
12601da177e4SLinus Torvalds 
llc_conn_ac_set_remote_busy_0(struct sock * sk,struct sk_buff * skb)12611da177e4SLinus Torvalds int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct sk_buff *skb)
12621da177e4SLinus Torvalds {
12631da177e4SLinus Torvalds 	llc_sk(sk)->remote_busy_flag = 0;
12641da177e4SLinus Torvalds 	return 0;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds 
llc_conn_ac_set_cause_flag_0(struct sock * sk,struct sk_buff * skb)12671da177e4SLinus Torvalds int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct sk_buff *skb)
12681da177e4SLinus Torvalds {
12691da177e4SLinus Torvalds 	llc_sk(sk)->cause_flag = 0;
12701da177e4SLinus Torvalds 	return 0;
12711da177e4SLinus Torvalds }
12721da177e4SLinus Torvalds 
llc_conn_ac_set_cause_flag_1(struct sock * sk,struct sk_buff * skb)12731da177e4SLinus Torvalds int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct sk_buff *skb)
12741da177e4SLinus Torvalds {
12751da177e4SLinus Torvalds 	llc_sk(sk)->cause_flag = 1;
12761da177e4SLinus Torvalds 	return 0;
12771da177e4SLinus Torvalds }
12781da177e4SLinus Torvalds 
llc_conn_ac_set_retry_cnt_0(struct sock * sk,struct sk_buff * skb)12791da177e4SLinus Torvalds int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct sk_buff *skb)
12801da177e4SLinus Torvalds {
12811da177e4SLinus Torvalds 	llc_sk(sk)->retry_count = 0;
12821da177e4SLinus Torvalds 	return 0;
12831da177e4SLinus Torvalds }
12841da177e4SLinus Torvalds 
llc_conn_ac_inc_retry_cnt_by_1(struct sock * sk,struct sk_buff * skb)12851da177e4SLinus Torvalds int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk, struct sk_buff *skb)
12861da177e4SLinus Torvalds {
12871da177e4SLinus Torvalds 	llc_sk(sk)->retry_count++;
12881da177e4SLinus Torvalds 	return 0;
12891da177e4SLinus Torvalds }
12901da177e4SLinus Torvalds 
llc_conn_ac_set_vr_0(struct sock * sk,struct sk_buff * skb)12911da177e4SLinus Torvalds int llc_conn_ac_set_vr_0(struct sock *sk, struct sk_buff *skb)
12921da177e4SLinus Torvalds {
12931da177e4SLinus Torvalds 	llc_sk(sk)->vR = 0;
12941da177e4SLinus Torvalds 	return 0;
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds 
llc_conn_ac_inc_vr_by_1(struct sock * sk,struct sk_buff * skb)12971da177e4SLinus Torvalds int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct sk_buff *skb)
12981da177e4SLinus Torvalds {
12991da177e4SLinus Torvalds 	llc_sk(sk)->vR = PDU_GET_NEXT_Vr(llc_sk(sk)->vR);
13001da177e4SLinus Torvalds 	return 0;
13011da177e4SLinus Torvalds }
13021da177e4SLinus Torvalds 
llc_conn_ac_set_vs_0(struct sock * sk,struct sk_buff * skb)13031da177e4SLinus Torvalds int llc_conn_ac_set_vs_0(struct sock *sk, struct sk_buff *skb)
13041da177e4SLinus Torvalds {
13051da177e4SLinus Torvalds 	llc_sk(sk)->vS = 0;
13061da177e4SLinus Torvalds 	return 0;
13071da177e4SLinus Torvalds }
13081da177e4SLinus Torvalds 
llc_conn_ac_set_vs_nr(struct sock * sk,struct sk_buff * skb)13091da177e4SLinus Torvalds int llc_conn_ac_set_vs_nr(struct sock *sk, struct sk_buff *skb)
13101da177e4SLinus Torvalds {
13111da177e4SLinus Torvalds 	llc_sk(sk)->vS = llc_sk(sk)->last_nr;
13121da177e4SLinus Torvalds 	return 0;
13131da177e4SLinus Torvalds }
13141da177e4SLinus Torvalds 
llc_conn_ac_inc_vs_by_1(struct sock * sk,struct sk_buff * skb)13152928c19eSArnaldo Carvalho de Melo static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb)
13161da177e4SLinus Torvalds {
131759c6196eSJochen Friedrich 	llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO;
13181da177e4SLinus Torvalds 	return 0;
13191da177e4SLinus Torvalds }
13201da177e4SLinus Torvalds 
llc_conn_tmr_common_cb(struct sock * sk,u8 type)1321fc8bcaa0SKees Cook static void llc_conn_tmr_common_cb(struct sock *sk, u8 type)
13221da177e4SLinus Torvalds {
13231da177e4SLinus Torvalds 	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
13241da177e4SLinus Torvalds 
13251da177e4SLinus Torvalds 	bh_lock_sock(sk);
13261da177e4SLinus Torvalds 	if (skb) {
13271da177e4SLinus Torvalds 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
13281da177e4SLinus Torvalds 
132904e4223fSArnaldo Carvalho de Melo 		skb_set_owner_r(skb, sk);
1330e0dd5519SArnaldo Carvalho de Melo 		ev->type = type;
13311da177e4SLinus Torvalds 		llc_process_tmr_ev(sk, skb);
13321da177e4SLinus Torvalds 	}
13331da177e4SLinus Torvalds 	bh_unlock_sock(sk);
13341da177e4SLinus Torvalds }
13351da177e4SLinus Torvalds 
llc_conn_pf_cycle_tmr_cb(struct timer_list * t)1336fc8bcaa0SKees Cook void llc_conn_pf_cycle_tmr_cb(struct timer_list *t)
1337e0dd5519SArnaldo Carvalho de Melo {
1338fc8bcaa0SKees Cook 	struct llc_sock *llc = from_timer(llc, t, pf_cycle_timer.timer);
1339fc8bcaa0SKees Cook 
1340fc8bcaa0SKees Cook 	llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_P_TMR);
1341e0dd5519SArnaldo Carvalho de Melo }
1342e0dd5519SArnaldo Carvalho de Melo 
llc_conn_busy_tmr_cb(struct timer_list * t)1343fc8bcaa0SKees Cook void llc_conn_busy_tmr_cb(struct timer_list *t)
13441da177e4SLinus Torvalds {
1345fc8bcaa0SKees Cook 	struct llc_sock *llc = from_timer(llc, t, busy_state_timer.timer);
1346fc8bcaa0SKees Cook 
1347fc8bcaa0SKees Cook 	llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_BUSY_TMR);
13481da177e4SLinus Torvalds }
13491da177e4SLinus Torvalds 
llc_conn_ack_tmr_cb(struct timer_list * t)1350fc8bcaa0SKees Cook void llc_conn_ack_tmr_cb(struct timer_list *t)
13511da177e4SLinus Torvalds {
1352fc8bcaa0SKees Cook 	struct llc_sock *llc = from_timer(llc, t, ack_timer.timer);
1353fc8bcaa0SKees Cook 
1354fc8bcaa0SKees Cook 	llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_ACK_TMR);
13551da177e4SLinus Torvalds }
13561da177e4SLinus Torvalds 
llc_conn_rej_tmr_cb(struct timer_list * t)1357fc8bcaa0SKees Cook void llc_conn_rej_tmr_cb(struct timer_list *t)
13581da177e4SLinus Torvalds {
1359fc8bcaa0SKees Cook 	struct llc_sock *llc = from_timer(llc, t, rej_sent_timer.timer);
1360fc8bcaa0SKees Cook 
1361fc8bcaa0SKees Cook 	llc_conn_tmr_common_cb(&llc->sk, LLC_CONN_EV_TYPE_REJ_TMR);
13621da177e4SLinus Torvalds }
13631da177e4SLinus Torvalds 
llc_conn_ac_rst_vs(struct sock * sk,struct sk_buff * skb)13641da177e4SLinus Torvalds int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
13651da177e4SLinus Torvalds {
13661da177e4SLinus Torvalds 	llc_sk(sk)->X = llc_sk(sk)->vS;
13671da177e4SLinus Torvalds 	llc_conn_ac_set_vs_nr(sk, skb);
13681da177e4SLinus Torvalds 	return 0;
13691da177e4SLinus Torvalds }
13701da177e4SLinus Torvalds 
llc_conn_ac_upd_vs(struct sock * sk,struct sk_buff * skb)13711da177e4SLinus Torvalds int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb)
13721da177e4SLinus Torvalds {
13731da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
13741da177e4SLinus Torvalds 	u8 nr = PDU_SUPV_GET_Nr(pdu);
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	if (llc_circular_between(llc_sk(sk)->vS, nr, llc_sk(sk)->X))
13771da177e4SLinus Torvalds 		llc_conn_ac_set_vs_nr(sk, skb);
13781da177e4SLinus Torvalds 	return 0;
13791da177e4SLinus Torvalds }
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds /*
13821da177e4SLinus Torvalds  * Non-standard actions; these not contained in IEEE specification; for
13831da177e4SLinus Torvalds  * our own usage
13841da177e4SLinus Torvalds  */
13851da177e4SLinus Torvalds /**
13861da177e4SLinus Torvalds  *	llc_conn_disc - removes connection from SAP list and frees it
13871da177e4SLinus Torvalds  *	@sk: closed connection
13881da177e4SLinus Torvalds  *	@skb: occurred event
13891da177e4SLinus Torvalds  */
llc_conn_disc(struct sock * sk,struct sk_buff * skb)13901da177e4SLinus Torvalds int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
13911da177e4SLinus Torvalds {
13921da177e4SLinus Torvalds 	/* FIXME: this thing seems to want to die */
13931da177e4SLinus Torvalds 	return 0;
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds /**
13971da177e4SLinus Torvalds  *	llc_conn_reset - resets connection
13981da177e4SLinus Torvalds  *	@sk : reseting connection.
13991da177e4SLinus Torvalds  *	@skb: occurred event.
14001da177e4SLinus Torvalds  *
14011da177e4SLinus Torvalds  *	Stop all timers, empty all queues and reset all flags.
14021da177e4SLinus Torvalds  */
llc_conn_reset(struct sock * sk,struct sk_buff * skb)14031da177e4SLinus Torvalds int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
14041da177e4SLinus Torvalds {
14051da177e4SLinus Torvalds 	llc_sk_reset(sk);
14061da177e4SLinus Torvalds 	return 0;
14071da177e4SLinus Torvalds }
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds /**
14101da177e4SLinus Torvalds  *	llc_circular_between - designates that b is between a and c or not
14111da177e4SLinus Torvalds  *	@a: lower bound
14121da177e4SLinus Torvalds  *	@b: element to see if is between a and b
14131da177e4SLinus Torvalds  *	@c: upper bound
14141da177e4SLinus Torvalds  *
14151da177e4SLinus Torvalds  *	This function designates that b is between a and c or not (for example,
14161da177e4SLinus Torvalds  *	0 is between 127 and 1). Returns 1 if b is between a and c, 0
14171da177e4SLinus Torvalds  *	otherwise.
14181da177e4SLinus Torvalds  */
llc_circular_between(u8 a,u8 b,u8 c)14191da177e4SLinus Torvalds u8 llc_circular_between(u8 a, u8 b, u8 c)
14201da177e4SLinus Torvalds {
14211da177e4SLinus Torvalds 	b = b - a;
14221da177e4SLinus Torvalds 	c = c - a;
14231da177e4SLinus Torvalds 	return b <= c;
14241da177e4SLinus Torvalds }
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds /**
14271da177e4SLinus Torvalds  *	llc_process_tmr_ev - timer backend
14281da177e4SLinus Torvalds  *	@sk: active connection
14291da177e4SLinus Torvalds  *	@skb: occurred event
14301da177e4SLinus Torvalds  *
14311da177e4SLinus Torvalds  *	This function is called from timer callback functions. When connection
14321da177e4SLinus Torvalds  *	is busy (during sending a data frame) timer expiration event must be
14331da177e4SLinus Torvalds  *	queued. Otherwise this event can be sent to connection state machine.
14341da177e4SLinus Torvalds  *	Queued events will process by llc_backlog_rcv function after sending
14351da177e4SLinus Torvalds  *	data frame.
14361da177e4SLinus Torvalds  */
llc_process_tmr_ev(struct sock * sk,struct sk_buff * skb)14371da177e4SLinus Torvalds static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
14381da177e4SLinus Torvalds {
14391da177e4SLinus Torvalds 	if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
14401da177e4SLinus Torvalds 		printk(KERN_WARNING "%s: timer called on closed connection\n",
14410dc47877SHarvey Harrison 		       __func__);
14421da177e4SLinus Torvalds 		kfree_skb(skb);
14431da177e4SLinus Torvalds 	} else {
14441da177e4SLinus Torvalds 		if (!sock_owned_by_user(sk))
14451da177e4SLinus Torvalds 			llc_conn_state_process(sk, skb);
14461da177e4SLinus Torvalds 		else {
14471da177e4SLinus Torvalds 			llc_set_backlog_type(skb, LLC_EVENT);
1448a3a858ffSZhu Yi 			__sk_add_backlog(sk, skb);
14491da177e4SLinus Torvalds 		}
14501da177e4SLinus Torvalds 	}
14511da177e4SLinus Torvalds }
1452