xref: /openbmc/linux/net/llc/llc_pdu.c (revision 72e6afe6)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * llc_pdu.c - access to PDU internals
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 1997 by Procom Technology, Inc.
51da177e4SLinus Torvalds  *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This program can be redistributed or modified under the terms of the
81da177e4SLinus Torvalds  * GNU General Public License as published by the Free Software Foundation.
91da177e4SLinus Torvalds  * This program is distributed without any warranty or implied warranty
101da177e4SLinus Torvalds  * of merchantability or fitness for a particular purpose.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * See the GNU General Public License for more details.
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/netdevice.h>
161da177e4SLinus Torvalds #include <net/llc_pdu.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
191da177e4SLinus Torvalds static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu);
201da177e4SLinus Torvalds 
llc_pdu_set_cmd_rsp(struct sk_buff * skb,u8 pdu_type)211da177e4SLinus Torvalds void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type)
221da177e4SLinus Torvalds {
231da177e4SLinus Torvalds 	llc_pdu_un_hdr(skb)->ssap |= pdu_type;
241da177e4SLinus Torvalds }
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds /**
27*72e6afe6SYang Yingliang  *	llc_pdu_set_pf_bit - sets poll/final bit in LLC header
2874c950c9SAndrew Lunn  *	@skb: Frame to set bit in
291da177e4SLinus Torvalds  *	@bit_value: poll/final bit (0 or 1).
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  *	This function sets poll/final bit in LLC header (based on type of PDU).
321da177e4SLinus Torvalds  *	in I or S pdus, p/f bit is right bit of fourth byte in header. in U
331da177e4SLinus Torvalds  *	pdus p/f bit is fifth bit of third byte.
341da177e4SLinus Torvalds  */
llc_pdu_set_pf_bit(struct sk_buff * skb,u8 bit_value)351da177e4SLinus Torvalds void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds 	u8 pdu_type;
381da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu;
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 	llc_pdu_decode_pdu_type(skb, &pdu_type);
411da177e4SLinus Torvalds 	pdu = llc_pdu_sn_hdr(skb);
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	switch (pdu_type) {
441da177e4SLinus Torvalds 	case LLC_PDU_TYPE_I:
451da177e4SLinus Torvalds 	case LLC_PDU_TYPE_S:
461da177e4SLinus Torvalds 		pdu->ctrl_2 = (pdu->ctrl_2 & 0xFE) | bit_value;
471da177e4SLinus Torvalds 		break;
481da177e4SLinus Torvalds 	case LLC_PDU_TYPE_U:
491da177e4SLinus Torvalds 		pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4);
501da177e4SLinus Torvalds 		break;
511da177e4SLinus Torvalds 	}
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds /**
551da177e4SLinus Torvalds  *	llc_pdu_decode_pf_bit - extracs poll/final bit from LLC header
561da177e4SLinus Torvalds  *	@skb: input skb that p/f bit must be extracted from it
571da177e4SLinus Torvalds  *	@pf_bit: poll/final bit (0 or 1)
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  *	This function extracts poll/final bit from LLC header (based on type of
601da177e4SLinus Torvalds  *	PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In
611da177e4SLinus Torvalds  *	U pdus p/f bit is fifth bit of third byte.
621da177e4SLinus Torvalds  */
llc_pdu_decode_pf_bit(struct sk_buff * skb,u8 * pf_bit)631da177e4SLinus Torvalds void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	u8 pdu_type;
661da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	llc_pdu_decode_pdu_type(skb, &pdu_type);
691da177e4SLinus Torvalds 	pdu = llc_pdu_sn_hdr(skb);
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	switch (pdu_type) {
721da177e4SLinus Torvalds 	case LLC_PDU_TYPE_I:
731da177e4SLinus Torvalds 	case LLC_PDU_TYPE_S:
741da177e4SLinus Torvalds 		*pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK;
751da177e4SLinus Torvalds 		break;
761da177e4SLinus Torvalds 	case LLC_PDU_TYPE_U:
771da177e4SLinus Torvalds 		*pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
781da177e4SLinus Torvalds 		break;
791da177e4SLinus Torvalds 	}
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds /**
831da177e4SLinus Torvalds  *	llc_pdu_init_as_disc_cmd - Builds DISC PDU
841da177e4SLinus Torvalds  *	@skb: Address of the skb to build
851da177e4SLinus Torvalds  *	@p_bit: The P bit to set in the PDU
861da177e4SLinus Torvalds  *
871da177e4SLinus Torvalds  *	Builds a pdu frame as a DISC command.
881da177e4SLinus Torvalds  */
llc_pdu_init_as_disc_cmd(struct sk_buff * skb,u8 p_bit)891da177e4SLinus Torvalds void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
941da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC;
951da177e4SLinus Torvalds 	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /**
991da177e4SLinus Torvalds  *	llc_pdu_init_as_i_cmd - builds I pdu
1001da177e4SLinus Torvalds  *	@skb: Address of the skb to build
1011da177e4SLinus Torvalds  *	@p_bit: The P bit to set in the PDU
1021da177e4SLinus Torvalds  *	@ns: The sequence number of the data PDU
1031da177e4SLinus Torvalds  *	@nr: The seq. number of the expected I PDU from the remote
1041da177e4SLinus Torvalds  *
1051da177e4SLinus Torvalds  *	Builds a pdu frame as an I command.
1061da177e4SLinus Torvalds  */
llc_pdu_init_as_i_cmd(struct sk_buff * skb,u8 p_bit,u8 ns,u8 nr)1071da177e4SLinus Torvalds void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
1081da177e4SLinus Torvalds {
1091da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_I;
1121da177e4SLinus Torvalds 	pdu->ctrl_2  = 0;
1131da177e4SLinus Torvalds 	pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */
1141da177e4SLinus Torvalds 	pdu->ctrl_1 |= (ns << 1) & 0xFE;   /* set N(S) in bits 2..8 */
1151da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE;   /* set N(R) in bits 10..16 */
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds /**
1191da177e4SLinus Torvalds  *	llc_pdu_init_as_rej_cmd - builds REJ PDU
1201da177e4SLinus Torvalds  *	@skb: Address of the skb to build
1211da177e4SLinus Torvalds  *	@p_bit: The P bit to set in the PDU
1221da177e4SLinus Torvalds  *	@nr: The seq. number of the expected I PDU from the remote
1231da177e4SLinus Torvalds  *
1241da177e4SLinus Torvalds  *	Builds a pdu frame as a REJ command.
1251da177e4SLinus Torvalds  */
llc_pdu_init_as_rej_cmd(struct sk_buff * skb,u8 p_bit,u8 nr)1261da177e4SLinus Torvalds void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
1311da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ;
1321da177e4SLinus Torvalds 	pdu->ctrl_2  = 0;
1331da177e4SLinus Torvalds 	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
1341da177e4SLinus Torvalds 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
1351da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds /**
1391da177e4SLinus Torvalds  *	llc_pdu_init_as_rnr_cmd - builds RNR pdu
1401da177e4SLinus Torvalds  *	@skb: Address of the skb to build
1411da177e4SLinus Torvalds  *	@p_bit: The P bit to set in the PDU
1421da177e4SLinus Torvalds  *	@nr: The seq. number of the expected I PDU from the remote
1431da177e4SLinus Torvalds  *
1441da177e4SLinus Torvalds  *	Builds a pdu frame as an RNR command.
1451da177e4SLinus Torvalds  */
llc_pdu_init_as_rnr_cmd(struct sk_buff * skb,u8 p_bit,u8 nr)1461da177e4SLinus Torvalds void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
1471da177e4SLinus Torvalds {
1481da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
1511da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR;
1521da177e4SLinus Torvalds 	pdu->ctrl_2  = 0;
1531da177e4SLinus Torvalds 	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
1541da177e4SLinus Torvalds 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
1551da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds /**
1591da177e4SLinus Torvalds  *	llc_pdu_init_as_rr_cmd - Builds RR pdu
1601da177e4SLinus Torvalds  *	@skb: Address of the skb to build
1611da177e4SLinus Torvalds  *	@p_bit: The P bit to set in the PDU
1621da177e4SLinus Torvalds  *	@nr: The seq. number of the expected I PDU from the remote
1631da177e4SLinus Torvalds  *
1641da177e4SLinus Torvalds  *	Builds a pdu frame as an RR command.
1651da177e4SLinus Torvalds  */
llc_pdu_init_as_rr_cmd(struct sk_buff * skb,u8 p_bit,u8 nr)1661da177e4SLinus Torvalds void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
1711da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_CMD_RR;
1721da177e4SLinus Torvalds 	pdu->ctrl_2  = p_bit & LLC_S_PF_BIT_MASK;
1731da177e4SLinus Torvalds 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
1741da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds /**
1781da177e4SLinus Torvalds  *	llc_pdu_init_as_sabme_cmd - builds SABME pdu
1791da177e4SLinus Torvalds  *	@skb: Address of the skb to build
1801da177e4SLinus Torvalds  *	@p_bit: The P bit to set in the PDU
1811da177e4SLinus Torvalds  *
1821da177e4SLinus Torvalds  *	Builds a pdu frame as an SABME command.
1831da177e4SLinus Torvalds  */
llc_pdu_init_as_sabme_cmd(struct sk_buff * skb,u8 p_bit)1841da177e4SLinus Torvalds void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit)
1851da177e4SLinus Torvalds {
1861da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
1891da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME;
1901da177e4SLinus Torvalds 	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds /**
1941da177e4SLinus Torvalds  *	llc_pdu_init_as_dm_rsp - builds DM response pdu
1951da177e4SLinus Torvalds  *	@skb: Address of the skb to build
1961da177e4SLinus Torvalds  *	@f_bit: The F bit to set in the PDU
1971da177e4SLinus Torvalds  *
1981da177e4SLinus Torvalds  *	Builds a pdu frame as a DM response.
1991da177e4SLinus Torvalds  */
llc_pdu_init_as_dm_rsp(struct sk_buff * skb,u8 f_bit)2001da177e4SLinus Torvalds void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
2051da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_RSP_DM;
2061da177e4SLinus Torvalds 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /**
2101da177e4SLinus Torvalds  *	llc_pdu_init_as_frmr_rsp - builds FRMR response PDU
2111da177e4SLinus Torvalds  *	@skb: Address of the frame to build
2121da177e4SLinus Torvalds  *	@prev_pdu: The rejected PDU frame
2131da177e4SLinus Torvalds  *	@f_bit: The F bit to set in the PDU
2141da177e4SLinus Torvalds  *	@vs: tx state vari value for the data link conn at the rejecting LLC
2151da177e4SLinus Torvalds  *	@vr: rx state var value for the data link conn at the rejecting LLC
2161da177e4SLinus Torvalds  *	@vzyxw: completely described in the IEEE Std 802.2 document (Pg 55)
2171da177e4SLinus Torvalds  *
2181da177e4SLinus Torvalds  *	Builds a pdu frame as a FRMR response.
2191da177e4SLinus Torvalds  */
llc_pdu_init_as_frmr_rsp(struct sk_buff * skb,struct llc_pdu_sn * prev_pdu,u8 f_bit,u8 vs,u8 vr,u8 vzyxw)2201da177e4SLinus Torvalds void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
2211da177e4SLinus Torvalds 			      u8 f_bit, u8 vs, u8 vr, u8 vzyxw)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds 	struct llc_frmr_info *frmr_info;
2241da177e4SLinus Torvalds 	u8 prev_pf = 0;
2251da177e4SLinus Torvalds 	u8 *ctrl;
2261da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
2291da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR;
2301da177e4SLinus Torvalds 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	frmr_info = (struct llc_frmr_info *)&pdu->ctrl_2;
2331da177e4SLinus Torvalds 	ctrl = (u8 *)&prev_pdu->ctrl_1;
2341da177e4SLinus Torvalds 	FRMR_INFO_SET_REJ_CNTRL(frmr_info,ctrl);
2351da177e4SLinus Torvalds 	FRMR_INFO_SET_Vs(frmr_info, vs);
2361da177e4SLinus Torvalds 	FRMR_INFO_SET_Vr(frmr_info, vr);
2371da177e4SLinus Torvalds 	prev_pf = llc_pdu_get_pf_bit(prev_pdu);
2381da177e4SLinus Torvalds 	FRMR_INFO_SET_C_R_BIT(frmr_info, prev_pf);
2391da177e4SLinus Torvalds 	FRMR_INFO_SET_INVALID_PDU_CTRL_IND(frmr_info, vzyxw);
2401da177e4SLinus Torvalds 	FRMR_INFO_SET_INVALID_PDU_INFO_IND(frmr_info, vzyxw);
2411da177e4SLinus Torvalds 	FRMR_INFO_SET_PDU_INFO_2LONG_IND(frmr_info, vzyxw);
2421da177e4SLinus Torvalds 	FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw);
2431da177e4SLinus Torvalds 	FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw);
244f83f1768SJoonwoo Park 	skb_put(skb, sizeof(struct llc_frmr_info));
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds /**
2481da177e4SLinus Torvalds  *	llc_pdu_init_as_rr_rsp - builds RR response pdu
2491da177e4SLinus Torvalds  *	@skb: Address of the skb to build
2501da177e4SLinus Torvalds  *	@f_bit: The F bit to set in the PDU
2511da177e4SLinus Torvalds  *	@nr: The seq. number of the expected data PDU from the remote
2521da177e4SLinus Torvalds  *
2531da177e4SLinus Torvalds  *	Builds a pdu frame as an RR response.
2541da177e4SLinus Torvalds  */
llc_pdu_init_as_rr_rsp(struct sk_buff * skb,u8 f_bit,u8 nr)2551da177e4SLinus Torvalds void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
2561da177e4SLinus Torvalds {
2571da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
2601da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_RSP_RR;
2611da177e4SLinus Torvalds 	pdu->ctrl_2  = 0;
2621da177e4SLinus Torvalds 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
2631da177e4SLinus Torvalds 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
2641da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds /**
2681da177e4SLinus Torvalds  *	llc_pdu_init_as_rej_rsp - builds REJ response pdu
2691da177e4SLinus Torvalds  *	@skb: Address of the skb to build
2701da177e4SLinus Torvalds  *	@f_bit: The F bit to set in the PDU
2711da177e4SLinus Torvalds  *	@nr: The seq. number of the expected data PDU from the remote
2721da177e4SLinus Torvalds  *
2731da177e4SLinus Torvalds  *	Builds a pdu frame as a REJ response.
2741da177e4SLinus Torvalds  */
llc_pdu_init_as_rej_rsp(struct sk_buff * skb,u8 f_bit,u8 nr)2751da177e4SLinus Torvalds void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
2801da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ;
2811da177e4SLinus Torvalds 	pdu->ctrl_2  = 0;
2821da177e4SLinus Torvalds 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
2831da177e4SLinus Torvalds 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
2841da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
2851da177e4SLinus Torvalds }
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds /**
2881da177e4SLinus Torvalds  *	llc_pdu_init_as_rnr_rsp - builds RNR response pdu
2891da177e4SLinus Torvalds  *	@skb: Address of the frame to build
2901da177e4SLinus Torvalds  *	@f_bit: The F bit to set in the PDU
2911da177e4SLinus Torvalds  *	@nr: The seq. number of the expected data PDU from the remote
2921da177e4SLinus Torvalds  *
2931da177e4SLinus Torvalds  *	Builds a pdu frame as an RNR response.
2941da177e4SLinus Torvalds  */
llc_pdu_init_as_rnr_rsp(struct sk_buff * skb,u8 f_bit,u8 nr)2951da177e4SLinus Torvalds void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
2961da177e4SLinus Torvalds {
2971da177e4SLinus Torvalds 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_S;
3001da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR;
3011da177e4SLinus Torvalds 	pdu->ctrl_2  = 0;
3021da177e4SLinus Torvalds 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
3031da177e4SLinus Torvalds 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
3041da177e4SLinus Torvalds 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds /**
3081da177e4SLinus Torvalds  *	llc_pdu_init_as_ua_rsp - builds UA response pdu
3091da177e4SLinus Torvalds  *	@skb: Address of the frame to build
3101da177e4SLinus Torvalds  *	@f_bit: The F bit to set in the PDU
3111da177e4SLinus Torvalds  *
3121da177e4SLinus Torvalds  *	Builds a pdu frame as a UA response.
3131da177e4SLinus Torvalds  */
llc_pdu_init_as_ua_rsp(struct sk_buff * skb,u8 f_bit)3141da177e4SLinus Torvalds void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
3151da177e4SLinus Torvalds {
3161da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
3191da177e4SLinus Torvalds 	pdu->ctrl_1 |= LLC_2_PDU_RSP_UA;
3201da177e4SLinus Torvalds 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds /**
3241da177e4SLinus Torvalds  *	llc_pdu_decode_pdu_type - designates PDU type
3251da177e4SLinus Torvalds  *	@skb: input skb that type of it must be designated.
3261da177e4SLinus Torvalds  *	@type: type of PDU (output argument).
3271da177e4SLinus Torvalds  *
3281da177e4SLinus Torvalds  *	This function designates type of PDU (I, S or U).
3291da177e4SLinus Torvalds  */
llc_pdu_decode_pdu_type(struct sk_buff * skb,u8 * type)3301da177e4SLinus Torvalds static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
3311da177e4SLinus Torvalds {
3321da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	if (pdu->ctrl_1 & 1) {
3351da177e4SLinus Torvalds 		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
3361da177e4SLinus Torvalds 			*type = LLC_PDU_TYPE_U;
3371da177e4SLinus Torvalds 		else
3381da177e4SLinus Torvalds 			*type = LLC_PDU_TYPE_S;
3391da177e4SLinus Torvalds 	} else
3401da177e4SLinus Torvalds 		*type = LLC_PDU_TYPE_I;
3411da177e4SLinus Torvalds }
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds /**
3441da177e4SLinus Torvalds  *	llc_pdu_get_pf_bit - extracts p/f bit of input PDU
3451da177e4SLinus Torvalds  *	@pdu: pointer to LLC header.
3461da177e4SLinus Torvalds  *
3471da177e4SLinus Torvalds  *	This function extracts p/f bit of input PDU. at first examines type of
3481da177e4SLinus Torvalds  *	PDU and then extracts p/f bit. Returns the p/f bit.
3491da177e4SLinus Torvalds  */
llc_pdu_get_pf_bit(struct llc_pdu_sn * pdu)3501da177e4SLinus Torvalds static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu)
3511da177e4SLinus Torvalds {
3521da177e4SLinus Torvalds 	u8 pdu_type;
3531da177e4SLinus Torvalds 	u8 pf_bit = 0;
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	if (pdu->ctrl_1 & 1) {
3561da177e4SLinus Torvalds 		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
3571da177e4SLinus Torvalds 			pdu_type = LLC_PDU_TYPE_U;
3581da177e4SLinus Torvalds 		else
3591da177e4SLinus Torvalds 			pdu_type = LLC_PDU_TYPE_S;
3601da177e4SLinus Torvalds 	} else
3611da177e4SLinus Torvalds 		pdu_type = LLC_PDU_TYPE_I;
3621da177e4SLinus Torvalds 	switch (pdu_type) {
3631da177e4SLinus Torvalds 	case LLC_PDU_TYPE_I:
3641da177e4SLinus Torvalds 	case LLC_PDU_TYPE_S:
3651da177e4SLinus Torvalds 		pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK;
3661da177e4SLinus Torvalds 		break;
3671da177e4SLinus Torvalds 	case LLC_PDU_TYPE_U:
3681da177e4SLinus Torvalds 		pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
3691da177e4SLinus Torvalds 		break;
3701da177e4SLinus Torvalds 	}
3711da177e4SLinus Torvalds 	return pf_bit;
3721da177e4SLinus Torvalds }
373