/****************************************************************************** * * Copyright(c) 2019 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #include static const u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; #ifdef RTW_PHL_TEST_FPGA static const u8 ap_addr[ETH_ALEN] = {0x00, 0xe0, 0x4c, 0x88, 0x52, 0xa0}; u8 ap_ssid[] = {'p','h','l','-','5','g'}; #else static const u8 ap_addr[ETH_ALEN] = {0x00, 0xe0, 0x4c, 0x12, 0x34, 0x56}; u8 ap_ssid[] = {'f','a','k','e','a','p'}; #endif u8 ap_ch = 1; u16 ap_beacon_interval = 100; /* unit: ms */ u16 ap_capability_info = 0x0001; u8 ap_datarate[] = {0x82, 0x84, 0x8b, 0x96, 0xc, 0x12, 0x18, 0x24}; int rtw_fakeap_tx(struct _ADAPTER *a, struct xmit_frame *frame) { u8 *data = frame->buf_addr + TXDESC_OFFSET; u32 data_len = frame->attrib.last_txcmdsz; struct sk_buff *skb; u8 *buf; if (GetFrameType(data) != WIFI_MGT_TYPE) return _FAIL; switch (get_frame_sub_type(data)) { case WIFI_AUTH: case WIFI_ASSOCREQ: case WIFI_REASSOCREQ: case WIFI_PROBEREQ: break; default: return _FAIL; } skb = rtw_skb_alloc(data_len); buf = skb_put(skb, data_len); _rtw_memcpy(buf, data, data_len); rtw_free_xmitbuf(&a->xmitpriv, frame->pxmitbuf); rtw_free_xmitframe(&a->xmitpriv, frame); skb_queue_tail(&adapter_to_dvobj(a)->fakeap.rxq, skb); _set_workitem(&adapter_to_dvobj(a)->fakeap.work); return _SUCCESS; } static void add_ie(struct sk_buff *skb, u8 index, u8 len, const u8 *source) { u8 *buf; buf = skb_put(skb, 2 + len); *buf = index; *(buf + 1) = len; if (len > 0) _rtw_memcpy(buf + 2, source, len); } void rtw_fakeap_bcn_timer_hdl(void *p) { struct dvobj_priv *d; struct sk_buff *skb; struct rtw_ieee80211_hdr *wlanhdr; int len; u8 *buf; u8 hdrlen; d = (struct dvobj_priv*)p; hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); len = hdrlen + _FIXED_IE_LENGTH_ + 2 + sizeof(ap_ssid) + 2 + sizeof(ap_datarate) + 2 + 1; skb = rtw_skb_alloc(len); _rtw_memset(skb->data, 0, len); buf = skb_put(skb, hdrlen); wlanhdr = (struct rtw_ieee80211_hdr*)buf; set_frame_sub_type(&wlanhdr->frame_ctl, WIFI_BEACON); _rtw_memcpy(wlanhdr->addr1, bcast_addr, ETH_ALEN); _rtw_memcpy(wlanhdr->addr2, ap_addr, ETH_ALEN); _rtw_memcpy(wlanhdr->addr3, ap_addr, ETH_ALEN); buf = skb_put(skb, _FIXED_IE_LENGTH_); /* timestamp: 8 bytes */ /* beacon interval: 2 bytes */ *(u16*)(buf + 8) = ap_beacon_interval; /* capability info: 2 bytes */ *(u16*)(buf + 10) = ap_capability_info; /* SSID */ add_ie(skb, _SSID_IE_, sizeof(ap_ssid), ap_ssid); /* supported rates... */ add_ie(skb, _SUPPORTEDRATES_IE_, sizeof(ap_datarate), ap_datarate); /* DS parameter set */ add_ie(skb, _DSSET_IE_, 1, &ap_ch); skb_queue_tail(&d->fakeap.rxq, skb); _set_workitem(&d->fakeap.work); } static void rx_prepare(struct _ADAPTER *adapter, union recv_frame *r) { struct rx_pkt_attrib *a; /* init recv_frame */ _rtw_init_listhead(&r->u.hdr.list); r->u.hdr.len = 0; a = &r->u.hdr.attrib; _rtw_memset(a, 0, sizeof(*a)); /* fill sec related attrib, iv_len and icv_len will be filled by * validate_recv_data_frame() */ a->crc_err = 0; a->icv_err = 0; a->encrypt = 0; /* fill rx pkt attrib */ a->hdrlen = 0; a->bw = CHANNEL_WIDTH_MAX; a->pkt_len = 0; a->pkt_rpt_type = NORMAL_RX; a->drvinfo_sz = 0; a->bdecrypted = 0; a->qos = 0; a->priority = 0; a->amsdu = 0; a->mdata = 0; a->mfrag = 0; a->seq_num = 0; a->frag_num = 0; a->data_rate = DESC_RATE6M; a->ppdu_cnt = 1; a->free_cnt = 0; } static union recv_frame* gen_probersp(struct _ADAPTER *a) { union recv_frame *r; u32 len; struct sk_buff *skb; struct rtw_ieee80211_hdr *wlanhdr; u8 *buf; u8 hdrlen; u8 ielen; r = rtw_alloc_recvframe(&a->recvpriv.free_recv_queue); if (!r) { RTW_ERR("%s: alloc recvframe failed!\n", __func__); return NULL; } rtw_init_recvframe(r, &a->recvpriv); rx_prepare(a, r); hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); len = RXDESC_OFFSET + hdrlen + _CAPABILITY_ + _STATUS_CODE_ + _ASOC_ID_ + 2 + sizeof(ap_ssid) + 2 + sizeof(ap_datarate) + 2 + 1; skb = rtw_skb_alloc(len); _rtw_memset(skb->data, 0, len); skb->dev = a->pnetdev; skb_reserve(skb, RXDESC_OFFSET); r->u.hdr.pkt = skb; buf = skb_put(skb, hdrlen); wlanhdr = (struct rtw_ieee80211_hdr*)buf; set_frame_sub_type(&wlanhdr->frame_ctl, WIFI_PROBERSP); _rtw_memcpy(wlanhdr->addr1, adapter_mac_addr(a), ETH_ALEN); _rtw_memcpy(wlanhdr->addr2, ap_addr, ETH_ALEN); _rtw_memcpy(wlanhdr->addr3, ap_addr, ETH_ALEN); buf = skb_put(skb, _FIXED_IE_LENGTH_); /* timestamp: 8 bytes */ /* beacon interval: 2 bytes */ *(u16*)(buf + 8) = ap_beacon_interval; /* capability info: 2 bytes */ *(u16*)(buf + 10) = ap_capability_info; /* SSID */ add_ie(skb, _SSID_IE_, sizeof(ap_ssid), ap_ssid); /* supported rates... */ add_ie(skb, _SUPPORTEDRATES_IE_, sizeof(ap_datarate), ap_datarate); /* DS parameter set */ add_ie(skb, _DSSET_IE_, 1, &ap_ch); /* handle r->u.hdr.attrib */ /* handle recv_frame pointer */ r->u.hdr.len = skb->len; r->u.hdr.rx_head = skb->head; r->u.hdr.rx_data = skb->data; r->u.hdr.rx_tail = skb_tail_pointer(skb); r->u.hdr.rx_end = skb_end_pointer(skb); return r; } static union recv_frame* gen_beacon(struct _ADAPTER *a, struct sk_buff *beacon) { union recv_frame *r; u32 len; struct sk_buff *skb; struct rtw_ieee80211_hdr *wlanhdr; u8 *buf; u8 hdrlen; r = rtw_alloc_recvframe(&a->recvpriv.free_recv_queue); if (!r) { RTW_ERR("%s: alloc recvframe failed!\n", __func__); return NULL; } rtw_init_recvframe(r, &a->recvpriv); rx_prepare(a, r); hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); len = RXDESC_OFFSET + beacon->len; skb = rtw_skb_alloc(len); _rtw_memset(skb->data, 0, len); skb->dev = a->pnetdev; skb_reserve(skb, RXDESC_OFFSET); r->u.hdr.pkt = skb; buf = skb_put(skb, beacon->len); _rtw_memcpy(buf, beacon->data, beacon->len); /* handle r->u.hdr.attrib */ /* handle recv_frame pointer */ r->u.hdr.len = skb->len; r->u.hdr.rx_head = skb->head; r->u.hdr.rx_data = skb->data; r->u.hdr.rx_tail = skb_tail_pointer(skb); r->u.hdr.rx_end = skb_end_pointer(skb); return r; } static union recv_frame *gen_auth(struct _ADAPTER *a, u8 *bssid) { union recv_frame *r; u32 len; struct sk_buff *skb; struct rtw_ieee80211_hdr *wlanhdr; u8 *buf; u8 hdrlen; r = rtw_alloc_recvframe(&a->recvpriv.free_recv_queue); if (!r) { RTW_ERR("%s: alloc recvframe failed!\n", __func__); return NULL; } rtw_init_recvframe(r, &a->recvpriv); rx_prepare(a, r); hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); len = RXDESC_OFFSET + hdrlen + _AUTH_ALGM_NUM_ + _AUTH_SEQ_NUM_ + _STATUS_CODE_; skb = rtw_skb_alloc(len); _rtw_memset(skb->data, 0, len); skb->dev = a->pnetdev; skb_reserve(skb, RXDESC_OFFSET); r->u.hdr.pkt = skb; buf = skb_put(skb, hdrlen); wlanhdr = (struct rtw_ieee80211_hdr*)buf; set_frame_sub_type(&wlanhdr->frame_ctl, WIFI_AUTH); _rtw_memcpy(wlanhdr->addr1, adapter_mac_addr(a), ETH_ALEN); _rtw_memcpy(wlanhdr->addr2, bssid, ETH_ALEN); _rtw_memcpy(wlanhdr->addr3, bssid, ETH_ALEN); /* setting auth algo number */ buf = skb_put(skb, _AUTH_ALGM_NUM_); *(u16*)buf = cpu_to_le16(0);; /* setting auth seq number */ buf = skb_put(skb, _AUTH_SEQ_NUM_); *(u16*)buf = cpu_to_le16(2); /* setting status code... */ buf = skb_put(skb, _STATUS_CODE_); *(u16*)buf = cpu_to_le16(0); /* handle r->u.hdr.attrib */ /* handle recv_frame pointer */ r->u.hdr.len = skb->len; r->u.hdr.rx_head = skb->head; r->u.hdr.rx_data = skb->data; r->u.hdr.rx_tail = skb_tail_pointer(skb); r->u.hdr.rx_end = skb_end_pointer(skb); return r; } static union recv_frame *gen_assocrsp(struct _ADAPTER *a, u8 *bssid) { union recv_frame *r; u32 len; struct sk_buff *skb; struct rtw_ieee80211_hdr *wlanhdr; u8 *buf; u8 hdrlen; r = rtw_alloc_recvframe(&a->recvpriv.free_recv_queue); if (!r) { RTW_ERR("%s: alloc recvframe failed!\n", __func__); return NULL; } rtw_init_recvframe(r, &a->recvpriv); rx_prepare(a, r); hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); len = RXDESC_OFFSET + hdrlen + _CAPABILITY_ + _STATUS_CODE_ + _ASOC_ID_ + 2 + sizeof(ap_datarate); skb = rtw_skb_alloc(len); _rtw_memset(skb->data, 0, len); skb->dev = a->pnetdev; skb_reserve(skb, RXDESC_OFFSET); r->u.hdr.pkt = skb; buf = skb_put(skb, hdrlen); wlanhdr = (struct rtw_ieee80211_hdr*)buf; set_frame_sub_type(&wlanhdr->frame_ctl, WIFI_ASSOCRSP); _rtw_memcpy(wlanhdr->addr1, adapter_mac_addr(a), ETH_ALEN); _rtw_memcpy(wlanhdr->addr2, bssid, ETH_ALEN); _rtw_memcpy(wlanhdr->addr3, bssid, ETH_ALEN); /* capability info: 2 bytes */ buf = skb_put(skb, _CAPABILITY_); *(u16*)buf = ap_capability_info; /* status code: 2 bytes */ buf = skb_put(skb, _STATUS_CODE_); *(u16*)buf = 0; /* AID: 2 bytes */ buf = skb_put(skb, _ASOC_ID_); *(u16*)buf = 100; /* supported rates... */ add_ie(skb, _SUPPORTEDRATES_IE_, sizeof(ap_datarate), ap_datarate); /* handle r->u.hdr.attrib */ /* handle recv_frame pointer */ r->u.hdr.len = skb->len; r->u.hdr.rx_head = skb->head; r->u.hdr.rx_data = skb->data; r->u.hdr.rx_tail = skb_tail_pointer(skb); r->u.hdr.rx_end = skb_end_pointer(skb); // recvframe_put(r, buflen); // pre_recv_entry(r, NULL); return r; } static union recv_frame* fakeap_dispatcher(struct _ADAPTER *a, struct sk_buff *skb) { u8 *pframe; union recv_frame *rframe = NULL; pframe = skb->data; RTW_INFO("A1-" MAC_FMT "\n", MAC_ARG(GetAddr1Ptr(pframe))); RTW_INFO("A2-" MAC_FMT "\n", MAC_ARG(get_addr2_ptr(pframe))); RTW_INFO("A3-" MAC_FMT "\n", MAC_ARG(GetAddr3Ptr(pframe))); if (GetFrameType(pframe) != WIFI_MGT_TYPE) return NULL; switch (get_frame_sub_type(pframe)) { case WIFI_AUTH: { u16 algo, seq; algo = le16_to_cpu(*(u16 *)(pframe + WLAN_HDR_A3_LEN)); seq = le16_to_cpu(*(u16 *)(pframe + WLAN_HDR_A3_LEN + 2)); if ((algo == 0) && (seq == 1)) rframe = gen_auth(a, GetAddr1Ptr(pframe)); } break; case WIFI_ASSOCREQ: case WIFI_REASSOCREQ: rframe = gen_assocrsp(a, GetAddr1Ptr(pframe)); break; case WIFI_PROBEREQ: rframe = gen_probersp(a); break; case WIFI_BEACON: rframe = gen_beacon(a, skb); default: break; } return rframe; } extern sint validate_recv_frame(struct _ADAPTER*, union recv_frame*); void rtw_fakeap_work(struct work_struct *work) { struct dvobj_priv *d; struct _ADAPTER *a; struct sk_buff_head *pktq; struct sk_buff *skb, *tmp; u8 *ta, *ra; union recv_frame *rframe; int i; d = container_of(work, struct dvobj_priv, fakeap.work); pktq = &d->fakeap.rxq; skb_queue_walk_safe(pktq, skb, tmp) { __skb_unlink(skb, pktq); ta = get_addr2_ptr(skb->data); ra = GetAddr1Ptr(skb->data); if (is_broadcast_mac_addr(ra) && (_rtw_memcmp(ta, ap_addr, ETH_ALEN)==_TRUE) && (get_frame_sub_type(skb->data) == WIFI_BEACON)) { for (i = 0; i < d->iface_nums; i++) { a = d->padapters[i]; if (a) { rframe = fakeap_dispatcher(a, skb); if (rframe) { validate_recv_frame(a, rframe); rframe = NULL; } } } } else { a = rtw_get_iface_by_macddr(dvobj_get_primary_adapter(d), ta); if (a) rframe = fakeap_dispatcher(a, skb); } rtw_skb_free(skb); if (rframe) { validate_recv_frame(a, rframe); rframe = NULL; } } }