1/*
2 * Decode functions which provides decoding of GAS packets as defined in 802.11u.
3 *
4 * Copyright (C) 2015, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
11 *
12 * $Id:$
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include "proto/802.11.h"
19#include "trace.h"
20#include "bcm_decode_ie.h"
21#include "bcm_decode_gas.h"
22
23static void printGasFrame(bcm_decode_gas_t *gasDecode)
24{
25	WL_P2PO(("decoded GAS frame:\n"));
26	WL_P2PO(("   category = %d\n", gasDecode->category));
27	WL_P2PO(("   action = %d (%s)\n", gasDecode->action,
28		gasDecode->action == GAS_REQUEST_ACTION_FRAME ? "GAS REQUEST" :
29		gasDecode->action == GAS_RESPONSE_ACTION_FRAME ? "GAS RESPONSE" :
30		gasDecode->action == GAS_COMEBACK_REQUEST_ACTION_FRAME ?
31			"GAS COMEBACK REQUEST" :
32		gasDecode->action == GAS_COMEBACK_RESPONSE_ACTION_FRAME ?
33			"GAS COMEBACK RESPONSE" :
34		"?"));
35	WL_P2PO(("   dialog token = %d\n", gasDecode->dialogToken));
36	switch (gasDecode->action)
37	{
38	case GAS_REQUEST_ACTION_FRAME:
39		WL_P2PO(("   advertisement protocol ID = %d\n",
40			gasDecode->request.apie.protocolId));
41		WL_PRPKT("   request",
42			gasDecode->request.req, gasDecode->request.reqLen);
43		break;
44	case GAS_RESPONSE_ACTION_FRAME:
45		WL_P2PO(("   status code = %d\n",
46			gasDecode->response.statusCode));
47		WL_P2PO(("   comeback delay = 0x%04x\n",
48			gasDecode->response.comebackDelay));
49		WL_P2PO(("   advertisement protocol ID = %d\n",
50			gasDecode->response.apie.protocolId));
51		WL_PRPKT("   response",
52			gasDecode->response.rsp, gasDecode->response.rspLen);
53		break;
54	case GAS_COMEBACK_REQUEST_ACTION_FRAME:
55		/* nothing */
56		break;
57	case GAS_COMEBACK_RESPONSE_ACTION_FRAME:
58		WL_P2PO(("   status code = %d\n",
59			gasDecode->comebackResponse.statusCode));
60		WL_P2PO(("   fragment ID = 0x%02x\n",
61			gasDecode->comebackResponse.fragmentId));
62		WL_P2PO(("   comeback delay = 0x%04x\n",
63			gasDecode->comebackResponse.comebackDelay));
64		WL_P2PO(("   advertisement protocol ID = %d\n",
65			gasDecode->comebackResponse.apie.protocolId));
66		WL_PRPKT("   response",
67			gasDecode->comebackResponse.rsp, gasDecode->comebackResponse.rspLen);
68		break;
69	default:
70		break;
71	}
72}
73
74static int decodeAdvertisementProtocol(bcm_decode_t *pkt,
75	bcm_decode_ie_adv_proto_tuple_t *ap)
76{
77	uint8 ie, len;
78
79	if (!bcm_decode_byte(pkt, &ie) || ie != DOT11_MNG_ADVERTISEMENT_ID) {
80		WL_ERROR(("decode error\n"));
81		return FALSE;
82	}
83
84	if (!bcm_decode_byte(pkt, &len) || len != 2) {
85		WL_ERROR(("decode error\n"));
86		return FALSE;
87	}
88
89	if (!bcm_decode_ie_advertisement_protocol_tuple(pkt, ap)) {
90		WL_ERROR(("decode error\n"));
91		return FALSE;
92	}
93
94	return TRUE;
95}
96
97static int decodeReqRsp(bcm_decode_t *pkt, uint16 *rLen, uint8 **r)
98{
99	if (!bcm_decode_le16(pkt, rLen)) {
100		WL_ERROR(("decode error\n"));
101		return FALSE;
102	}
103
104	if (bcm_decode_remaining(pkt) < *rLen) {
105		WL_ERROR(("decode error\n"));
106		return FALSE;
107	}
108
109	*r = bcm_decode_current_ptr(pkt);
110	bcm_decode_offset_set(pkt, bcm_decode_offset(pkt) + *rLen);
111
112	return TRUE;
113}
114
115int bcm_decode_gas(bcm_decode_t *pkt, bcm_decode_gas_t *gasDecode)
116{
117
118	memset(gasDecode, 0, sizeof(*gasDecode));
119
120	if (bcm_decode_remaining(pkt) < 3) {
121		WL_ERROR(("decode error\n"));
122		return FALSE;
123	}
124
125	(void)bcm_decode_byte(pkt, &gasDecode->category);
126	(void)bcm_decode_byte(pkt, &gasDecode->action);
127	(void)bcm_decode_byte(pkt, &gasDecode->dialogToken);
128
129	if (gasDecode->category != DOT11_ACTION_CAT_PUBLIC) {
130		WL_P2PO(("invalid category %d\n", gasDecode->category));
131		return FALSE;
132	}
133
134	switch (gasDecode->action)
135	{
136	case GAS_REQUEST_ACTION_FRAME:
137		if (!decodeAdvertisementProtocol(pkt, &gasDecode->request.apie)) {
138			WL_ERROR(("decode error\n"));
139			return FALSE;
140		}
141		if (!decodeReqRsp(pkt, &gasDecode->request.reqLen, &gasDecode->request.req)) {
142			WL_ERROR(("decode error\n"));
143			return FALSE;
144		}
145		break;
146	case GAS_RESPONSE_ACTION_FRAME:
147		if (!bcm_decode_le16(pkt, &gasDecode->response.statusCode)) {
148			WL_ERROR(("decode error\n"));
149			return FALSE;
150		}
151		if (!bcm_decode_le16(pkt, &gasDecode->response.comebackDelay)) {
152			WL_ERROR(("decode error\n"));
153			return FALSE;
154		}
155		if (!decodeAdvertisementProtocol(pkt, &gasDecode->response.apie)) {
156			WL_ERROR(("decode error\n"));
157			return FALSE;
158		}
159		if (!decodeReqRsp(pkt, &gasDecode->response.rspLen, &gasDecode->response.rsp)) {
160			WL_ERROR(("decode error\n"));
161			return FALSE;
162		}
163		break;
164	case GAS_COMEBACK_REQUEST_ACTION_FRAME:
165		/* nothing */
166		break;
167	case GAS_COMEBACK_RESPONSE_ACTION_FRAME:
168		if (!bcm_decode_le16(pkt, &gasDecode->comebackResponse.statusCode)) {
169			WL_ERROR(("decode error\n"));
170			return FALSE;
171		}
172		if (!bcm_decode_byte(pkt, &gasDecode->comebackResponse.fragmentId)) {
173			WL_ERROR(("decode error\n"));
174			return FALSE;
175		}
176		if (!bcm_decode_le16(pkt, &gasDecode->comebackResponse.comebackDelay)) {
177			WL_ERROR(("decode error\n"));
178			return FALSE;
179		}
180		if (!decodeAdvertisementProtocol(pkt, &gasDecode->comebackResponse.apie)) {
181			WL_ERROR(("decode error\n"));
182			return FALSE;
183		}
184		if (!decodeReqRsp(pkt, &gasDecode->comebackResponse.rspLen,
185			&gasDecode->comebackResponse.rsp)) {
186			WL_ERROR(("decode error\n"));
187			return FALSE;
188		}
189		break;
190	default:
191		WL_P2PO(("invalid action %d\n", gasDecode->action));
192		return FALSE;
193		break;
194	}
195
196	printGasFrame(gasDecode);
197	return TRUE;
198}
199