1fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt/* 2fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface 3fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> 4fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2003-2004, Instant802 Networks, Inc. 5fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2005-2006, Devicescape Software, Inc. 6fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> 7fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications 8fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * 9fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 10fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * See README for more details. 11fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 12fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "includes.h" 14fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <netpacket/packet.h> 15fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <linux/filter.h> 16fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 17fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/common.h" 18fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/eloop.h" 19fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "common/ieee802_11_defs.h" 20fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "common/ieee802_11_common.h" 21fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "linux_ioctl.h" 22fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "radiotap_iter.h" 23fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "driver_nl80211.h" 24fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 25fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 26fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) 27fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 28fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct ieee80211_hdr *hdr; 29fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u16 fc; 30fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt union wpa_event_data event; 31fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 32fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt hdr = (struct ieee80211_hdr *) buf; 33fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt fc = le_to_host16(hdr->frame_control); 34fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 35fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memset(&event, 0, sizeof(event)); 36fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.tx_status.type = WLAN_FC_GET_TYPE(fc); 37fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.tx_status.stype = WLAN_FC_GET_STYPE(fc); 38fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.tx_status.dst = hdr->addr1; 39fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.tx_status.data = buf; 40fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.tx_status.data_len = len; 41fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.tx_status.ack = ok; 42fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); 43fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 44fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 45fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 46fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void from_unknown_sta(struct wpa_driver_nl80211_data *drv, 47fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 *buf, size_t len) 48fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 49fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct ieee80211_hdr *hdr = (void *)buf; 50fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u16 fc; 51fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt union wpa_event_data event; 52fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 53fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (len < sizeof(*hdr)) 54fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 55fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 56fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt fc = le_to_host16(hdr->frame_control); 57fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 58fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memset(&event, 0, sizeof(event)); 59fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len); 60fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_from_unknown.addr = hdr->addr2; 61fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) == 62fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (WLAN_FC_FROMDS | WLAN_FC_TODS); 63fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); 64fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 65fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 66fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 67fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_frame(struct wpa_driver_nl80211_data *drv, 68fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 *buf, size_t len, int datarate, int ssi_signal) 69fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 70fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct ieee80211_hdr *hdr; 71fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u16 fc; 72fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt union wpa_event_data event; 73fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 74fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt hdr = (struct ieee80211_hdr *) buf; 75fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt fc = le_to_host16(hdr->frame_control); 76fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 77fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt switch (WLAN_FC_GET_TYPE(fc)) { 78fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case WLAN_FC_TYPE_MGMT: 79fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memset(&event, 0, sizeof(event)); 80fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_mgmt.frame = buf; 81fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_mgmt.frame_len = len; 82fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_mgmt.datarate = datarate; 83fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt event.rx_mgmt.ssi_signal = ssi_signal; 84fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); 85fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 86fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case WLAN_FC_TYPE_CTRL: 87fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* can only get here with PS-Poll frames */ 88fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "CTRL"); 89fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt from_unknown_sta(drv, buf, len); 90fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 91fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case WLAN_FC_TYPE_DATA: 92fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt from_unknown_sta(drv, buf, len); 93fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 94fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 95fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 96fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 97fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 98fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) 99fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 100fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_driver_nl80211_data *drv = eloop_ctx; 101fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int len; 102fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned char buf[3000]; 103fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct ieee80211_radiotap_iterator iter; 104fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int ret; 105fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int datarate = 0, ssi_signal = 0; 106fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int injected = 0, failed = 0, rxflags = 0; 107fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 108fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt len = recv(sock, buf, sizeof(buf), 0); 109fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (len < 0) { 110fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s", 111fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt strerror(errno)); 112fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 113fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 114fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 115fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) { 116fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame"); 117fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 118fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 119fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 120fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt while (1) { 121fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ret = ieee80211_radiotap_iterator_next(&iter); 122fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (ret == -ENOENT) 123fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 124fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (ret) { 125fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)", 126fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ret); 127fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 128fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 129fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt switch (iter.this_arg_index) { 130fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_FLAGS: 131fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) 132fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt len -= 4; 133fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 134fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_RX_FLAGS: 135fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rxflags = 1; 136fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 137fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_TX_FLAGS: 138fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt injected = 1; 139fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt failed = le_to_host16((*(uint16_t *) iter.this_arg)) & 140fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt IEEE80211_RADIOTAP_F_TX_FAIL; 141fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 142fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_DATA_RETRIES: 143fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 144fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_CHANNEL: 145fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* TODO: convert from freq/flags to channel number */ 146fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 147fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_RATE: 148fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt datarate = *iter.this_arg * 5; 149fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 150fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 151fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ssi_signal = (s8) *iter.this_arg; 152fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt break; 153fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 154fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 155fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 156fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (rxflags && injected) 157fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 158fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 159fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!injected) 160fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt handle_frame(drv, buf + iter._max_length, 161fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt len - iter._max_length, datarate, ssi_signal); 162fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else 163fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt handle_tx_callback(drv->ctx, buf + iter._max_length, 164fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt len - iter._max_length, !failed); 165fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 166fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 167fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 168fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt/* 169fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * we post-process the filter code later and rewrite 170fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * this to the offset to the last instruction 171fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 172fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#define PASS 0xFF 173fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#define FAIL 0xFE 174fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 175fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct sock_filter msock_filter_insns[] = { 176fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 177fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * do a little-endian load of the radiotap length field 178fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 179fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load lower byte into A */ 180fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), 181fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* put it into X (== index register) */ 182fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_MISC| BPF_TAX, 0), 183fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load upper byte into A */ 184fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), 185fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* left-shift it by 8 */ 186fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), 187fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* or with X */ 188fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), 189fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* put result into X */ 190fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_MISC| BPF_TAX, 0), 191fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 192fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 193fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Allow management frames through, this also gives us those 194fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * management frames that we sent ourselves with status 195fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 196fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load the lower byte of the IEEE 802.11 frame control field */ 197fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), 198fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* mask off frame type and version */ 199fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), 200fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* accept frame if it's both 0, fall through otherwise */ 201fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), 202fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 203fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 204fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * TODO: add a bit to radiotap RX flags that indicates 205fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * that the sending station is not associated, then 206fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * add a filter here that filters on our DA and that flag 207fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * to allow us to deauth frames to that bad station. 208fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * 209fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * For now allow all To DS data frames through. 210fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 211fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load the IEEE 802.11 frame control field */ 212fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0), 213fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* mask off frame type, version and DS status */ 214fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03), 215fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* accept frame if version 0, type 2 and To DS, fall through otherwise 216fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 217fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0), 218fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 219fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#if 0 220fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 221fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * drop non-data frames 222fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 223fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load the lower byte of the frame control field */ 224fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), 225fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* mask off QoS bit */ 226fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), 227fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* drop non-data frames */ 228fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), 229fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#endif 230fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load the upper byte of the frame control field */ 231fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), 232fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* mask off toDS/fromDS */ 233fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), 234fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* accept WDS frames */ 235fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), 236fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 237fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 238fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * add header length to index 239fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 240fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* load the lower byte of the frame control field */ 241fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), 242fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* mask off QoS bit */ 243fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), 244fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* right shift it by 6 to give 0 or 2 */ 245fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), 246fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* add data frame header length */ 247fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), 248fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* add index, was start of 802.11 header */ 249fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), 250fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* move to index, now start of LL header */ 251fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_MISC | BPF_TAX, 0), 252fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 253fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 254fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Accept empty data frames, we use those for 255fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * polling activity. 256fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 257fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), 258fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), 259fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 260fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 261fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Accept EAPOL frames 262fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 263fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), 264fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), 265fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), 266fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), 267fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 268fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* keep these last two statements or change the code below */ 269fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* return 0 == "DROP" */ 270fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_RET | BPF_K, 0), 271fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* return ~0 == "keep all" */ 272fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt BPF_STMT(BPF_RET | BPF_K, ~0), 273fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}; 274fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 275fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct sock_fprog msock_filter = { 276fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .len = ARRAY_SIZE(msock_filter_insns), 277fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .filter = msock_filter_insns, 278fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}; 279fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 280fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 281fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int add_monitor_filter(int s) 282fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 283fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int idx; 284fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 285fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* rewrite all PASS/FAIL jump offsets */ 286fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (idx = 0; idx < msock_filter.len; idx++) { 287fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct sock_filter *insn = &msock_filter_insns[idx]; 288fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 289fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (BPF_CLASS(insn->code) == BPF_JMP) { 290fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (insn->code == (BPF_JMP|BPF_JA)) { 291fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (insn->k == PASS) 292fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt insn->k = msock_filter.len - idx - 2; 293fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else if (insn->k == FAIL) 294fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt insn->k = msock_filter.len - idx - 3; 295fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 296fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 297fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (insn->jt == PASS) 298fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt insn->jt = msock_filter.len - idx - 2; 299fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else if (insn->jt == FAIL) 300fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt insn->jt = msock_filter.len - idx - 3; 301fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 302fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (insn->jf == PASS) 303fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt insn->jf = msock_filter.len - idx - 2; 304fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else if (insn->jf == FAIL) 305fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt insn->jf = msock_filter.len - idx - 3; 306fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 307fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 308fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 309fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, 310fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &msock_filter, sizeof(msock_filter))) { 311fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s", 312fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt strerror(errno)); 313fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 314fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 315fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 316fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 317fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 318fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 319fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 320fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtvoid nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv) 321fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 322fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_refcount > 0) 323fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_refcount--; 324fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d", 325fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_refcount); 326fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_refcount > 0) 327fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 328fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 329fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_ifidx >= 0) { 330fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nl80211_remove_iface(drv, drv->monitor_ifidx); 331fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_ifidx = -1; 332fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 333fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_sock >= 0) { 334fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt eloop_unregister_read_sock(drv->monitor_sock); 335fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt close(drv->monitor_sock); 336fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_sock = -1; 337fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 338fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 339fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 340fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 341fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) 342fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 343fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt char buf[IFNAMSIZ]; 344fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct sockaddr_ll ll; 345fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int optval; 346fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt socklen_t optlen; 347fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 348fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_ifidx >= 0) { 349fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_refcount++; 350fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d", 351fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_refcount); 352fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 353fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 354fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 355fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) { 356fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 357fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * P2P interface name is of the format p2p-%s-%d. For monitor 358fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * interface name corresponding to P2P GO, replace "p2p-" with 359fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * "mon-" to retain the same interface name length and to 360fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * indicate that it is a monitor interface. 361fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 362fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4); 363fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } else { 364fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Non-P2P interface with AP functionality. */ 365fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname); 366fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 367fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 368fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt buf[IFNAMSIZ - 1] = '\0'; 369fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 370fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_ifidx = 371fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, 372fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0, NULL, NULL, 0); 373fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 374fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_ifidx == -EOPNOTSUPP) { 375fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 376fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * This is backward compatibility for a few versions of 377fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * the kernel only that didn't advertise the right 378fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * attributes for the only driver that then supported 379fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * AP mode w/o monitor -- ath6kl. 380fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 381fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Driver does not support " 382fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "monitor interface type - try to run without it"); 383fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->device_ap_sme = 1; 384fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 385fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 386fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_ifidx < 0) 387fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 388fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 389fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1)) 390fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto error; 391fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 392fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt memset(&ll, 0, sizeof(ll)); 393fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ll.sll_family = AF_PACKET; 394fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ll.sll_ifindex = drv->monitor_ifidx; 395fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 396fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_sock < 0) { 397fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s", 398fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt strerror(errno)); 399fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto error; 400fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 401fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 402fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (add_monitor_filter(drv->monitor_sock)) { 403fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " 404fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "interface; do filtering in user space"); 405fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* This works, but will cost in performance. */ 406fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 407fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 408fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { 409fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s", 410fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt strerror(errno)); 411fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto error; 412fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 413fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 414fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt optlen = sizeof(optval); 415fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt optval = 20; 416fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (setsockopt 417fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { 418fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s", 419fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt strerror(errno)); 420fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto error; 421fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 422fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 423fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, 424fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv, NULL)) { 425fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket"); 426fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto error; 427fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 428fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 429fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt drv->monitor_refcount++; 430fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 431fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt error: 432fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nl80211_remove_monitor_interface(drv); 433fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 434fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 435fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 436fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 437fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint nl80211_send_monitor(struct wpa_driver_nl80211_data *drv, 438fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const void *data, size_t len, 439fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int encrypt, int noack) 440fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 441fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt __u8 rtap_hdr[] = { 442fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0x00, 0x00, /* radiotap version */ 443fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0x0e, 0x00, /* radiotap length */ 444fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ 445fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ 446fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0x00, /* padding */ 447fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0x00, 0x00, /* RX and TX flags to indicate that */ 448fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0x00, 0x00, /* this is the injected frame directly */ 449fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt }; 450fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct iovec iov[2] = { 451fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt { 452fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .iov_base = &rtap_hdr, 453fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .iov_len = sizeof(rtap_hdr), 454fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt }, 455fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt { 456fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .iov_base = (void *) data, 457fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .iov_len = len, 458fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 459fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt }; 460fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct msghdr msg = { 461fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_name = NULL, 462fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_namelen = 0, 463fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_iov = iov, 464fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_iovlen = 2, 465fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_control = NULL, 466fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_controllen = 0, 467fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt .msg_flags = 0, 468fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt }; 469fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int res; 470fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u16 txflags = 0; 471fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 472fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (encrypt) 473fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; 474fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 475fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (drv->monitor_sock < 0) { 476fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available " 477fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "for %s", __func__); 478fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 479fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 480fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 481fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (noack) 482fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt txflags |= IEEE80211_RADIOTAP_F_TX_NOACK; 483fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WPA_PUT_LE16(&rtap_hdr[12], txflags); 484fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 485fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt res = sendmsg(drv->monitor_sock, &msg, 0); 486fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (res < 0) { 487fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno)); 488fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 489fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 490fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 491fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 492