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