0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/init.h>
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 #include <net/llc.h>
0018 #include <net/llc_sap.h>
0019 #include <net/llc_conn.h>
0020 #include <net/llc_c_ac.h>
0021 #include <net/llc_s_ac.h>
0022 #include <net/llc_c_ev.h>
0023 #include <net/llc_c_st.h>
0024 #include <net/llc_s_ev.h>
0025 #include <net/llc_s_st.h>
0026 #include <net/llc_pdu.h>
0027
0028 static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
0029 {
0030 struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0031
0032 return LLC_PDU_IS_CMD(pdu) &&
0033 LLC_PDU_TYPE_IS_U(pdu) &&
0034 LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
0035 !pdu->dsap;
0036 }
0037
0038 static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
0039 {
0040 struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
0041
0042 return LLC_PDU_IS_CMD(pdu) &&
0043 LLC_PDU_TYPE_IS_U(pdu) &&
0044 LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
0045 !pdu->dsap;
0046 }
0047
0048 static int llc_station_ac_send_xid_r(struct sk_buff *skb)
0049 {
0050 u8 mac_da[ETH_ALEN], dsap;
0051 int rc = 1;
0052 struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U,
0053 sizeof(struct llc_xid_info));
0054
0055 if (!nskb)
0056 goto out;
0057 llc_pdu_decode_sa(skb, mac_da);
0058 llc_pdu_decode_ssap(skb, &dsap);
0059 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
0060 llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
0061 rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da);
0062 if (unlikely(rc))
0063 goto free;
0064 dev_queue_xmit(nskb);
0065 out:
0066 return rc;
0067 free:
0068 kfree_skb(nskb);
0069 goto out;
0070 }
0071
0072 static int llc_station_ac_send_test_r(struct sk_buff *skb)
0073 {
0074 u8 mac_da[ETH_ALEN], dsap;
0075 int rc = 1;
0076 u32 data_size;
0077 struct sk_buff *nskb;
0078
0079
0080 data_size = ntohs(eth_hdr(skb)->h_proto) - 3;
0081 nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
0082
0083 if (!nskb)
0084 goto out;
0085 llc_pdu_decode_sa(skb, mac_da);
0086 llc_pdu_decode_ssap(skb, &dsap);
0087 llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
0088 llc_pdu_init_as_test_rsp(nskb, skb);
0089 rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da);
0090 if (unlikely(rc))
0091 goto free;
0092 dev_queue_xmit(nskb);
0093 out:
0094 return rc;
0095 free:
0096 kfree_skb(nskb);
0097 goto out;
0098 }
0099
0100
0101
0102
0103
0104
0105
0106 static void llc_station_rcv(struct sk_buff *skb)
0107 {
0108 if (llc_stat_ev_rx_null_dsap_xid_c(skb))
0109 llc_station_ac_send_xid_r(skb);
0110 else if (llc_stat_ev_rx_null_dsap_test_c(skb))
0111 llc_station_ac_send_test_r(skb);
0112 kfree_skb(skb);
0113 }
0114
0115 void __init llc_station_init(void)
0116 {
0117 llc_set_station_handler(llc_station_rcv);
0118 }
0119
0120 void llc_station_exit(void)
0121 {
0122 llc_set_station_handler(NULL);
0123 }