• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/madwimax-0.1.1/src/
1/*
2 * This is a reverse-engineered driver for mobile WiMAX (802.16e) devices
3 * based on Samsung CMC-730 chip.
4 * This file contains binary protocol realization.
5 * Copyright (C) 2008-2009 Alexander Gordeev <lasaine@lvk.cs.msu.su>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <string.h>
23
24#include "logging.h"
25#include "protocol.h"
26
27static int process_normal_config_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
28{
29	short type_a = (buf[0x14] << 8) + buf[0x15];
30	short type_b = (buf[0x16] << 8) + buf[0x17];
31	short param_len = (buf[0x18] << 8) + buf[0x19];
32
33	if (type_a == 0x8 && type_b == 0x2) {
34		if (param_len != 0x80) {
35			wmlog_msg(1, "bad param_len");
36			return -1;
37		}
38		memcpy(dev->chip, buf + 0x1a, 0x40);
39		memcpy(dev->firmware, buf + 0x5a, 0x40);
40		dev->info_updated |= WDS_CHIP | WDS_FIRMWARE;
41		return 0;
42	}
43	if (type_a == 0x3 && type_b == 0x2) {
44		if (param_len != 0x6) {
45			wmlog_msg(1, "bad param_len");
46			return -1;
47		}
48		memcpy(dev->mac, buf + 0x1a, 0x6);
49		dev->info_updated |= WDS_MAC;
50		return 0;
51	}
52	if (type_a == 0x1 && type_b == 0x2) {
53		if (param_len != 0x2) {
54			wmlog_msg(1, "bad param_len");
55			return -1;
56		}
57		set_link_status((buf[0x1a] << 8) + buf[0x1b]);
58		return 0;
59	}
60	if (type_a == 0x1 && type_b == 0x3) {
61		if (param_len != 0x4) {
62			wmlog_msg(1, "bad param_len");
63			return -1;
64		}
65		set_link_status(0);
66		return 0;
67	}
68	if (type_a == 0x1 && type_b == 0xa) {
69		if (param_len != 0x16) {
70			wmlog_msg(1, "bad param_len");
71			return -1;
72		}
73		dev->rssi = (buf[0x1a] << 8) + buf[0x1b];
74		dev->cinr = (float)((short)((buf[0x1c] << 8) + buf[0x1d])) / 8;
75		memcpy(dev->bsid, buf + 0x1e, 0x6);
76		dev->txpwr = (buf[0x26] << 8) + buf[0x27];
77		dev->freq = (buf[0x28] << 24) + (buf[0x29] << 16) + (buf[0x2a] << 8) + buf[0x2b];
78		dev->info_updated |= WDS_RSSI | WDS_CINR | WDS_BSID | WDS_TXPWR | WDS_FREQ;
79		return 0;
80	}
81	if (type_a == 0x1 && type_b == 0xc) {
82		if (param_len != 0x2) {
83			wmlog_msg(1, "bad param_len");
84			return -1;
85		}
86		set_state((buf[0x1a] << 8) + buf[0x1b]);
87		return 0;
88	}
89
90	dev->info_updated |= WDS_OTHER;
91
92	return 0;
93}
94
95static int process_debug_config_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
96{
97	dev->info_updated |= WDS_OTHER;
98	return 0;
99}
100
101static int process_config_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
102{
103	if (buf[0x12] != 0x15) {
104		wmlog_msg(1, "bad format");
105		return -1;
106	}
107
108	switch (buf[0x13]) {
109		case 0x00:
110			return process_normal_config_response(dev, buf, len);
111		case 0x02:
112			return process_debug_config_response(dev, buf, len);
113		case 0x04:
114			break;
115		default:
116			wmlog_msg(1, "bad format");
117			return -1;
118	}
119
120	dev->info_updated |= WDS_OTHER;
121
122	return 0;
123}
124
125static int process_data_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
126{
127	write_netif(buf + 0x06, len - 0x06);
128	return 0;
129}
130
131static int process_E_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
132{
133	if (buf[0x5] == 0x3) {
134		dev->proto_flags = buf[0x7];
135		dev->info_updated |= WDS_PROTO_FLAGS;
136		return 0;
137	}
138
139	dev->info_updated |= WDS_OTHER;
140
141	return 0;
142}
143
144static int process_P_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
145{
146	dev->info_updated |= WDS_OTHER;
147	return 0;
148}
149
150int process_response(struct wimax_dev_status *dev, const unsigned char *buf, int len)
151{
152	int check_len;
153
154	if(len < 4) {
155		wmlog_msg(1, "short read");
156		return -1;
157	}
158
159	if(buf[0] != 0x57) {
160		wmlog_msg(1, "bad header");
161		return -1;
162	}
163
164	check_len = 4 + buf[2] + (buf[3] << 8);
165	if(buf[1] == 0x43 || buf[1] == 0x44) {
166		check_len += 2;
167	}
168
169	if(check_len != len) {
170		wmlog_msg(1, "bad length: %02x instead of %02x", check_len, len);
171		return -1;
172	}
173
174	switch (buf[1]) {
175		case 0x43:
176			return process_config_response(dev, buf, len);
177		case 0x44:
178			return process_data_response(dev, buf, len);
179		case 0x45:
180			return process_E_response(dev, buf, len);
181		case 0x50:
182			return process_P_response(dev, buf, len);
183		default:
184			wmlog_msg(1, "bad response type: %02x", buf[1]);
185			return -1;
186	}
187}
188
189
190static inline void fill_outgoing_packet_header(unsigned char *buf, unsigned char type, int body_len)
191{
192	buf[0x00] = 0x57;
193	buf[0x01] = type;
194	buf[0x02] = body_len & 0xff;
195	buf[0x03] = (body_len >> 8) & 0xff;
196}
197
198int fill_protocol_info_req(unsigned char *buf, unsigned char flags)
199{
200	fill_outgoing_packet_header(buf, 0x45, 4);
201	buf += HEADER_LENGTH_LOWLEVEL;
202	buf[0x00] = 0x00;
203	buf[0x01] = 0x02;
204	buf[0x02] = 0x00;
205	buf[0x03] = flags;
206	return HEADER_LENGTH_LOWLEVEL + 4;
207}
208
209int fill_mac_lowlevel_req(unsigned char *buf)
210{
211	fill_outgoing_packet_header(buf, 0x50, 0x14);
212	buf += HEADER_LENGTH_LOWLEVEL;
213	memset(buf, 0, 0x14);
214	buf[0x0c] = 0x15;
215	buf[0x0d] = 0x0a;
216	return HEADER_LENGTH_LOWLEVEL + 0x14;
217}
218
219static inline void fill_config_req(unsigned char *buf, int body_len)
220{
221	fill_outgoing_packet_header(buf, 0x43, body_len);
222	memset(buf + HEADER_LENGTH, 0, 12);
223}
224
225static int fill_normal_config_req(unsigned char *buf, unsigned short type_a, unsigned short type_b, unsigned short param_len, unsigned char *param)
226{
227	int body_len = 0x14 + param_len;
228	fill_config_req(buf, body_len);
229	buf[0x04] = 0x15;
230	buf[0x05] = 0x00;
231	buf += HEADER_LENGTH;
232	buf[0x0c] = 0x15;
233	buf[0x0d] = 0x00;
234	buf[0x0e] = type_a >> 8;
235	buf[0x0f] = type_a & 0xff;
236	buf[0x10] = type_b >> 8;
237	buf[0x11] = type_b & 0xff;
238	buf[0x12] = param_len >> 8;
239	buf[0x13] = param_len & 0xff;
240	memcpy(buf + 0x14, param, param_len);
241	return HEADER_LENGTH + body_len;
242}
243
244int fill_init_cmd(unsigned char *buf)
245{
246	fill_config_req(buf, 0x12);
247	buf[0x04] = 0x15;
248	buf[0x05] = 0x04;
249	buf += HEADER_LENGTH;
250	buf[0x0c] = 0x15;
251	buf[0x0d] = 0x04;
252	buf[0x0e] = 0x50;
253	buf[0x0f] = 0x04;
254	return HEADER_LENGTH + 0x12;
255}
256
257int fill_string_info_req(unsigned char *buf)
258{
259	return fill_normal_config_req(buf, 0x8, 0x1, 0x0, NULL);
260}
261
262int fill_diode_control_cmd(unsigned char *buf, int turn_on)
263{
264	unsigned char param[0x2] = {0x0, turn_on ? 0x1 : 0x0};
265	return fill_normal_config_req(buf, 0x30, 0x1, sizeof(param), param);
266}
267
268int fill_mac_req(unsigned char *buf)
269{
270	return fill_normal_config_req(buf, 0x3, 0x1, 0x0, NULL);
271}
272
273int fill_auth_policy_req(unsigned char *buf)
274{
275	return fill_normal_config_req(buf, 0x20, 0x8, 0x0, NULL);
276}
277
278int fill_auth_method_req(unsigned char *buf)
279{
280	return fill_normal_config_req(buf, 0x20, 0xc, 0x0, NULL);
281}
282
283int fill_auth_set_cmd(unsigned char *buf, char *netid)
284{
285	short netid_len = strlen(netid) + 1;
286	unsigned char param[netid_len + 4];
287	param[0] = 0x0;
288	param[1] = 0x10;
289	param[2] = netid_len >> 8;
290	param[3] = netid_len & 0xff;
291	memcpy(param + 4, netid, netid_len);
292	return fill_normal_config_req(buf, 0x20, 0x20, sizeof(param), param);
293}
294
295int fill_find_network_req(unsigned char *buf, unsigned short level)
296{
297	unsigned char param[0x2] = {level >> 8, level & 0xff};
298	return fill_normal_config_req(buf, 0x1, 0x1, sizeof(param), param);
299}
300
301int fill_connection_params_req(unsigned char *buf)
302{
303	unsigned char param[0x2] = {0x00, 0x00};
304	return fill_normal_config_req(buf, 0x1, 0x9, sizeof(param), param);
305}
306
307int fill_state_req(unsigned char *buf)
308{
309	return fill_normal_config_req(buf, 0x1, 0xb, 0x0, NULL);
310}
311
312int fill_network_list_req(unsigned char *buf)
313{
314	unsigned char param[0x2] = {0x00, 0x00};
315	return fill_normal_config_req(buf, 0x24, 0x1, sizeof(param), param);
316}
317
318
319int get_header_len()
320{
321	return HEADER_LENGTH;
322}
323
324int fill_data_packet_header(unsigned char *buf, int body_len)
325{
326	fill_outgoing_packet_header(buf, 0x44, body_len);
327	return HEADER_LENGTH + body_len;
328}
329
330