| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * llc_pdu.c - access to PDU internals | 
 | 3 |  * | 
 | 4 |  * Copyright (c) 1997 by Procom Technology, Inc. | 
 | 5 |  *		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 
 | 6 |  * | 
 | 7 |  * This program can be redistributed or modified under the terms of the | 
 | 8 |  * GNU General Public License as published by the Free Software Foundation. | 
 | 9 |  * This program is distributed without any warranty or implied warranty | 
 | 10 |  * of merchantability or fitness for a particular purpose. | 
 | 11 |  * | 
 | 12 |  * See the GNU General Public License for more details. | 
 | 13 |  */ | 
 | 14 |  | 
 | 15 | #include <linux/netdevice.h> | 
 | 16 | #include <net/llc_pdu.h> | 
 | 17 |  | 
 | 18 | static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); | 
 | 19 | static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu); | 
 | 20 |  | 
 | 21 | void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type) | 
 | 22 | { | 
 | 23 | 	llc_pdu_un_hdr(skb)->ssap |= pdu_type; | 
 | 24 | } | 
 | 25 |  | 
 | 26 | /** | 
 | 27 |  *	pdu_set_pf_bit - sets poll/final bit in LLC header | 
 | 28 |  *	@pdu_frame: input frame that p/f bit must be set into it. | 
 | 29 |  *	@bit_value: poll/final bit (0 or 1). | 
 | 30 |  * | 
 | 31 |  *	This function sets poll/final bit in LLC header (based on type of PDU). | 
 | 32 |  *	in I or S pdus, p/f bit is right bit of fourth byte in header. in U | 
 | 33 |  *	pdus p/f bit is fifth bit of third byte. | 
 | 34 |  */ | 
 | 35 | void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) | 
 | 36 | { | 
 | 37 | 	u8 pdu_type; | 
 | 38 | 	struct llc_pdu_sn *pdu; | 
 | 39 |  | 
 | 40 | 	llc_pdu_decode_pdu_type(skb, &pdu_type); | 
 | 41 | 	pdu = llc_pdu_sn_hdr(skb); | 
 | 42 |  | 
 | 43 | 	switch (pdu_type) { | 
 | 44 | 	case LLC_PDU_TYPE_I: | 
 | 45 | 	case LLC_PDU_TYPE_S: | 
 | 46 | 		pdu->ctrl_2 = (pdu->ctrl_2 & 0xFE) | bit_value; | 
 | 47 | 		break; | 
 | 48 | 	case LLC_PDU_TYPE_U: | 
 | 49 | 		pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4); | 
 | 50 | 		break; | 
 | 51 | 	} | 
 | 52 | } | 
 | 53 |  | 
 | 54 | /** | 
 | 55 |  *	llc_pdu_decode_pf_bit - extracs poll/final bit from LLC header | 
 | 56 |  *	@skb: input skb that p/f bit must be extracted from it | 
 | 57 |  *	@pf_bit: poll/final bit (0 or 1) | 
 | 58 |  * | 
 | 59 |  *	This function extracts poll/final bit from LLC header (based on type of | 
 | 60 |  *	PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In | 
 | 61 |  *	U pdus p/f bit is fifth bit of third byte. | 
 | 62 |  */ | 
 | 63 | void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) | 
 | 64 | { | 
 | 65 | 	u8 pdu_type; | 
 | 66 | 	struct llc_pdu_sn *pdu; | 
 | 67 |  | 
 | 68 | 	llc_pdu_decode_pdu_type(skb, &pdu_type); | 
 | 69 | 	pdu = llc_pdu_sn_hdr(skb); | 
 | 70 |  | 
 | 71 | 	switch (pdu_type) { | 
 | 72 | 	case LLC_PDU_TYPE_I: | 
 | 73 | 	case LLC_PDU_TYPE_S: | 
 | 74 | 		*pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK; | 
 | 75 | 		break; | 
 | 76 | 	case LLC_PDU_TYPE_U: | 
 | 77 | 		*pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; | 
 | 78 | 		break; | 
 | 79 | 	} | 
 | 80 | } | 
 | 81 |  | 
 | 82 | /** | 
 | 83 |  *	llc_pdu_init_as_disc_cmd - Builds DISC PDU | 
 | 84 |  *	@skb: Address of the skb to build | 
 | 85 |  *	@p_bit: The P bit to set in the PDU | 
 | 86 |  * | 
 | 87 |  *	Builds a pdu frame as a DISC command. | 
 | 88 |  */ | 
 | 89 | void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) | 
 | 90 | { | 
 | 91 | 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); | 
 | 92 |  | 
 | 93 | 	pdu->ctrl_1  = LLC_PDU_TYPE_U; | 
 | 94 | 	pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC; | 
 | 95 | 	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; | 
 | 96 | } | 
 | 97 |  | 
 | 98 | /** | 
 | 99 |  *	llc_pdu_init_as_i_cmd - builds I pdu | 
 | 100 |  *	@skb: Address of the skb to build | 
 | 101 |  *	@p_bit: The P bit to set in the PDU | 
 | 102 |  *	@ns: The sequence number of the data PDU | 
 | 103 |  *	@nr: The seq. number of the expected I PDU from the remote | 
 | 104 |  * | 
 | 105 |  *	Builds a pdu frame as an I command. | 
 | 106 |  */ | 
 | 107 | void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) | 
 | 108 | { | 
 | 109 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 110 |  | 
 | 111 | 	pdu->ctrl_1  = LLC_PDU_TYPE_I; | 
 | 112 | 	pdu->ctrl_2  = 0; | 
 | 113 | 	pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */ | 
 | 114 | 	pdu->ctrl_1 |= (ns << 1) & 0xFE;   /* set N(S) in bits 2..8 */ | 
 | 115 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE;   /* set N(R) in bits 10..16 */ | 
 | 116 | } | 
 | 117 |  | 
 | 118 | /** | 
 | 119 |  *	llc_pdu_init_as_rej_cmd - builds REJ PDU | 
 | 120 |  *	@skb: Address of the skb to build | 
 | 121 |  *	@p_bit: The P bit to set in the PDU | 
 | 122 |  *	@nr: The seq. number of the expected I PDU from the remote | 
 | 123 |  * | 
 | 124 |  *	Builds a pdu frame as a REJ command. | 
 | 125 |  */ | 
 | 126 | void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) | 
 | 127 | { | 
 | 128 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 129 |  | 
 | 130 | 	pdu->ctrl_1  = LLC_PDU_TYPE_S; | 
 | 131 | 	pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ; | 
 | 132 | 	pdu->ctrl_2  = 0; | 
 | 133 | 	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; | 
 | 134 | 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ | 
 | 135 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ | 
 | 136 | } | 
 | 137 |  | 
 | 138 | /** | 
 | 139 |  *	llc_pdu_init_as_rnr_cmd - builds RNR pdu | 
 | 140 |  *	@skb: Address of the skb to build | 
 | 141 |  *	@p_bit: The P bit to set in the PDU | 
 | 142 |  *	@nr: The seq. number of the expected I PDU from the remote | 
 | 143 |  * | 
 | 144 |  *	Builds a pdu frame as an RNR command. | 
 | 145 |  */ | 
 | 146 | void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) | 
 | 147 | { | 
 | 148 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 149 |  | 
 | 150 | 	pdu->ctrl_1  = LLC_PDU_TYPE_S; | 
 | 151 | 	pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR; | 
 | 152 | 	pdu->ctrl_2  = 0; | 
 | 153 | 	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; | 
 | 154 | 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ | 
 | 155 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ | 
 | 156 | } | 
 | 157 |  | 
 | 158 | /** | 
 | 159 |  *	llc_pdu_init_as_rr_cmd - Builds RR pdu | 
 | 160 |  *	@skb: Address of the skb to build | 
 | 161 |  *	@p_bit: The P bit to set in the PDU | 
 | 162 |  *	@nr: The seq. number of the expected I PDU from the remote | 
 | 163 |  * | 
 | 164 |  *	Builds a pdu frame as an RR command. | 
 | 165 |  */ | 
 | 166 | void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) | 
 | 167 | { | 
 | 168 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 169 |  | 
 | 170 | 	pdu->ctrl_1  = LLC_PDU_TYPE_S; | 
 | 171 | 	pdu->ctrl_1 |= LLC_2_PDU_CMD_RR; | 
 | 172 | 	pdu->ctrl_2  = p_bit & LLC_S_PF_BIT_MASK; | 
 | 173 | 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ | 
 | 174 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ | 
 | 175 | } | 
 | 176 |  | 
 | 177 | /** | 
 | 178 |  *	llc_pdu_init_as_sabme_cmd - builds SABME pdu | 
 | 179 |  *	@skb: Address of the skb to build | 
 | 180 |  *	@p_bit: The P bit to set in the PDU | 
 | 181 |  * | 
 | 182 |  *	Builds a pdu frame as an SABME command. | 
 | 183 |  */ | 
 | 184 | void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit) | 
 | 185 | { | 
 | 186 | 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); | 
 | 187 |  | 
 | 188 | 	pdu->ctrl_1  = LLC_PDU_TYPE_U; | 
 | 189 | 	pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME; | 
 | 190 | 	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; | 
 | 191 | } | 
 | 192 |  | 
 | 193 | /** | 
 | 194 |  *	llc_pdu_init_as_dm_rsp - builds DM response pdu | 
 | 195 |  *	@skb: Address of the skb to build | 
 | 196 |  *	@f_bit: The F bit to set in the PDU | 
 | 197 |  * | 
 | 198 |  *	Builds a pdu frame as a DM response. | 
 | 199 |  */ | 
 | 200 | void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit) | 
 | 201 | { | 
 | 202 | 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); | 
 | 203 |  | 
 | 204 | 	pdu->ctrl_1  = LLC_PDU_TYPE_U; | 
 | 205 | 	pdu->ctrl_1 |= LLC_2_PDU_RSP_DM; | 
 | 206 | 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; | 
 | 207 | } | 
 | 208 |  | 
 | 209 | /** | 
 | 210 |  *	llc_pdu_init_as_frmr_rsp - builds FRMR response PDU | 
 | 211 |  *	@skb: Address of the frame to build | 
 | 212 |  *	@prev_pdu: The rejected PDU frame | 
 | 213 |  *	@f_bit: The F bit to set in the PDU | 
 | 214 |  *	@vs: tx state vari value for the data link conn at the rejecting LLC | 
 | 215 |  *	@vr: rx state var value for the data link conn at the rejecting LLC | 
 | 216 |  *	@vzyxw: completely described in the IEEE Std 802.2 document (Pg 55) | 
 | 217 |  * | 
 | 218 |  *	Builds a pdu frame as a FRMR response. | 
 | 219 |  */ | 
 | 220 | void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, | 
 | 221 | 			      u8 f_bit, u8 vs, u8 vr, u8 vzyxw) | 
 | 222 | { | 
 | 223 | 	struct llc_frmr_info *frmr_info; | 
 | 224 | 	u8 prev_pf = 0; | 
 | 225 | 	u8 *ctrl; | 
 | 226 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 227 |  | 
 | 228 | 	pdu->ctrl_1  = LLC_PDU_TYPE_U; | 
 | 229 | 	pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR; | 
 | 230 | 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; | 
 | 231 |  | 
 | 232 | 	frmr_info = (struct llc_frmr_info *)&pdu->ctrl_2; | 
 | 233 | 	ctrl = (u8 *)&prev_pdu->ctrl_1; | 
 | 234 | 	FRMR_INFO_SET_REJ_CNTRL(frmr_info,ctrl); | 
 | 235 | 	FRMR_INFO_SET_Vs(frmr_info, vs); | 
 | 236 | 	FRMR_INFO_SET_Vr(frmr_info, vr); | 
 | 237 | 	prev_pf = llc_pdu_get_pf_bit(prev_pdu); | 
 | 238 | 	FRMR_INFO_SET_C_R_BIT(frmr_info, prev_pf); | 
 | 239 | 	FRMR_INFO_SET_INVALID_PDU_CTRL_IND(frmr_info, vzyxw); | 
 | 240 | 	FRMR_INFO_SET_INVALID_PDU_INFO_IND(frmr_info, vzyxw); | 
 | 241 | 	FRMR_INFO_SET_PDU_INFO_2LONG_IND(frmr_info, vzyxw); | 
 | 242 | 	FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw); | 
 | 243 | 	FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw); | 
 | 244 | 	skb_put(skb, sizeof(struct llc_frmr_info)); | 
 | 245 | } | 
 | 246 |  | 
 | 247 | /** | 
 | 248 |  *	llc_pdu_init_as_rr_rsp - builds RR response pdu | 
 | 249 |  *	@skb: Address of the skb to build | 
 | 250 |  *	@f_bit: The F bit to set in the PDU | 
 | 251 |  *	@nr: The seq. number of the expected data PDU from the remote | 
 | 252 |  * | 
 | 253 |  *	Builds a pdu frame as an RR response. | 
 | 254 |  */ | 
 | 255 | void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) | 
 | 256 | { | 
 | 257 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 258 |  | 
 | 259 | 	pdu->ctrl_1  = LLC_PDU_TYPE_S; | 
 | 260 | 	pdu->ctrl_1 |= LLC_2_PDU_RSP_RR; | 
 | 261 | 	pdu->ctrl_2  = 0; | 
 | 262 | 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; | 
 | 263 | 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ | 
 | 264 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */ | 
 | 265 | } | 
 | 266 |  | 
 | 267 | /** | 
 | 268 |  *	llc_pdu_init_as_rej_rsp - builds REJ response pdu | 
 | 269 |  *	@skb: Address of the skb to build | 
 | 270 |  *	@f_bit: The F bit to set in the PDU | 
 | 271 |  *	@nr: The seq. number of the expected data PDU from the remote | 
 | 272 |  * | 
 | 273 |  *	Builds a pdu frame as a REJ response. | 
 | 274 |  */ | 
 | 275 | void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) | 
 | 276 | { | 
 | 277 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 278 |  | 
 | 279 | 	pdu->ctrl_1  = LLC_PDU_TYPE_S; | 
 | 280 | 	pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ; | 
 | 281 | 	pdu->ctrl_2  = 0; | 
 | 282 | 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; | 
 | 283 | 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ | 
 | 284 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */ | 
 | 285 | } | 
 | 286 |  | 
 | 287 | /** | 
 | 288 |  *	llc_pdu_init_as_rnr_rsp - builds RNR response pdu | 
 | 289 |  *	@skb: Address of the frame to build | 
 | 290 |  *	@f_bit: The F bit to set in the PDU | 
 | 291 |  *	@nr: The seq. number of the expected data PDU from the remote | 
 | 292 |  * | 
 | 293 |  *	Builds a pdu frame as an RNR response. | 
 | 294 |  */ | 
 | 295 | void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) | 
 | 296 | { | 
 | 297 | 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); | 
 | 298 |  | 
 | 299 | 	pdu->ctrl_1  = LLC_PDU_TYPE_S; | 
 | 300 | 	pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR; | 
 | 301 | 	pdu->ctrl_2  = 0; | 
 | 302 | 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; | 
 | 303 | 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */ | 
 | 304 | 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */ | 
 | 305 | } | 
 | 306 |  | 
 | 307 | /** | 
 | 308 |  *	llc_pdu_init_as_ua_rsp - builds UA response pdu | 
 | 309 |  *	@skb: Address of the frame to build | 
 | 310 |  *	@f_bit: The F bit to set in the PDU | 
 | 311 |  * | 
 | 312 |  *	Builds a pdu frame as a UA response. | 
 | 313 |  */ | 
 | 314 | void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) | 
 | 315 | { | 
 | 316 | 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); | 
 | 317 |  | 
 | 318 | 	pdu->ctrl_1  = LLC_PDU_TYPE_U; | 
 | 319 | 	pdu->ctrl_1 |= LLC_2_PDU_RSP_UA; | 
 | 320 | 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; | 
 | 321 | } | 
 | 322 |  | 
 | 323 | /** | 
 | 324 |  *	llc_pdu_decode_pdu_type - designates PDU type | 
 | 325 |  *	@skb: input skb that type of it must be designated. | 
 | 326 |  *	@type: type of PDU (output argument). | 
 | 327 |  * | 
 | 328 |  *	This function designates type of PDU (I, S or U). | 
 | 329 |  */ | 
 | 330 | static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) | 
 | 331 | { | 
 | 332 | 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); | 
 | 333 |  | 
 | 334 | 	if (pdu->ctrl_1 & 1) { | 
 | 335 | 		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U) | 
 | 336 | 			*type = LLC_PDU_TYPE_U; | 
 | 337 | 		else | 
 | 338 | 			*type = LLC_PDU_TYPE_S; | 
 | 339 | 	} else | 
 | 340 | 		*type = LLC_PDU_TYPE_I; | 
 | 341 | } | 
 | 342 |  | 
 | 343 | /** | 
 | 344 |  *	llc_pdu_get_pf_bit - extracts p/f bit of input PDU | 
 | 345 |  *	@pdu: pointer to LLC header. | 
 | 346 |  * | 
 | 347 |  *	This function extracts p/f bit of input PDU. at first examines type of | 
 | 348 |  *	PDU and then extracts p/f bit. Returns the p/f bit. | 
 | 349 |  */ | 
 | 350 | static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu) | 
 | 351 | { | 
 | 352 | 	u8 pdu_type; | 
 | 353 | 	u8 pf_bit = 0; | 
 | 354 |  | 
 | 355 | 	if (pdu->ctrl_1 & 1) { | 
 | 356 | 		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U) | 
 | 357 | 			pdu_type = LLC_PDU_TYPE_U; | 
 | 358 | 		else | 
 | 359 | 			pdu_type = LLC_PDU_TYPE_S; | 
 | 360 | 	} else | 
 | 361 | 		pdu_type = LLC_PDU_TYPE_I; | 
 | 362 | 	switch (pdu_type) { | 
 | 363 | 	case LLC_PDU_TYPE_I: | 
 | 364 | 	case LLC_PDU_TYPE_S: | 
 | 365 | 		pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK; | 
 | 366 | 		break; | 
 | 367 | 	case LLC_PDU_TYPE_U: | 
 | 368 | 		pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; | 
 | 369 | 		break; | 
 | 370 | 	} | 
 | 371 | 	return pf_bit; | 
 | 372 | } |