0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/netdevice.h>
0015 #include <linux/slab.h>
0016 #include <linux/export.h>
0017 #include <net/net_namespace.h>
0018 #include <net/llc.h>
0019 #include <net/llc_pdu.h>
0020 #include <net/llc_sap.h>
0021
0022 #if 0
0023 #define dprintk(args...) printk(KERN_DEBUG args)
0024 #else
0025 #define dprintk(args...)
0026 #endif
0027
0028
0029
0030
0031
0032
0033
0034 static void (*llc_station_handler)(struct sk_buff *skb);
0035
0036
0037
0038
0039 static void (*llc_type_handlers[2])(struct llc_sap *sap,
0040 struct sk_buff *skb);
0041
0042 void llc_add_pack(int type, void (*handler)(struct llc_sap *sap,
0043 struct sk_buff *skb))
0044 {
0045 smp_wmb();
0046 if (type == LLC_DEST_SAP || type == LLC_DEST_CONN)
0047 llc_type_handlers[type - 1] = handler;
0048 }
0049
0050 void llc_remove_pack(int type)
0051 {
0052 if (type == LLC_DEST_SAP || type == LLC_DEST_CONN)
0053 llc_type_handlers[type - 1] = NULL;
0054 synchronize_net();
0055 }
0056
0057 void llc_set_station_handler(void (*handler)(struct sk_buff *skb))
0058 {
0059
0060 if (handler)
0061 smp_wmb();
0062
0063 llc_station_handler = handler;
0064
0065 if (!handler)
0066 synchronize_net();
0067 }
0068
0069
0070
0071
0072
0073
0074
0075 static __inline__ int llc_pdu_type(struct sk_buff *skb)
0076 {
0077 int type = LLC_DEST_CONN;
0078 struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
0079
0080 if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) != LLC_PDU_TYPE_U)
0081 goto out;
0082 switch (LLC_U_PDU_CMD(pdu)) {
0083 case LLC_1_PDU_CMD_XID:
0084 case LLC_1_PDU_CMD_UI:
0085 case LLC_1_PDU_CMD_TEST:
0086 type = LLC_DEST_SAP;
0087 break;
0088 case LLC_2_PDU_CMD_SABME:
0089 case LLC_2_PDU_CMD_DISC:
0090 case LLC_2_PDU_RSP_UA:
0091 case LLC_2_PDU_RSP_DM:
0092 case LLC_2_PDU_RSP_FRMR:
0093 break;
0094 default:
0095 type = LLC_DEST_INVALID;
0096 break;
0097 }
0098 out:
0099 return type;
0100 }
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111 static inline int llc_fixup_skb(struct sk_buff *skb)
0112 {
0113 u8 llc_len = 2;
0114 struct llc_pdu_un *pdu;
0115
0116 if (unlikely(!pskb_may_pull(skb, sizeof(*pdu))))
0117 return 0;
0118
0119 pdu = (struct llc_pdu_un *)skb->data;
0120 if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U)
0121 llc_len = 1;
0122 llc_len += 2;
0123
0124 if (unlikely(!pskb_may_pull(skb, llc_len)))
0125 return 0;
0126
0127 skb->transport_header += llc_len;
0128 skb_pull(skb, llc_len);
0129 if (skb->protocol == htons(ETH_P_802_2)) {
0130 __be16 pdulen = eth_hdr(skb)->h_proto;
0131 s32 data_size = ntohs(pdulen) - llc_len;
0132
0133 if (data_size < 0 ||
0134 !pskb_may_pull(skb, data_size))
0135 return 0;
0136 if (unlikely(pskb_trim_rcsum(skb, data_size)))
0137 return 0;
0138 }
0139 return 1;
0140 }
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 int llc_rcv(struct sk_buff *skb, struct net_device *dev,
0156 struct packet_type *pt, struct net_device *orig_dev)
0157 {
0158 struct llc_sap *sap;
0159 struct llc_pdu_sn *pdu;
0160 int dest;
0161 int (*rcv)(struct sk_buff *, struct net_device *,
0162 struct packet_type *, struct net_device *);
0163 void (*sta_handler)(struct sk_buff *skb);
0164 void (*sap_handler)(struct llc_sap *sap, struct sk_buff *skb);
0165
0166 if (!net_eq(dev_net(dev), &init_net))
0167 goto drop;
0168
0169
0170
0171
0172
0173 if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
0174 dprintk("%s: PACKET_OTHERHOST\n", __func__);
0175 goto drop;
0176 }
0177 skb = skb_share_check(skb, GFP_ATOMIC);
0178 if (unlikely(!skb))
0179 goto out;
0180 if (unlikely(!llc_fixup_skb(skb)))
0181 goto drop;
0182 pdu = llc_pdu_sn_hdr(skb);
0183 if (unlikely(!pdu->dsap))
0184 goto handle_station;
0185 sap = llc_sap_find(pdu->dsap);
0186 if (unlikely(!sap)) {
0187 dprintk("%s: llc_sap_find(%02X) failed!\n", __func__,
0188 pdu->dsap);
0189 goto drop;
0190 }
0191
0192
0193
0194
0195 rcv = rcu_dereference(sap->rcv_func);
0196 dest = llc_pdu_type(skb);
0197 sap_handler = dest ? READ_ONCE(llc_type_handlers[dest - 1]) : NULL;
0198 if (unlikely(!sap_handler)) {
0199 if (rcv)
0200 rcv(skb, dev, pt, orig_dev);
0201 else
0202 kfree_skb(skb);
0203 } else {
0204 if (rcv) {
0205 struct sk_buff *cskb = skb_clone(skb, GFP_ATOMIC);
0206 if (cskb)
0207 rcv(cskb, dev, pt, orig_dev);
0208 }
0209 sap_handler(sap, skb);
0210 }
0211 llc_sap_put(sap);
0212 out:
0213 return 0;
0214 drop:
0215 kfree_skb(skb);
0216 goto out;
0217 handle_station:
0218 sta_handler = READ_ONCE(llc_station_handler);
0219 if (!sta_handler)
0220 goto drop;
0221 sta_handler(skb);
0222 goto out;
0223 }
0224
0225 EXPORT_SYMBOL(llc_add_pack);
0226 EXPORT_SYMBOL(llc_remove_pack);
0227 EXPORT_SYMBOL(llc_set_station_handler);