xref: /openbmc/linux/drivers/staging/vt6655/key.c (revision d7c43082)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * File: key.c
17  *
18  * Purpose: Implement functions for 802.11i Key management
19  *
20  * Author: Jerry Chen
21  *
22  * Date: May 29, 2003
23  *
24  */
25 
26 #include "tmacro.h"
27 #include "key.h"
28 #include "mac.h"
29 
30 static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr,
31 			   struct ieee80211_key_conf *key, u32 key_type,
32 			   u32 mode, bool onfly_latch)
33 {
34 	struct vnt_private *priv = hw->priv;
35 	u8 broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
36 	u16 key_mode = 0;
37 	u32 entry = 0;
38 	u8 *bssid;
39 	u8 key_inx = key->keyidx;
40 	u8 i;
41 
42 	if (mac_addr)
43 		bssid = mac_addr;
44 	else
45 		bssid = &broadcast[0];
46 
47 	if (key_type != VNT_KEY_DEFAULTKEY) {
48 		for (i = 0; i < (MAX_KEY_TABLE - 1); i++) {
49 			if (!test_bit(i, &priv->key_entry_inuse)) {
50 				set_bit(i, &priv->key_entry_inuse);
51 
52 				key->hw_key_idx = i;
53 				entry = key->hw_key_idx;
54 				break;
55 			}
56 		}
57 	}
58 
59 	switch (key_type) {
60 	case VNT_KEY_DEFAULTKEY:
61 		/* default key last entry */
62 		entry = MAX_KEY_TABLE - 1;
63 		key->hw_key_idx = entry;
64 		/* fall through */
65 	case VNT_KEY_ALLGROUP:
66 		key_mode |= VNT_KEY_ALLGROUP;
67 		if (onfly_latch)
68 			key_mode |= VNT_KEY_ONFLY_ALL;
69 		/* fall through */
70 	case VNT_KEY_GROUP_ADDRESS:
71 		key_mode |= mode;
72 		/* fall through */
73 	case VNT_KEY_GROUP:
74 		key_mode |= (mode << 4);
75 		key_mode |= VNT_KEY_GROUP;
76 		break;
77 	case  VNT_KEY_PAIRWISE:
78 		key_mode |= mode;
79 		key_inx = 4;
80 		break;
81 	default:
82 		return -EINVAL;
83 	}
84 
85 	if (onfly_latch)
86 		key_mode |= VNT_KEY_ONFLY;
87 
88 	if (mode == KEY_CTL_WEP) {
89 		if (key->keylen == WLAN_KEY_LEN_WEP40)
90 			key->key[15] &= 0x7f;
91 		if (key->keylen == WLAN_KEY_LEN_WEP104)
92 			key->key[15] |= 0x80;
93 	}
94 
95 	MACvSetKeyEntry(priv, key_mode, entry, key_inx,
96 			bssid, (u32 *)key->key, priv->byLocalID);
97 
98 	return 0;
99 }
100 
101 int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
102 		 struct ieee80211_vif *vif, struct ieee80211_key_conf *key)
103 {
104 	struct ieee80211_bss_conf *conf = &vif->bss_conf;
105 	struct vnt_private *priv = hw->priv;
106 	u8 *mac_addr = NULL;
107 	u8 key_dec_mode = 0;
108 	int ret = 0;
109 	u32 u;
110 
111 	if (sta)
112 		mac_addr = &sta->addr[0];
113 
114 	switch (key->cipher) {
115 	case 0:
116 		for (u = 0 ; u < MAX_KEY_TABLE; u++)
117 			MACvDisableKeyEntry(priv, u);
118 		return ret;
119 
120 	case WLAN_CIPHER_SUITE_WEP40:
121 	case WLAN_CIPHER_SUITE_WEP104:
122 		for (u = 0; u < MAX_KEY_TABLE; u++)
123 			MACvDisableKeyEntry(priv, u);
124 
125 		vnt_set_keymode(hw, mac_addr,
126 				key, VNT_KEY_DEFAULTKEY, KEY_CTL_WEP, true);
127 
128 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
129 
130 		return ret;
131 	case WLAN_CIPHER_SUITE_TKIP:
132 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
133 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
134 
135 		key_dec_mode = KEY_CTL_TKIP;
136 
137 		break;
138 	case WLAN_CIPHER_SUITE_CCMP:
139 		key_dec_mode = KEY_CTL_CCMP;
140 
141 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
142 	}
143 
144 	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
145 		vnt_set_keymode(hw, mac_addr,
146 				key, VNT_KEY_PAIRWISE, key_dec_mode, true);
147 	} else {
148 		vnt_set_keymode(hw, mac_addr,
149 				key, VNT_KEY_DEFAULTKEY, key_dec_mode, true);
150 
151 		vnt_set_keymode(hw, (u8 *)conf->bssid,
152 				key, VNT_KEY_GROUP_ADDRESS, key_dec_mode, true);
153 	}
154 
155 	return 0;
156 }
157