linux/drivers/net/wireless/intel/iwlwifi/mei/net.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2021 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 */
  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                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 */
  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 bytes
 102         * src IP address    - 4 bytes
 103         * target MAC addess - 6 bytes
 104         */
 105        target_ip = (void *)((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
 137static bool
 138iwl_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
 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 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
 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_t
 278iwl_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
 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        else
 343                skb = orig_skb;
 344
 345        /* CSME wants the MAC header as well, push it back */
 346        skb_push(skb, skb->data - skb_mac_header(skb));
 347
 348        /*
 349         * Add the packet that CSME wants to get to the ring. Don't send the
 350         * Check Shared Area HECI message since this is not possible from the
 351         * Rx context. The caller will schedule a worker to do just that.
 352         */
 353        iwl_mei_add_data_to_ring(skb, false);
 354
 355        /*
 356         * In case we drop the packet, don't free it, the caller will do that
 357         * for us
 358         */
 359        if (ret == RX_HANDLER_PASS)
 360                dev_kfree_skb(skb);
 361
 362        return ret;
 363}
 364
 365#define DHCP_SERVER_PORT 67
 366#define DHCP_CLIENT_PORT 68
 367void iwl_mei_tx_copy_to_csme(struct sk_buff *origskb, unsigned int ivlen)
 368{
 369        struct ieee80211_hdr *hdr;
 370        struct sk_buff *skb;
 371        struct ethhdr ethhdr;
 372        struct ethhdr *eth;
 373
 374        /* Catch DHCP packets */
 375        if (origskb->protocol != htons(ETH_P_IP) ||
 376            ip_hdr(origskb)->protocol != IPPROTO_UDP ||
 377            udp_hdr(origskb)->source != htons(DHCP_CLIENT_PORT) ||
 378            udp_hdr(origskb)->dest != htons(DHCP_SERVER_PORT))
 379                return;
 380
 381        /*
 382         * We could be a bit less aggressive here and not copy everything, but
 383         * this is very rare anyway, do don't bother much.
 384         */
 385        skb = skb_copy(origskb, GFP_ATOMIC);
 386        if (!skb)
 387                return;
 388
 389        skb->protocol = origskb->protocol;
 390
 391        hdr = (void *)skb->data;
 392
 393        memcpy(ethhdr.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
 394        memcpy(ethhdr.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
 395
 396        /*
 397         * Remove the ieee80211 header + IV + SNAP but leave the ethertype
 398         * We still have enough headroom for the sap header.
 399         */
 400        pskb_pull(skb, ieee80211_hdrlen(hdr->frame_control) + ivlen + 6);
 401        eth = skb_push(skb, sizeof(ethhdr.h_dest) + sizeof(ethhdr.h_source));
 402        memcpy(eth, &ethhdr, sizeof(ethhdr.h_dest) + sizeof(ethhdr.h_source));
 403
 404        iwl_mei_add_data_to_ring(skb, true);
 405
 406        dev_kfree_skb(skb);
 407}
 408EXPORT_SYMBOL_GPL(iwl_mei_tx_copy_to_csme);
 409