Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: rtl8188eu: Introduce monitor interface for IEEE 802.11 frames

This adds support for monitoring IEEE 802.11 Data and Management frames
received or transmitted by a RTL8188EU-based device handled by this
driver.

The monitor interface is not enabled by default and will be registered
only if monitor_enable module parameter is set to 1. When enabled it
will show up as a monX network device, which can be used by the
userspace programs for monitoring network traffic.

It is intended as an exploratory/debugging tool for rtl8188eu driver.

Signed-off-by: Jakub Sitnicki <jsitnicki@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jakub Sitnicki and committed by
Greg Kroah-Hartman
0a0796eb d59177cb

+270
+1
drivers/staging/rtl8188eu/Makefile
··· 42 42 hal/usb_halinit.o \ 43 43 os_dep/ioctl_linux.o \ 44 44 os_dep/mlme_linux.o \ 45 + os_dep/mon.o \ 45 46 os_dep/os_intfs.o \ 46 47 os_dep/osdep_service.o \ 47 48 os_dep/recv_linux.o \
+14
drivers/staging/rtl8188eu/core/rtw_recv.c
··· 25 25 #include <drv_types.h> 26 26 #include <recv_osdep.h> 27 27 #include <mlme_osdep.h> 28 + #include <mon.h> 28 29 #include <wifi.h> 29 30 #include <linux/vmalloc.h> 30 31 ··· 1329 1328 retval = _FAIL; 1330 1329 break; 1331 1330 } 1331 + 1332 + /* 1333 + * This is the last moment before management and control frames get 1334 + * discarded. So we need to forward them to the monitor now or never. 1335 + * 1336 + * At the same time data frames can still be encrypted if software 1337 + * decryption is in use. However, decryption can occur not until later 1338 + * (see recv_func()). 1339 + * 1340 + * Hence forward the frame to the monitor anyway to preserve the order 1341 + * in which frames were received. 1342 + */ 1343 + rtl88eu_mon_recv_hook(adapter->pmondev, precv_frame); 1332 1344 1333 1345 exit: 1334 1346
+4
drivers/staging/rtl8188eu/core/rtw_xmit.c
··· 21 21 22 22 #include <osdep_service.h> 23 23 #include <drv_types.h> 24 + #include <mon.h> 24 25 #include <wifi.h> 25 26 #include <osdep_intf.h> 26 27 #include <linux/vmalloc.h> ··· 1100 1099 mem_start = (unsigned char *)round_up(addr, 4) + hw_hdr_offset; 1101 1100 memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); 1102 1101 } 1102 + 1103 + /* Frame is about to be encrypted. Forward it to the monitor first. */ 1104 + rtl88eu_mon_xmit_hook(padapter->pmondev, pxmitframe, frg_len); 1103 1105 1104 1106 if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { 1105 1107 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"));
+4
drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
··· 20 20 #define _RTL8188E_XMIT_C_ 21 21 #include <osdep_service.h> 22 22 #include <drv_types.h> 23 + #include <mon.h> 23 24 #include <wifi.h> 24 25 #include <osdep_intf.h> 25 26 #include <usb_ops_linux.h> ··· 685 684 686 685 s32 rtl8188eu_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe) 687 686 { 687 + struct xmit_priv *xmitpriv = &adapt->xmitpriv; 688 + 689 + rtl88eu_mon_xmit_hook(adapt->pmondev, pmgntframe, xmitpriv->frag_len); 688 690 return rtw_dump_xframe(adapt, pmgntframe); 689 691 } 690 692
+2
drivers/staging/rtl8188eu/include/drv_types.h
··· 131 131 u8 if2name[16]; 132 132 133 133 u8 notch_filter; 134 + bool monitor_enable; 134 135 }; 135 136 136 137 /* For registry parameters */ ··· 210 209 void (*intf_start)(struct adapter *adapter); 211 210 void (*intf_stop)(struct adapter *adapter); 212 211 struct net_device *pnetdev; 212 + struct net_device *pmondev; 213 213 214 214 /* used by rtw_rereg_nd_name related function */ 215 215 struct rereg_nd_name_data {
+36
drivers/staging/rtl8188eu/include/mon.h
··· 1 + /* 2 + * RTL8188EU monitor interface 3 + * 4 + * Copyright (C) 2015 Jakub Sitnicki 5 + * 6 + * This program is free software; you can redistribute it and/or modify it under 7 + * the terms of the GNU General Public License version 2 as published by the 8 + * Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 + * details. 14 + */ 15 + 16 + /* 17 + * Monitor interface receives all transmitted and received IEEE 802.11 18 + * frames, both Data and Management, and passes them up to userspace 19 + * preserving the WLAN headers. 20 + */ 21 + 22 + #ifndef _MON_H_ 23 + #define _MON_H_ 24 + 25 + struct net_device; 26 + struct recv_frame; 27 + struct xmit_frame; 28 + 29 + struct net_device *rtl88eu_mon_init(void); 30 + void rtl88eu_mon_deinit(struct net_device *dev); 31 + 32 + void rtl88eu_mon_recv_hook(struct net_device *dev, struct recv_frame *frame); 33 + void rtl88eu_mon_xmit_hook(struct net_device *dev, struct xmit_frame *frame, 34 + uint frag_len); 35 + 36 + #endif /* _MON_H_ */
+194
drivers/staging/rtl8188eu/os_dep/mon.c
··· 1 + /* 2 + * RTL8188EU monitor interface 3 + * 4 + * Copyright (C) 2015 Jakub Sitnicki 5 + * 6 + * This program is free software; you can redistribute it and/or modify it under 7 + * the terms of the GNU General Public License version 2 as published by the 8 + * Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 + * details. 14 + */ 15 + 16 + #include <linux/ieee80211.h> 17 + #include <linux/netdevice.h> 18 + #include <net/cfg80211.h> 19 + 20 + #include <drv_types.h> 21 + #include <rtw_recv.h> 22 + #include <rtw_xmit.h> 23 + 24 + /** 25 + * unprotect_frame() - unset Protected flag and strip off IV and ICV/MIC 26 + */ 27 + static void unprotect_frame(struct sk_buff *skb, int iv_len, int icv_len) 28 + { 29 + struct ieee80211_hdr *hdr; 30 + int hdr_len; 31 + 32 + hdr = (struct ieee80211_hdr *)skb->data; 33 + hdr_len = ieee80211_hdrlen(hdr->frame_control); 34 + 35 + if (skb->len < hdr_len + iv_len + icv_len) 36 + return; 37 + if (!ieee80211_has_protected(hdr->frame_control)) 38 + return; 39 + 40 + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED); 41 + 42 + memmove(skb->data + iv_len, skb->data, hdr_len); 43 + skb_pull(skb, iv_len); 44 + skb_trim(skb, skb->len - icv_len); 45 + } 46 + 47 + static void mon_recv_decrypted(struct net_device *dev, const u8 *data, 48 + int data_len, int iv_len, int icv_len) 49 + { 50 + struct sk_buff *skb; 51 + 52 + skb = netdev_alloc_skb(dev, data_len); 53 + if (!skb) 54 + return; 55 + memcpy(skb_put(skb, data_len), data, data_len); 56 + 57 + /* 58 + * Frame data is not encrypted. Strip off protection so 59 + * userspace doesn't think that it is. 60 + */ 61 + unprotect_frame(skb, iv_len, icv_len); 62 + 63 + skb->ip_summed = CHECKSUM_UNNECESSARY; 64 + skb->protocol = eth_type_trans(skb, dev); 65 + netif_rx(skb); 66 + } 67 + 68 + static void mon_recv_encrypted(struct net_device *dev, const u8 *data, 69 + int data_len) 70 + { 71 + if (net_ratelimit()) 72 + netdev_info(dev, "Encrypted packets are not supported"); 73 + } 74 + 75 + /** 76 + * rtl88eu_mon_recv_hook() - forward received frame to the monitor interface 77 + * 78 + * Assumes that the frame contains an IV and an ICV/MIC, and that 79 + * encrypt field in frame->attrib have been set accordingly. 80 + */ 81 + void rtl88eu_mon_recv_hook(struct net_device *dev, struct recv_frame *frame) 82 + { 83 + struct rx_pkt_attrib *attr; 84 + int iv_len, icv_len; 85 + int data_len; 86 + u8 *data; 87 + 88 + if (!dev || !frame) 89 + return; 90 + if (!netif_running(dev)) 91 + return; 92 + 93 + attr = &frame->attrib; 94 + data = frame->rx_data; 95 + data_len = frame->len; 96 + 97 + /* Broadcast and multicast frames don't have attr->{iv,icv}_len set */ 98 + SET_ICE_IV_LEN(iv_len, icv_len, attr->encrypt); 99 + 100 + if (attr->bdecrypted) 101 + mon_recv_decrypted(dev, data, data_len, iv_len, icv_len); 102 + else 103 + mon_recv_encrypted(dev, data, data_len); 104 + } 105 + 106 + /** 107 + * rtl88eu_mon_xmit_hook() - forward trasmitted frame to the monitor interface 108 + * 109 + * Assumes that: 110 + * - frame header contains an IV and frame->attrib.iv_len is set accordingly, 111 + * - data is not encrypted and ICV/MIC has not been appended yet. 112 + */ 113 + void rtl88eu_mon_xmit_hook(struct net_device *dev, struct xmit_frame *frame, 114 + uint frag_len) 115 + { 116 + struct pkt_attrib *attr; 117 + u8 *data; 118 + int i, offset; 119 + 120 + if (!dev || !frame) 121 + return; 122 + if (!netif_running(dev)) 123 + return; 124 + 125 + attr = &frame->attrib; 126 + 127 + offset = TXDESC_SIZE + frame->pkt_offset * PACKET_OFFSET_SZ; 128 + data = frame->buf_addr + offset; 129 + 130 + for (i = 0; i < attr->nr_frags - 1; i++) { 131 + mon_recv_decrypted(dev, data, frag_len, attr->iv_len, 0); 132 + data += frag_len; 133 + data = (u8 *)round_up((size_t)data, 4); 134 + } 135 + /* Last fragment has different length */ 136 + mon_recv_decrypted(dev, data, attr->last_txcmdsz, attr->iv_len, 0); 137 + } 138 + 139 + static netdev_tx_t mon_xmit(struct sk_buff *skb, struct net_device *dev) 140 + { 141 + dev_kfree_skb(skb); 142 + return NETDEV_TX_OK; 143 + } 144 + 145 + static const struct net_device_ops mon_netdev_ops = { 146 + .ndo_start_xmit = mon_xmit, 147 + .ndo_change_mtu = eth_change_mtu, 148 + .ndo_set_mac_address = eth_mac_addr, 149 + .ndo_validate_addr = eth_validate_addr, 150 + }; 151 + 152 + static void mon_setup(struct net_device *dev) 153 + { 154 + dev->netdev_ops = &mon_netdev_ops; 155 + dev->destructor = free_netdev; 156 + ether_setup(dev); 157 + dev->tx_queue_len = 0; 158 + dev->type = ARPHRD_IEEE80211; 159 + /* 160 + * Use a locally administered address (IEEE 802) 161 + * XXX: Copied from mac80211_hwsim driver. Revisit. 162 + */ 163 + eth_zero_addr(dev->dev_addr); 164 + dev->dev_addr[0] = 0x12; 165 + } 166 + 167 + struct net_device *rtl88eu_mon_init(void) 168 + { 169 + struct net_device *dev; 170 + int err; 171 + 172 + dev = alloc_netdev(0, "mon%d", NET_NAME_UNKNOWN, mon_setup); 173 + if (!dev) 174 + goto fail; 175 + 176 + err = register_netdev(dev); 177 + if (err < 0) 178 + goto fail_free_dev; 179 + 180 + return dev; 181 + 182 + fail_free_dev: 183 + free_netdev(dev); 184 + fail: 185 + return NULL; 186 + } 187 + 188 + void rtl88eu_mon_deinit(struct net_device *dev) 189 + { 190 + if (!dev) 191 + return; 192 + 193 + unregister_netdev(dev); 194 + }
+5
drivers/staging/rtl8188eu/os_dep/os_intfs.c
··· 185 185 module_param_named(debug, rtw_debug, int, 0444); 186 186 MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)"); 187 187 188 + static bool rtw_monitor_enable; 189 + module_param_named(monitor_enable, rtw_monitor_enable, bool, 0444); 190 + MODULE_PARM_DESC(monitor_enable, "Enable monitor inferface (default: false)"); 191 + 188 192 static int netdev_open(struct net_device *pnetdev); 189 193 static int netdev_close(struct net_device *pnetdev); 190 194 ··· 608 604 snprintf(registry_par->ifname, 16, "%s", ifname); 609 605 snprintf(registry_par->if2name, 16, "%s", if2name); 610 606 registry_par->notch_filter = (u8)rtw_notch_filter; 607 + registry_par->monitor_enable = rtw_monitor_enable; 611 608 } 612 609 613 610 static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p)
+10
drivers/staging/rtl8188eu/os_dep/usb_intf.c
··· 26 26 #include <hal_intf.h> 27 27 #include <linux/usb.h> 28 28 #include <linux/vmalloc.h> 29 + #include <mon.h> 29 30 #include <osdep_intf.h> 30 31 31 32 #include <usb_ops_linux.h> ··· 349 348 { 350 349 struct adapter *padapter = NULL; 351 350 struct net_device *pnetdev = NULL; 351 + struct net_device *pmondev; 352 352 int status = _FAIL; 353 353 354 354 padapter = (struct adapter *)vzalloc(sizeof(*padapter)); ··· 367 365 goto free_adapter; 368 366 SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); 369 367 padapter = rtw_netdev_priv(pnetdev); 368 + 369 + if (padapter->registrypriv.monitor_enable) { 370 + pmondev = rtl88eu_mon_init(); 371 + if (pmondev == NULL) 372 + netdev_warn(pnetdev, "Failed to initialize monitor interface"); 373 + padapter->pmondev = pmondev; 374 + } 370 375 371 376 /* step 2. hook HalFunc, allocate HalData */ 372 377 hal_set_hal_ops(padapter); ··· 467 458 unregister_netdev(pnetdev); 468 459 rtw_proc_remove_one(pnetdev); 469 460 } 461 + rtl88eu_mon_deinit(if1->pmondev); 470 462 rtw_cancel_all_timer(if1); 471 463 472 464 rtw_dev_unload(if1);