Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * llc_pdu.c - access to PDU internals
0003  *
0004  * Copyright (c) 1997 by Procom Technology, Inc.
0005  *       2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
0006  *
0007  * This program can be redistributed or modified under the terms of the
0008  * GNU General Public License as published by the Free Software Foundation.
0009  * This program is distributed without any warranty or implied warranty
0010  * of merchantability or fitness for a particular purpose.
0011  *
0012  * See the GNU General Public License for more details.
0013  */
0014 
0015 #include <linux/netdevice.h>
0016 #include <net/llc_pdu.h>
0017 
0018 static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
0019 static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu);
0020 
0021 void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type)
0022 {
0023     llc_pdu_un_hdr(skb)->ssap |= pdu_type;
0024 }
0025 
0026 /**
0027  *  llc_pdu_set_pf_bit - sets poll/final bit in LLC header
0028  *  @skb: Frame to set bit in
0029  *  @bit_value: poll/final bit (0 or 1).
0030  *
0031  *  This function sets poll/final bit in LLC header (based on type of PDU).
0032  *  in I or S pdus, p/f bit is right bit of fourth byte in header. in U
0033  *  pdus p/f bit is fifth bit of third byte.
0034  */
0035 void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value)
0036 {
0037     u8 pdu_type;
0038     struct llc_pdu_sn *pdu;
0039 
0040     llc_pdu_decode_pdu_type(skb, &pdu_type);
0041     pdu = llc_pdu_sn_hdr(skb);
0042 
0043     switch (pdu_type) {
0044     case LLC_PDU_TYPE_I:
0045     case LLC_PDU_TYPE_S:
0046         pdu->ctrl_2 = (pdu->ctrl_2 & 0xFE) | bit_value;
0047         break;
0048     case LLC_PDU_TYPE_U:
0049         pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4);
0050         break;
0051     }
0052 }
0053 
0054 /**
0055  *  llc_pdu_decode_pf_bit - extracs poll/final bit from LLC header
0056  *  @skb: input skb that p/f bit must be extracted from it
0057  *  @pf_bit: poll/final bit (0 or 1)
0058  *
0059  *  This function extracts poll/final bit from LLC header (based on type of
0060  *  PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In
0061  *  U pdus p/f bit is fifth bit of third byte.
0062  */
0063 void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit)
0064 {
0065     u8 pdu_type;
0066     struct llc_pdu_sn *pdu;
0067 
0068     llc_pdu_decode_pdu_type(skb, &pdu_type);
0069     pdu = llc_pdu_sn_hdr(skb);
0070 
0071     switch (pdu_type) {
0072     case LLC_PDU_TYPE_I:
0073     case LLC_PDU_TYPE_S:
0074         *pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK;
0075         break;
0076     case LLC_PDU_TYPE_U:
0077         *pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
0078         break;
0079     }
0080 }
0081 
0082 /**
0083  *  llc_pdu_init_as_disc_cmd - Builds DISC PDU
0084  *  @skb: Address of the skb to build
0085  *  @p_bit: The P bit to set in the PDU
0086  *
0087  *  Builds a pdu frame as a DISC command.
0088  */
0089 void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
0090 {
0091     struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0092 
0093     pdu->ctrl_1  = LLC_PDU_TYPE_U;
0094     pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC;
0095     pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
0096 }
0097 
0098 /**
0099  *  llc_pdu_init_as_i_cmd - builds I pdu
0100  *  @skb: Address of the skb to build
0101  *  @p_bit: The P bit to set in the PDU
0102  *  @ns: The sequence number of the data PDU
0103  *  @nr: The seq. number of the expected I PDU from the remote
0104  *
0105  *  Builds a pdu frame as an I command.
0106  */
0107 void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
0108 {
0109     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0110 
0111     pdu->ctrl_1  = LLC_PDU_TYPE_I;
0112     pdu->ctrl_2  = 0;
0113     pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */
0114     pdu->ctrl_1 |= (ns << 1) & 0xFE;   /* set N(S) in bits 2..8 */
0115     pdu->ctrl_2 |= (nr << 1) & 0xFE;   /* set N(R) in bits 10..16 */
0116 }
0117 
0118 /**
0119  *  llc_pdu_init_as_rej_cmd - builds REJ PDU
0120  *  @skb: Address of the skb to build
0121  *  @p_bit: The P bit to set in the PDU
0122  *  @nr: The seq. number of the expected I PDU from the remote
0123  *
0124  *  Builds a pdu frame as a REJ command.
0125  */
0126 void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
0127 {
0128     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0129 
0130     pdu->ctrl_1  = LLC_PDU_TYPE_S;
0131     pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ;
0132     pdu->ctrl_2  = 0;
0133     pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
0134     pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
0135     pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
0136 }
0137 
0138 /**
0139  *  llc_pdu_init_as_rnr_cmd - builds RNR pdu
0140  *  @skb: Address of the skb to build
0141  *  @p_bit: The P bit to set in the PDU
0142  *  @nr: The seq. number of the expected I PDU from the remote
0143  *
0144  *  Builds a pdu frame as an RNR command.
0145  */
0146 void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
0147 {
0148     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0149 
0150     pdu->ctrl_1  = LLC_PDU_TYPE_S;
0151     pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR;
0152     pdu->ctrl_2  = 0;
0153     pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
0154     pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
0155     pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
0156 }
0157 
0158 /**
0159  *  llc_pdu_init_as_rr_cmd - Builds RR pdu
0160  *  @skb: Address of the skb to build
0161  *  @p_bit: The P bit to set in the PDU
0162  *  @nr: The seq. number of the expected I PDU from the remote
0163  *
0164  *  Builds a pdu frame as an RR command.
0165  */
0166 void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
0167 {
0168     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0169 
0170     pdu->ctrl_1  = LLC_PDU_TYPE_S;
0171     pdu->ctrl_1 |= LLC_2_PDU_CMD_RR;
0172     pdu->ctrl_2  = p_bit & LLC_S_PF_BIT_MASK;
0173     pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
0174     pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
0175 }
0176 
0177 /**
0178  *  llc_pdu_init_as_sabme_cmd - builds SABME pdu
0179  *  @skb: Address of the skb to build
0180  *  @p_bit: The P bit to set in the PDU
0181  *
0182  *  Builds a pdu frame as an SABME command.
0183  */
0184 void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit)
0185 {
0186     struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0187 
0188     pdu->ctrl_1  = LLC_PDU_TYPE_U;
0189     pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME;
0190     pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
0191 }
0192 
0193 /**
0194  *  llc_pdu_init_as_dm_rsp - builds DM response pdu
0195  *  @skb: Address of the skb to build
0196  *  @f_bit: The F bit to set in the PDU
0197  *
0198  *  Builds a pdu frame as a DM response.
0199  */
0200 void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit)
0201 {
0202     struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0203 
0204     pdu->ctrl_1  = LLC_PDU_TYPE_U;
0205     pdu->ctrl_1 |= LLC_2_PDU_RSP_DM;
0206     pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
0207 }
0208 
0209 /**
0210  *  llc_pdu_init_as_frmr_rsp - builds FRMR response PDU
0211  *  @skb: Address of the frame to build
0212  *  @prev_pdu: The rejected PDU frame
0213  *  @f_bit: The F bit to set in the PDU
0214  *  @vs: tx state vari value for the data link conn at the rejecting LLC
0215  *  @vr: rx state var value for the data link conn at the rejecting LLC
0216  *  @vzyxw: completely described in the IEEE Std 802.2 document (Pg 55)
0217  *
0218  *  Builds a pdu frame as a FRMR response.
0219  */
0220 void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
0221                   u8 f_bit, u8 vs, u8 vr, u8 vzyxw)
0222 {
0223     struct llc_frmr_info *frmr_info;
0224     u8 prev_pf = 0;
0225     u8 *ctrl;
0226     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0227 
0228     pdu->ctrl_1  = LLC_PDU_TYPE_U;
0229     pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR;
0230     pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
0231 
0232     frmr_info = (struct llc_frmr_info *)&pdu->ctrl_2;
0233     ctrl = (u8 *)&prev_pdu->ctrl_1;
0234     FRMR_INFO_SET_REJ_CNTRL(frmr_info,ctrl);
0235     FRMR_INFO_SET_Vs(frmr_info, vs);
0236     FRMR_INFO_SET_Vr(frmr_info, vr);
0237     prev_pf = llc_pdu_get_pf_bit(prev_pdu);
0238     FRMR_INFO_SET_C_R_BIT(frmr_info, prev_pf);
0239     FRMR_INFO_SET_INVALID_PDU_CTRL_IND(frmr_info, vzyxw);
0240     FRMR_INFO_SET_INVALID_PDU_INFO_IND(frmr_info, vzyxw);
0241     FRMR_INFO_SET_PDU_INFO_2LONG_IND(frmr_info, vzyxw);
0242     FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw);
0243     FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw);
0244     skb_put(skb, sizeof(struct llc_frmr_info));
0245 }
0246 
0247 /**
0248  *  llc_pdu_init_as_rr_rsp - builds RR response pdu
0249  *  @skb: Address of the skb to build
0250  *  @f_bit: The F bit to set in the PDU
0251  *  @nr: The seq. number of the expected data PDU from the remote
0252  *
0253  *  Builds a pdu frame as an RR response.
0254  */
0255 void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
0256 {
0257     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0258 
0259     pdu->ctrl_1  = LLC_PDU_TYPE_S;
0260     pdu->ctrl_1 |= LLC_2_PDU_RSP_RR;
0261     pdu->ctrl_2  = 0;
0262     pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
0263     pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
0264     pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
0265 }
0266 
0267 /**
0268  *  llc_pdu_init_as_rej_rsp - builds REJ response pdu
0269  *  @skb: Address of the skb to build
0270  *  @f_bit: The F bit to set in the PDU
0271  *  @nr: The seq. number of the expected data PDU from the remote
0272  *
0273  *  Builds a pdu frame as a REJ response.
0274  */
0275 void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
0276 {
0277     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0278 
0279     pdu->ctrl_1  = LLC_PDU_TYPE_S;
0280     pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ;
0281     pdu->ctrl_2  = 0;
0282     pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
0283     pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
0284     pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
0285 }
0286 
0287 /**
0288  *  llc_pdu_init_as_rnr_rsp - builds RNR response pdu
0289  *  @skb: Address of the frame to build
0290  *  @f_bit: The F bit to set in the PDU
0291  *  @nr: The seq. number of the expected data PDU from the remote
0292  *
0293  *  Builds a pdu frame as an RNR response.
0294  */
0295 void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
0296 {
0297     struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0298 
0299     pdu->ctrl_1  = LLC_PDU_TYPE_S;
0300     pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR;
0301     pdu->ctrl_2  = 0;
0302     pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
0303     pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
0304     pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
0305 }
0306 
0307 /**
0308  *  llc_pdu_init_as_ua_rsp - builds UA response pdu
0309  *  @skb: Address of the frame to build
0310  *  @f_bit: The F bit to set in the PDU
0311  *
0312  *  Builds a pdu frame as a UA response.
0313  */
0314 void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
0315 {
0316     struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0317 
0318     pdu->ctrl_1  = LLC_PDU_TYPE_U;
0319     pdu->ctrl_1 |= LLC_2_PDU_RSP_UA;
0320     pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
0321 }
0322 
0323 /**
0324  *  llc_pdu_decode_pdu_type - designates PDU type
0325  *  @skb: input skb that type of it must be designated.
0326  *  @type: type of PDU (output argument).
0327  *
0328  *  This function designates type of PDU (I, S or U).
0329  */
0330 static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
0331 {
0332     struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0333 
0334     if (pdu->ctrl_1 & 1) {
0335         if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
0336             *type = LLC_PDU_TYPE_U;
0337         else
0338             *type = LLC_PDU_TYPE_S;
0339     } else
0340         *type = LLC_PDU_TYPE_I;
0341 }
0342 
0343 /**
0344  *  llc_pdu_get_pf_bit - extracts p/f bit of input PDU
0345  *  @pdu: pointer to LLC header.
0346  *
0347  *  This function extracts p/f bit of input PDU. at first examines type of
0348  *  PDU and then extracts p/f bit. Returns the p/f bit.
0349  */
0350 static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu)
0351 {
0352     u8 pdu_type;
0353     u8 pf_bit = 0;
0354 
0355     if (pdu->ctrl_1 & 1) {
0356         if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
0357             pdu_type = LLC_PDU_TYPE_U;
0358         else
0359             pdu_type = LLC_PDU_TYPE_S;
0360     } else
0361         pdu_type = LLC_PDU_TYPE_I;
0362     switch (pdu_type) {
0363     case LLC_PDU_TYPE_I:
0364     case LLC_PDU_TYPE_S:
0365         pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK;
0366         break;
0367     case LLC_PDU_TYPE_U:
0368         pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
0369         break;
0370     }
0371     return pf_bit;
0372 }