Branch data Line data Source code
1 : : /* 2 : : * llc_input.c - Minimal input path for LLC 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 : : #include <linux/netdevice.h> 15 : : #include <linux/slab.h> 16 : : #include <linux/export.h> 17 : : #include <net/net_namespace.h> 18 : : #include <net/llc.h> 19 : : #include <net/llc_pdu.h> 20 : : #include <net/llc_sap.h> 21 : : 22 : : #if 0 23 : : #define dprintk(args...) printk(KERN_DEBUG args) 24 : : #else 25 : : #define dprintk(args...) 26 : : #endif 27 : : 28 : : /* 29 : : * Packet handler for the station, registerable because in the minimal 30 : : * LLC core that is taking shape only the very minimal subset of LLC that 31 : : * is needed for things like IPX, Appletalk, etc will stay, with all the 32 : : * rest in the llc1 and llc2 modules. 33 : : */ 34 : : static void (*llc_station_handler)(struct sk_buff *skb); 35 : : 36 : : /* 37 : : * Packet handlers for LLC_DEST_SAP and LLC_DEST_CONN. 38 : : */ 39 : : static void (*llc_type_handlers[2])(struct llc_sap *sap, 40 : : struct sk_buff *skb); 41 : : 42 : 0 : void llc_add_pack(int type, void (*handler)(struct llc_sap *sap, 43 : : struct sk_buff *skb)) 44 : : { 45 : 0 : smp_wmb(); /* ensure initialisation is complete before it's called */ 46 [ # # ]: 0 : if (type == LLC_DEST_SAP || type == LLC_DEST_CONN) 47 : 0 : llc_type_handlers[type - 1] = handler; 48 : 0 : } 49 : : 50 : 0 : void llc_remove_pack(int type) 51 : : { 52 [ # # ]: 0 : if (type == LLC_DEST_SAP || type == LLC_DEST_CONN) 53 : 0 : llc_type_handlers[type - 1] = NULL; 54 : 0 : synchronize_net(); 55 : 0 : } 56 : : 57 : 0 : void llc_set_station_handler(void (*handler)(struct sk_buff *skb)) 58 : : { 59 : : /* Ensure initialisation is complete before it's called */ 60 [ # # ]: 0 : if (handler) 61 : 0 : smp_wmb(); 62 : : 63 : 0 : llc_station_handler = handler; 64 : : 65 [ # # ]: 0 : if (!handler) 66 : 0 : synchronize_net(); 67 : 0 : } 68 : : 69 : : /** 70 : : * llc_pdu_type - returns which LLC component must handle for PDU 71 : : * @skb: input skb 72 : : * 73 : : * This function returns which LLC component must handle this PDU. 74 : : */ 75 : 0 : static __inline__ int llc_pdu_type(struct sk_buff *skb) 76 : : { 77 : : int type = LLC_DEST_CONN; /* I-PDU or S-PDU type */ 78 : : struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); 79 : : 80 [ # # ]: 0 : if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) != LLC_PDU_TYPE_U) 81 : : goto out; 82 [ # # # ]: 0 : switch (LLC_U_PDU_CMD(pdu)) { 83 : : case LLC_1_PDU_CMD_XID: 84 : : case LLC_1_PDU_CMD_UI: 85 : : case LLC_1_PDU_CMD_TEST: 86 : : type = LLC_DEST_SAP; 87 : 0 : break; 88 : : case LLC_2_PDU_CMD_SABME: 89 : : case LLC_2_PDU_CMD_DISC: 90 : : case LLC_2_PDU_RSP_UA: 91 : : case LLC_2_PDU_RSP_DM: 92 : : case LLC_2_PDU_RSP_FRMR: 93 : : break; 94 : : default: 95 : : type = LLC_DEST_INVALID; 96 : 0 : break; 97 : : } 98 : : out: 99 : 0 : return type; 100 : : } 101 : : 102 : : /** 103 : : * llc_fixup_skb - initializes skb pointers 104 : : * @skb: This argument points to incoming skb 105 : : * 106 : : * Initializes internal skb pointer to start of network layer by deriving 107 : : * length of LLC header; finds length of LLC control field in LLC header 108 : : * by looking at the two lowest-order bits of the first control field 109 : : * byte; field is either 3 or 4 bytes long. 110 : : */ 111 : 0 : static inline int llc_fixup_skb(struct sk_buff *skb) 112 : : { 113 : : u8 llc_len = 2; 114 : : struct llc_pdu_un *pdu; 115 : : 116 [ # # ]: 0 : if (unlikely(!pskb_may_pull(skb, sizeof(*pdu)))) 117 : : return 0; 118 : : 119 : 0 : pdu = (struct llc_pdu_un *)skb->data; 120 [ # # ]: 0 : if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U) 121 : : llc_len = 1; 122 : 0 : llc_len += 2; 123 : : 124 [ # # ]: 0 : if (unlikely(!pskb_may_pull(skb, llc_len))) 125 : : return 0; 126 : : 127 : 0 : skb->transport_header += llc_len; 128 : 0 : skb_pull(skb, llc_len); 129 [ # # ]: 0 : if (skb->protocol == htons(ETH_P_802_2)) { 130 : 0 : __be16 pdulen = eth_hdr(skb)->h_proto; 131 : 0 : s32 data_size = ntohs(pdulen) - llc_len; 132 : : 133 [ # # # # ]: 0 : if (data_size < 0 || 134 : 0 : !pskb_may_pull(skb, data_size)) 135 : : return 0; 136 [ # # ]: 0 : if (unlikely(pskb_trim_rcsum(skb, data_size))) 137 : : return 0; 138 : : } 139 : : return 1; 140 : : } 141 : : 142 : : /** 143 : : * llc_rcv - 802.2 entry point from net lower layers 144 : : * @skb: received pdu 145 : : * @dev: device that receive pdu 146 : : * @pt: packet type 147 : : * 148 : : * When the system receives a 802.2 frame this function is called. It 149 : : * checks SAP and connection of received pdu and passes frame to 150 : : * llc_{station,sap,conn}_rcv for sending to proper state machine. If 151 : : * the frame is related to a busy connection (a connection is sending 152 : : * data now), it queues this frame in the connection's backlog. 153 : : */ 154 : 0 : int llc_rcv(struct sk_buff *skb, struct net_device *dev, 155 : : struct packet_type *pt, struct net_device *orig_dev) 156 : : { 157 : : struct llc_sap *sap; 158 : : struct llc_pdu_sn *pdu; 159 : : int dest; 160 : : int (*rcv)(struct sk_buff *, struct net_device *, 161 : : struct packet_type *, struct net_device *); 162 : : void (*sta_handler)(struct sk_buff *skb); 163 : : void (*sap_handler)(struct llc_sap *sap, struct sk_buff *skb); 164 : : 165 [ # # ]: 0 : if (!net_eq(dev_net(dev), &init_net)) 166 : : goto drop; 167 : : 168 : : /* 169 : : * When the interface is in promisc. mode, drop all the crap that it 170 : : * receives, do not try to analyse it. 171 : : */ 172 [ # # ]: 0 : if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) { 173 : : dprintk("%s: PACKET_OTHERHOST\n", __func__); 174 : : goto drop; 175 : : } 176 : 0 : skb = skb_share_check(skb, GFP_ATOMIC); 177 [ # # ]: 0 : if (unlikely(!skb)) 178 : : goto out; 179 [ # # ]: 0 : if (unlikely(!llc_fixup_skb(skb))) 180 : : goto drop; 181 : : pdu = llc_pdu_sn_hdr(skb); 182 [ # # ]: 0 : if (unlikely(!pdu->dsap)) /* NULL DSAP, refer to station */ 183 : : goto handle_station; 184 : 0 : sap = llc_sap_find(pdu->dsap); 185 [ # # ]: 0 : if (unlikely(!sap)) {/* unknown SAP */ 186 : : dprintk("%s: llc_sap_find(%02X) failed!\n", __func__, 187 : : pdu->dsap); 188 : : goto drop; 189 : : } 190 : : /* 191 : : * First the upper layer protocols that don't need the full 192 : : * LLC functionality 193 : : */ 194 : 0 : rcv = rcu_dereference(sap->rcv_func); 195 : 0 : dest = llc_pdu_type(skb); 196 [ # # ]: 0 : sap_handler = dest ? READ_ONCE(llc_type_handlers[dest - 1]) : NULL; 197 [ # # ]: 0 : if (unlikely(!sap_handler)) { 198 [ # # ]: 0 : if (rcv) 199 : 0 : rcv(skb, dev, pt, orig_dev); 200 : : else 201 : 0 : kfree_skb(skb); 202 : : } else { 203 [ # # ]: 0 : if (rcv) { 204 : 0 : struct sk_buff *cskb = skb_clone(skb, GFP_ATOMIC); 205 [ # # ]: 0 : if (cskb) 206 : 0 : rcv(cskb, dev, pt, orig_dev); 207 : : } 208 : 0 : sap_handler(sap, skb); 209 : : } 210 : 0 : llc_sap_put(sap); 211 : : out: 212 : 0 : return 0; 213 : : drop: 214 : 0 : kfree_skb(skb); 215 : 0 : goto out; 216 : : handle_station: 217 : 0 : sta_handler = READ_ONCE(llc_station_handler); 218 [ # # ]: 0 : if (!sta_handler) 219 : : goto drop; 220 : 0 : sta_handler(skb); 221 : 0 : goto out; 222 : : } 223 : : 224 : : EXPORT_SYMBOL(llc_add_pack); 225 : : EXPORT_SYMBOL(llc_remove_pack); 226 : : EXPORT_SYMBOL(llc_set_station_handler);