413 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2021-2022 Intel Corporation4 */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 case30 * pass_to_csme and rx_handler_res are set. Otherwise, next level of filters31 * should be checked.32 */33static 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 else59 *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 case78 * rx_handler_res is set.79 */80static 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 bytes102 * src IP address - 4 bytes103 * target MAC addess - 6 bytes104 */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 the110 * 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 else118 *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 else129 *rx_handler_res = RX_HANDLER_CONSUMED;130 131 return true;132 }133 134 return false;135}136 137static bool138iwl_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't152 * 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, both169 * 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 else180 *rx_handler_res = RX_HANDLER_CONSUMED;181 182 return true;183 }184 185 return false;186}187 188static 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 bytes213 * 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 we233 * 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 else240 *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 else254 *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 266static 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 277static rx_handler_result_t278iwl_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 header290 * is in the headroom.291 */292 skb_reset_network_header(skb);293 294 /*295 * MCAST IP packets sent by us are received again here without296 * 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 328rx_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 the354 * Check Shared Area HECI message since this is not possible from the355 * 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 that361 * for us362 */363 if (ret == RX_HANDLER_PASS)364 dev_kfree_skb(skb);365 366 return ret;367}368 369#define DHCP_SERVER_PORT 67370#define DHCP_CLIENT_PORT 68371void 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, but387 * 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 ethertype402 * 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}412EXPORT_SYMBOL_GPL(iwl_mei_tx_copy_to_csme);413