cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wlan_cfg.c (8664B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
      4 * All rights reserved.
      5 */
      6
      7#include <linux/bitfield.h>
      8#include "wlan_if.h"
      9#include "wlan.h"
     10#include "wlan_cfg.h"
     11#include "netdev.h"
     12
     13enum cfg_cmd_type {
     14	CFG_BYTE_CMD	= 0,
     15	CFG_HWORD_CMD	= 1,
     16	CFG_WORD_CMD	= 2,
     17	CFG_STR_CMD	= 3,
     18	CFG_BIN_CMD	= 4
     19};
     20
     21static const struct wilc_cfg_byte g_cfg_byte[] = {
     22	{WID_STATUS, 0},
     23	{WID_RSSI, 0},
     24	{WID_LINKSPEED, 0},
     25	{WID_WOWLAN_TRIGGER, 0},
     26	{WID_NIL, 0}
     27};
     28
     29static const struct wilc_cfg_hword g_cfg_hword[] = {
     30	{WID_NIL, 0}
     31};
     32
     33static const struct wilc_cfg_word g_cfg_word[] = {
     34	{WID_FAILED_COUNT, 0},
     35	{WID_RECEIVED_FRAGMENT_COUNT, 0},
     36	{WID_SUCCESS_FRAME_COUNT, 0},
     37	{WID_GET_INACTIVE_TIME, 0},
     38	{WID_NIL, 0}
     39
     40};
     41
     42static const struct wilc_cfg_str g_cfg_str[] = {
     43	{WID_FIRMWARE_VERSION, NULL},
     44	{WID_MAC_ADDR, NULL},
     45	{WID_ASSOC_RES_INFO, NULL},
     46	{WID_NIL, NULL}
     47};
     48
     49#define WILC_RESP_MSG_TYPE_CONFIG_REPLY		'R'
     50#define WILC_RESP_MSG_TYPE_STATUS_INFO		'I'
     51#define WILC_RESP_MSG_TYPE_NETWORK_INFO		'N'
     52#define WILC_RESP_MSG_TYPE_SCAN_COMPLETE	'S'
     53
     54/********************************************
     55 *
     56 *      Configuration Functions
     57 *
     58 ********************************************/
     59
     60static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8)
     61{
     62	if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE)
     63		return 0;
     64
     65	put_unaligned_le16(id, &frame[offset]);
     66	put_unaligned_le16(1, &frame[offset + 2]);
     67	frame[offset + 4] = val8;
     68	return 5;
     69}
     70
     71static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
     72{
     73	if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE)
     74		return 0;
     75
     76	put_unaligned_le16(id, &frame[offset]);
     77	put_unaligned_le16(2, &frame[offset + 2]);
     78	put_unaligned_le16(val16, &frame[offset + 4]);
     79
     80	return 6;
     81}
     82
     83static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
     84{
     85	if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE)
     86		return 0;
     87
     88	put_unaligned_le16(id, &frame[offset]);
     89	put_unaligned_le16(4, &frame[offset + 2]);
     90	put_unaligned_le32(val32, &frame[offset + 4]);
     91
     92	return 8;
     93}
     94
     95static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
     96				 u32 size)
     97{
     98	if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE)
     99		return 0;
    100
    101	put_unaligned_le16(id, &frame[offset]);
    102	put_unaligned_le16(size, &frame[offset + 2]);
    103	if (str && size != 0)
    104		memcpy(&frame[offset + 4], str, size);
    105
    106	return (size + 4);
    107}
    108
    109static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
    110{
    111	u32 i;
    112	u8 checksum = 0;
    113
    114	if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE)
    115		return 0;
    116
    117	put_unaligned_le16(id, &frame[offset]);
    118	put_unaligned_le16(size, &frame[offset + 2]);
    119
    120	if ((b) && size != 0) {
    121		memcpy(&frame[offset + 4], b, size);
    122		for (i = 0; i < size; i++)
    123			checksum += frame[offset + i + 4];
    124	}
    125
    126	frame[offset + size + 4] = checksum;
    127
    128	return (size + 5);
    129}
    130
    131/********************************************
    132 *
    133 *      Configuration Response Functions
    134 *
    135 ********************************************/
    136
    137static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size)
    138{
    139	u16 wid;
    140	u32 len = 0, i = 0;
    141	struct wilc_cfg *cfg = &wl->cfg;
    142
    143	while (size > 0) {
    144		i = 0;
    145		wid = get_unaligned_le16(info);
    146
    147		switch (FIELD_GET(WILC_WID_TYPE, wid)) {
    148		case WID_CHAR:
    149			while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid)
    150				i++;
    151
    152			if (cfg->b[i].id == wid)
    153				cfg->b[i].val = info[4];
    154
    155			len = 3;
    156			break;
    157
    158		case WID_SHORT:
    159			while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid)
    160				i++;
    161
    162			if (cfg->hw[i].id == wid)
    163				cfg->hw[i].val = get_unaligned_le16(&info[4]);
    164
    165			len = 4;
    166			break;
    167
    168		case WID_INT:
    169			while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid)
    170				i++;
    171
    172			if (cfg->w[i].id == wid)
    173				cfg->w[i].val = get_unaligned_le32(&info[4]);
    174
    175			len = 6;
    176			break;
    177
    178		case WID_STR:
    179			while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid)
    180				i++;
    181
    182			if (cfg->s[i].id == wid)
    183				memcpy(cfg->s[i].str, &info[2], info[2] + 2);
    184
    185			len = 2 + info[2];
    186			break;
    187
    188		default:
    189			break;
    190		}
    191		size -= (2 + len);
    192		info += (2 + len);
    193	}
    194}
    195
    196static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info)
    197{
    198	u32 wid, len;
    199
    200	wid = get_unaligned_le16(info);
    201
    202	len = info[2];
    203
    204	if (len == 1 && wid == WID_STATUS) {
    205		int i = 0;
    206
    207		while (wl->cfg.b[i].id != WID_NIL &&
    208		       wl->cfg.b[i].id != wid)
    209			i++;
    210
    211		if (wl->cfg.b[i].id == wid)
    212			wl->cfg.b[i].val = info[3];
    213	}
    214}
    215
    216/********************************************
    217 *
    218 *      Configuration Exported Functions
    219 *
    220 ********************************************/
    221
    222int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size)
    223{
    224	u8 type = FIELD_GET(WILC_WID_TYPE, id);
    225	int ret = 0;
    226
    227	switch (type) {
    228	case CFG_BYTE_CMD:
    229		if (size >= 1)
    230			ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf);
    231		break;
    232
    233	case CFG_HWORD_CMD:
    234		if (size >= 2)
    235			ret = wilc_wlan_cfg_set_hword(frame, offset, id,
    236						      *((u16 *)buf));
    237		break;
    238
    239	case CFG_WORD_CMD:
    240		if (size >= 4)
    241			ret = wilc_wlan_cfg_set_word(frame, offset, id,
    242						     *((u32 *)buf));
    243		break;
    244
    245	case CFG_STR_CMD:
    246		ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size);
    247		break;
    248
    249	case CFG_BIN_CMD:
    250		ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size);
    251		break;
    252	}
    253
    254	return ret;
    255}
    256
    257int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id)
    258{
    259	if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE)
    260		return 0;
    261
    262	put_unaligned_le16(id, &frame[offset]);
    263
    264	return 2;
    265}
    266
    267int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer,
    268			  u32 buffer_size)
    269{
    270	u8 type = FIELD_GET(WILC_WID_TYPE, wid);
    271	int i, ret = 0;
    272	struct wilc_cfg *cfg = &wl->cfg;
    273
    274	i = 0;
    275	if (type == CFG_BYTE_CMD) {
    276		while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid)
    277			i++;
    278
    279		if (cfg->b[i].id == wid) {
    280			memcpy(buffer, &cfg->b[i].val, 1);
    281			ret = 1;
    282		}
    283	} else if (type == CFG_HWORD_CMD) {
    284		while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid)
    285			i++;
    286
    287		if (cfg->hw[i].id == wid) {
    288			memcpy(buffer, &cfg->hw[i].val, 2);
    289			ret = 2;
    290		}
    291	} else if (type == CFG_WORD_CMD) {
    292		while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid)
    293			i++;
    294
    295		if (cfg->w[i].id == wid) {
    296			memcpy(buffer, &cfg->w[i].val, 4);
    297			ret = 4;
    298		}
    299	} else if (type == CFG_STR_CMD) {
    300		while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid)
    301			i++;
    302
    303		if (cfg->s[i].id == wid) {
    304			u16 size = get_unaligned_le16(cfg->s[i].str);
    305
    306			if (buffer_size >= size) {
    307				memcpy(buffer, &cfg->s[i].str[2], size);
    308				ret = size;
    309			}
    310		}
    311	}
    312	return ret;
    313}
    314
    315void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
    316			       struct wilc_cfg_rsp *rsp)
    317{
    318	u8 msg_type;
    319	u8 msg_id;
    320
    321	msg_type = frame[0];
    322	msg_id = frame[1];      /* seq no */
    323	frame += 4;
    324	size -= 4;
    325	rsp->type = 0;
    326
    327	switch (msg_type) {
    328	case WILC_RESP_MSG_TYPE_CONFIG_REPLY:
    329		wilc_wlan_parse_response_frame(wilc, frame, size);
    330		rsp->type = WILC_CFG_RSP;
    331		rsp->seq_no = msg_id;
    332		break;
    333
    334	case WILC_RESP_MSG_TYPE_STATUS_INFO:
    335		wilc_wlan_parse_info_frame(wilc, frame);
    336		rsp->type = WILC_CFG_RSP_STATUS;
    337		rsp->seq_no = msg_id;
    338		/* call host interface info parse as well */
    339		wilc_gnrl_async_info_received(wilc, frame - 4, size + 4);
    340		break;
    341
    342	case WILC_RESP_MSG_TYPE_NETWORK_INFO:
    343		wilc_network_info_received(wilc, frame - 4, size + 4);
    344		break;
    345
    346	case WILC_RESP_MSG_TYPE_SCAN_COMPLETE:
    347		wilc_scan_complete_received(wilc, frame - 4, size + 4);
    348		break;
    349
    350	default:
    351		rsp->seq_no = msg_id;
    352		break;
    353	}
    354}
    355
    356int wilc_wlan_cfg_init(struct wilc *wl)
    357{
    358	struct wilc_cfg_str_vals *str_vals;
    359	int i = 0;
    360
    361	wl->cfg.b = kmemdup(g_cfg_byte, sizeof(g_cfg_byte), GFP_KERNEL);
    362	if (!wl->cfg.b)
    363		return -ENOMEM;
    364
    365	wl->cfg.hw = kmemdup(g_cfg_hword, sizeof(g_cfg_hword), GFP_KERNEL);
    366	if (!wl->cfg.hw)
    367		goto out_b;
    368
    369	wl->cfg.w = kmemdup(g_cfg_word, sizeof(g_cfg_word), GFP_KERNEL);
    370	if (!wl->cfg.w)
    371		goto out_hw;
    372
    373	wl->cfg.s = kmemdup(g_cfg_str, sizeof(g_cfg_str), GFP_KERNEL);
    374	if (!wl->cfg.s)
    375		goto out_w;
    376
    377	str_vals = kzalloc(sizeof(*str_vals), GFP_KERNEL);
    378	if (!str_vals)
    379		goto out_s;
    380
    381	wl->cfg.str_vals = str_vals;
    382	/* store the string cfg parameters */
    383	wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
    384	wl->cfg.s[i].str = str_vals->firmware_version;
    385	i++;
    386	wl->cfg.s[i].id = WID_MAC_ADDR;
    387	wl->cfg.s[i].str = str_vals->mac_address;
    388	i++;
    389	wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
    390	wl->cfg.s[i].str = str_vals->assoc_rsp;
    391	i++;
    392	wl->cfg.s[i].id = WID_NIL;
    393	wl->cfg.s[i].str = NULL;
    394	return 0;
    395
    396out_s:
    397	kfree(wl->cfg.s);
    398out_w:
    399	kfree(wl->cfg.w);
    400out_hw:
    401	kfree(wl->cfg.hw);
    402out_b:
    403	kfree(wl->cfg.b);
    404	return -ENOMEM;
    405}
    406
    407void wilc_wlan_cfg_deinit(struct wilc *wl)
    408{
    409	kfree(wl->cfg.b);
    410	kfree(wl->cfg.hw);
    411	kfree(wl->cfg.w);
    412	kfree(wl->cfg.s);
    413	kfree(wl->cfg.str_vals);
    414}