1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2021-2022 Intel Corporation
4 */
5
6 #include <uapi/linux/if_ether.h>
7 #include <uapi/linux/if_arp.h>
8 #include <uapi/linux/icmp.h>
9
10 #include <linux/etherdevice.h>
11 #include <linux/netdevice.h>
12 #include <linux/skbuff.h>
13 #include <linux/ieee80211.h>
14
15 #include <net/cfg80211.h>
16 #include <net/ip.h>
17
18 #include <linux/if_arp.h>
19 #include <linux/icmp.h>
20 #include <linux/udp.h>
21 #include <linux/ip.h>
22 #include <linux/mm.h>
23
24 #include "internal.h"
25 #include "sap.h"
26 #include "iwl-mei.h"
27
28 /*
29 * Returns true if further filtering should be stopped. Only in that case
30 * pass_to_csme and rx_handler_res are set. Otherwise, next level of filters
31 * should be checked.
32 */
iwl_mei_rx_filter_eth(const struct ethhdr * ethhdr,const struct iwl_sap_oob_filters * filters,bool * pass_to_csme,rx_handler_result_t * rx_handler_res)33 static bool iwl_mei_rx_filter_eth(const struct ethhdr *ethhdr,
34 const struct iwl_sap_oob_filters *filters,
35 bool *pass_to_csme,
36 rx_handler_result_t *rx_handler_res)
37 {
38 const struct iwl_sap_eth_filter *filt;
39
40 /* This filter is not relevant for UCAST packet */
41 if (!is_multicast_ether_addr(ethhdr->h_dest) ||
42 is_broadcast_ether_addr(ethhdr->h_dest))
43 return false;
44
45 for (filt = &filters->eth_filters[0];
46 filt < &filters->eth_filters[0] + ARRAY_SIZE(filters->eth_filters);
47 filt++) {
48 /* Assume there are no enabled filter after a disabled one */
49 if (!(filt->flags & SAP_ETH_FILTER_ENABLED))
50 break;
51
52 if (compare_ether_header(filt->mac_address, ethhdr->h_dest))
53 continue;
54
55 /* Packet needs to reach the host's stack */
56 if (filt->flags & SAP_ETH_FILTER_COPY)
57 *rx_handler_res = RX_HANDLER_PASS;
58 else
59 *rx_handler_res = RX_HANDLER_CONSUMED;
60
61 /* We have an authoritative answer, stop filtering */
62 if (filt->flags & SAP_ETH_FILTER_STOP) {
63 *pass_to_csme = true;
64 return true;
65 }
66
67 return false;
68 }
69
70 /* MCAST frames that don't match layer 2 filters are not sent to ME */
71 *pass_to_csme = false;
72
73 return true;
74 }
75
76 /*
77 * Returns true iff the frame should be passed to CSME in which case
78 * rx_handler_res is set.
79 */
iwl_mei_rx_filter_arp(struct sk_buff * skb,const struct iwl_sap_oob_filters * filters,rx_handler_result_t * rx_handler_res)80 static bool iwl_mei_rx_filter_arp(struct sk_buff *skb,
81 const struct iwl_sap_oob_filters *filters,
82 rx_handler_result_t *rx_handler_res)
83 {
84 const struct iwl_sap_ipv4_filter *filt = &filters->ipv4_filter;
85 const struct arphdr *arp;
86 const __be32 *target_ip;
87 u32 flags = le32_to_cpu(filt->flags);
88
89 if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
90 return false;
91
92 arp = arp_hdr(skb);
93
94 /* Handle only IPv4 over ethernet ARP frames */
95 if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
96 arp->ar_pro != htons(ETH_P_IP))
97 return false;
98
99 /*
100 * After the ARP header, we have:
101 * src MAC address - 6 bytes
102 * src IP address - 4 bytes
103 * target MAC addess - 6 bytes
104 */
105 target_ip = (const void *)((const u8 *)(arp + 1) +
106 ETH_ALEN + sizeof(__be32) + ETH_ALEN);
107
108 /*
109 * ARP request is forwarded to ME only if IP address match in the
110 * ARP request's target ip field.
111 */
112 if (arp->ar_op == htons(ARPOP_REQUEST) &&
113 (filt->flags & cpu_to_le32(SAP_IPV4_FILTER_ARP_REQ_PASS)) &&
114 (filt->ipv4_addr == 0 || filt->ipv4_addr == *target_ip)) {
115 if (flags & SAP_IPV4_FILTER_ARP_REQ_COPY)
116 *rx_handler_res = RX_HANDLER_PASS;
117 else
118 *rx_handler_res = RX_HANDLER_CONSUMED;
119
120 return true;
121 }
122
123 /* ARP reply is always forwarded to ME regardless of the IP */
124 if (flags & SAP_IPV4_FILTER_ARP_RESP_PASS &&
125 arp->ar_op == htons(ARPOP_REPLY)) {
126 if (flags & SAP_IPV4_FILTER_ARP_RESP_COPY)
127 *rx_handler_res = RX_HANDLER_PASS;
128 else
129 *rx_handler_res = RX_HANDLER_CONSUMED;
130
131 return true;
132 }
133
134 return false;
135 }
136
137 static bool
iwl_mei_rx_filter_tcp_udp(struct sk_buff * skb,bool ip_match,const struct iwl_sap_oob_filters * filters,rx_handler_result_t * rx_handler_res)138 iwl_mei_rx_filter_tcp_udp(struct sk_buff *skb, bool ip_match,
139 const struct iwl_sap_oob_filters *filters,
140 rx_handler_result_t *rx_handler_res)
141 {
142 const struct iwl_sap_flex_filter *filt;
143
144 for (filt = &filters->flex_filters[0];
145 filt < &filters->flex_filters[0] + ARRAY_SIZE(filters->flex_filters);
146 filt++) {
147 if (!(filt->flags & SAP_FLEX_FILTER_ENABLED))
148 break;
149
150 /*
151 * We are required to have a match on the IP level and we didn't
152 * have such match.
153 */
154 if ((filt->flags &
155 (SAP_FLEX_FILTER_IPV4 | SAP_FLEX_FILTER_IPV6)) &&
156 !ip_match)
157 continue;
158
159 if ((filt->flags & SAP_FLEX_FILTER_UDP) &&
160 ip_hdr(skb)->protocol != IPPROTO_UDP)
161 continue;
162
163 if ((filt->flags & SAP_FLEX_FILTER_TCP) &&
164 ip_hdr(skb)->protocol != IPPROTO_TCP)
165 continue;
166
167 /*
168 * We must have either a TCP header or a UDP header, both
169 * starts with a source port and then a destination port.
170 * Both are big endian words.
171 * Use a UDP header and that will work for TCP as well.
172 */
173 if ((filt->src_port && filt->src_port != udp_hdr(skb)->source) ||
174 (filt->dst_port && filt->dst_port != udp_hdr(skb)->dest))
175 continue;
176
177 if (filt->flags & SAP_FLEX_FILTER_COPY)
178 *rx_handler_res = RX_HANDLER_PASS;
179 else
180 *rx_handler_res = RX_HANDLER_CONSUMED;
181
182 return true;
183 }
184
185 return false;
186 }
187
iwl_mei_rx_filter_ipv4(struct sk_buff * skb,const struct iwl_sap_oob_filters * filters,rx_handler_result_t * rx_handler_res)188 static bool iwl_mei_rx_filter_ipv4(struct sk_buff *skb,
189 const struct iwl_sap_oob_filters *filters,
190 rx_handler_result_t *rx_handler_res)
191 {
192 const struct iwl_sap_ipv4_filter *filt = &filters->ipv4_filter;
193 const struct iphdr *iphdr;
194 unsigned int iphdrlen;
195 bool match;
196
197 if (!pskb_may_pull(skb, skb_network_offset(skb) + sizeof(*iphdr)) ||
198 !pskb_may_pull(skb, skb_network_offset(skb) + ip_hdrlen(skb)))
199 return false;
200
201 iphdrlen = ip_hdrlen(skb);
202 iphdr = ip_hdr(skb);
203 match = !filters->ipv4_filter.ipv4_addr ||
204 filters->ipv4_filter.ipv4_addr == iphdr->daddr;
205
206 skb_set_transport_header(skb, skb_network_offset(skb) + iphdrlen);
207
208 switch (ip_hdr(skb)->protocol) {
209 case IPPROTO_UDP:
210 case IPPROTO_TCP:
211 /*
212 * UDP header is shorter than TCP header and we look at the first bytes
213 * of the header anyway (see below).
214 * If we have a truncated TCP packet, let CSME handle this.
215 */
216 if (!pskb_may_pull(skb, skb_transport_offset(skb) +
217 sizeof(struct udphdr)))
218 return false;
219
220 return iwl_mei_rx_filter_tcp_udp(skb, match,
221 filters, rx_handler_res);
222
223 case IPPROTO_ICMP: {
224 struct icmphdr *icmp;
225
226 if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(*icmp)))
227 return false;
228
229 icmp = icmp_hdr(skb);
230
231 /*
232 * Don't pass echo requests to ME even if it wants it as we
233 * want the host to answer.
234 */
235 if ((filt->flags & cpu_to_le32(SAP_IPV4_FILTER_ICMP_PASS)) &&
236 match && (icmp->type != ICMP_ECHO || icmp->code != 0)) {
237 if (filt->flags & cpu_to_le32(SAP_IPV4_FILTER_ICMP_COPY))
238 *rx_handler_res = RX_HANDLER_PASS;
239 else
240 *rx_handler_res = RX_HANDLER_CONSUMED;
241
242 return true;
243 }
244 break;
245 }
246 case IPPROTO_ICMPV6:
247 /* TODO: Should we have the same ICMP request logic here too? */
248 if ((filters->icmpv6_flags & cpu_to_le32(SAP_ICMPV6_FILTER_ENABLED) &&
249 match)) {
250 if (filters->icmpv6_flags &
251 cpu_to_le32(SAP_ICMPV6_FILTER_COPY))
252 *rx_handler_res = RX_HANDLER_PASS;
253 else
254 *rx_handler_res = RX_HANDLER_CONSUMED;
255
256 return true;
257 }
258 break;
259 default:
260 return false;
261 }
262
263 return false;
264 }
265
iwl_mei_rx_filter_ipv6(struct sk_buff * skb,const struct iwl_sap_oob_filters * filters,rx_handler_result_t * rx_handler_res)266 static bool iwl_mei_rx_filter_ipv6(struct sk_buff *skb,
267 const struct iwl_sap_oob_filters *filters,
268 rx_handler_result_t *rx_handler_res)
269 {
270 *rx_handler_res = RX_HANDLER_PASS;
271
272 /* TODO */
273
274 return false;
275 }
276
277 static rx_handler_result_t
iwl_mei_rx_pass_to_csme(struct sk_buff * skb,const struct iwl_sap_oob_filters * filters,bool * pass_to_csme)278 iwl_mei_rx_pass_to_csme(struct sk_buff *skb,
279 const struct iwl_sap_oob_filters *filters,
280 bool *pass_to_csme)
281 {
282 const struct ethhdr *ethhdr = (void *)skb_mac_header(skb);
283 rx_handler_result_t rx_handler_res = RX_HANDLER_PASS;
284 bool (*filt_handler)(struct sk_buff *skb,
285 const struct iwl_sap_oob_filters *filters,
286 rx_handler_result_t *rx_handler_res);
287
288 /*
289 * skb->data points the IP header / ARP header and the ETH header
290 * is in the headroom.
291 */
292 skb_reset_network_header(skb);
293
294 /*
295 * MCAST IP packets sent by us are received again here without
296 * an ETH header. Drop them here.
297 */
298 if (!skb_mac_offset(skb))
299 return RX_HANDLER_PASS;
300
301 if (skb_headroom(skb) < sizeof(*ethhdr))
302 return RX_HANDLER_PASS;
303
304 if (iwl_mei_rx_filter_eth(ethhdr, filters,
305 pass_to_csme, &rx_handler_res))
306 return rx_handler_res;
307
308 switch (skb->protocol) {
309 case htons(ETH_P_IP):
310 filt_handler = iwl_mei_rx_filter_ipv4;
311 break;
312 case htons(ETH_P_ARP):
313 filt_handler = iwl_mei_rx_filter_arp;
314 break;
315 case htons(ETH_P_IPV6):
316 filt_handler = iwl_mei_rx_filter_ipv6;
317 break;
318 default:
319 *pass_to_csme = false;
320 return rx_handler_res;
321 }
322
323 *pass_to_csme = filt_handler(skb, filters, &rx_handler_res);
324
325 return rx_handler_res;
326 }
327
iwl_mei_rx_filter(struct sk_buff * orig_skb,const struct iwl_sap_oob_filters * filters,bool * pass_to_csme)328 rx_handler_result_t iwl_mei_rx_filter(struct sk_buff *orig_skb,
329 const struct iwl_sap_oob_filters *filters,
330 bool *pass_to_csme)
331 {
332 rx_handler_result_t ret;
333 struct sk_buff *skb;
334
335 ret = iwl_mei_rx_pass_to_csme(orig_skb, filters, pass_to_csme);
336
337 if (!*pass_to_csme)
338 return RX_HANDLER_PASS;
339
340 if (ret == RX_HANDLER_PASS) {
341 skb = skb_copy(orig_skb, GFP_ATOMIC);
342
343 if (!skb)
344 return RX_HANDLER_PASS;
345 } else {
346 skb = orig_skb;
347 }
348
349 /* CSME wants the MAC header as well, push it back */
350 skb_push(skb, skb->data - skb_mac_header(skb));
351
352 /*
353 * Add the packet that CSME wants to get to the ring. Don't send the
354 * Check Shared Area HECI message since this is not possible from the
355 * Rx context. The caller will schedule a worker to do just that.
356 */
357 iwl_mei_add_data_to_ring(skb, false);
358
359 /*
360 * In case we drop the packet, don't free it, the caller will do that
361 * for us
362 */
363 if (ret == RX_HANDLER_PASS)
364 dev_kfree_skb(skb);
365
366 return ret;
367 }
368
369 #define DHCP_SERVER_PORT 67
370 #define DHCP_CLIENT_PORT 68
iwl_mei_tx_copy_to_csme(struct sk_buff * origskb,unsigned int ivlen)371 void iwl_mei_tx_copy_to_csme(struct sk_buff *origskb, unsigned int ivlen)
372 {
373 struct ieee80211_hdr *hdr;
374 struct sk_buff *skb;
375 struct ethhdr ethhdr;
376 struct ethhdr *eth;
377
378 /* Catch DHCP packets */
379 if (origskb->protocol != htons(ETH_P_IP) ||
380 ip_hdr(origskb)->protocol != IPPROTO_UDP ||
381 udp_hdr(origskb)->source != htons(DHCP_CLIENT_PORT) ||
382 udp_hdr(origskb)->dest != htons(DHCP_SERVER_PORT))
383 return;
384
385 /*
386 * We could be a bit less aggressive here and not copy everything, but
387 * this is very rare anyway, do don't bother much.
388 */
389 skb = skb_copy(origskb, GFP_ATOMIC);
390 if (!skb)
391 return;
392
393 skb->protocol = origskb->protocol;
394
395 hdr = (void *)skb->data;
396
397 memcpy(ethhdr.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
398 memcpy(ethhdr.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
399
400 /*
401 * Remove the ieee80211 header + IV + SNAP but leave the ethertype
402 * We still have enough headroom for the sap header.
403 */
404 pskb_pull(skb, ieee80211_hdrlen(hdr->frame_control) + ivlen + 6);
405 eth = skb_push(skb, sizeof(ethhdr.h_dest) + sizeof(ethhdr.h_source));
406 memcpy(eth, ðhdr, sizeof(ethhdr.h_dest) + sizeof(ethhdr.h_source));
407
408 iwl_mei_add_data_to_ring(skb, true);
409
410 dev_kfree_skb(skb);
411 }
412 EXPORT_SYMBOL_GPL(iwl_mei_tx_copy_to_csme);
413