blob: ae6c1db65bfa82ae8597355d90b293f88112c476 [file] [log] [blame]
Andy Green7c212cc2010-11-08 20:20:42 +00001/*
2 * libwebsockets - small server side websockets and web server implementation
Andy Greene77ddd82010-11-13 10:03:47 +00003 *
Andy Greena1ce6be2013-01-18 11:43:21 +08004 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
Andy Green7c212cc2010-11-08 20:20:42 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include "private-libwebsockets.h"
23
Andy Green6d1fcb72013-01-18 01:55:48 +080024unsigned char lextable[] = {
Andy Greencc13c6f2013-11-09 10:09:09 +080025 #include "lextable.h"
Andy Green6d1fcb72013-01-18 01:55:48 +080026};
27
Andy Greenbbc5c072014-03-09 11:49:21 +080028#define FAIL_CHAR 0x08
29
Andy Green6d1fcb72013-01-18 01:55:48 +080030int lextable_decode(int pos, char c)
31{
Andy Greenbbc5c072014-03-09 11:49:21 +080032 c = tolower(c);
33
34 while (1) {
35 if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
36 if ((lextable[pos] & 0x7f) != c)
37 return -1;
38 /* fall thru */
39 pos++;
40 if (lextable[pos] == FAIL_CHAR)
41 return -1;
Andy Green6d1fcb72013-01-18 01:55:48 +080042 return pos;
Andy Greenbbc5c072014-03-09 11:49:21 +080043 }
Andy Greenf012f752014-08-22 19:38:17 +080044
45 if (lextable[pos] == FAIL_CHAR)
46 return -1;
47
Andy Green2c24ec02014-04-02 19:45:42 +080048 /* b7 = 0, end or 3-byte */
49 if (lextable[pos] < FAIL_CHAR) /* terminal marker */
50 return pos;
51
52 if (lextable[pos] == c) /* goto */
53 return pos + (lextable[pos + 1]) +
54 (lextable[pos + 2] << 8);
55 /* fall thru goto */
56 pos += 3;
57 /* continue */
Andy Green6d1fcb72013-01-18 01:55:48 +080058 }
Andy Green6d1fcb72013-01-18 01:55:48 +080059}
60
Andy Green4b85c1d2015-12-04 11:08:32 +080061int lws_allocate_header_table(struct lws *wsi)
Andy Green16ab3182013-02-10 18:02:31 +080062{
Andy Green3df58002015-12-25 12:44:12 +080063 struct lws_context *context = wsi->context;
64 int n;
65
66 lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi,
67 (void *)wsi->u.hdr.ah);
68
69 /* if we are already bound to one, just clear it down */
70 if (wsi->u.hdr.ah)
71 goto reset;
72 /*
73 * server should have suppressed the accept of a new wsi before this
74 * became the case. If initiating multiple client connects, make sure
75 * the ah pool is big enough to cope, or be prepared to retry
76 */
77 if (context->ah_count_in_use == context->max_http_header_pool) {
78 lwsl_err("No free ah\n");
Andy Green16ab3182013-02-10 18:02:31 +080079 return -1;
80 }
Andy Green3df58002015-12-25 12:44:12 +080081
82 for (n = 0; n < context->max_http_header_pool; n++)
83 if (!context->ah_pool[n].in_use)
84 break;
85
86 /* if the count of in use said something free... */
87 assert(n != context->max_http_header_pool);
88
89 wsi->u.hdr.ah = &context->ah_pool[n];
90 wsi->u.hdr.ah->in_use = 1;
91
92 context->ah_count_in_use++;
93 /* if we used up all the ah, defeat accepting new server connections */
94 if (context->ah_count_in_use == context->max_http_header_pool)
95 if (_lws_server_listen_accept_flow_control(context, 0))
96 return 1;
97
98 lwsl_debug("%s: wsi %p: ah %p: count %d (on exit)\n",
99 __func__, (void *)wsi, (void *)wsi->u.hdr.ah,
100 context->ah_count_in_use);
101
102reset:
103 /* init the ah to reflect no headers or data have appeared yet */
Andy Greenb5b23192013-02-11 17:13:32 +0800104 memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index));
Andy Green6b5de702015-12-15 21:15:58 +0800105 wsi->u.hdr.ah->nfrag = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800106 wsi->u.hdr.ah->pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800107
Andy Green16ab3182013-02-10 18:02:31 +0800108 return 0;
109}
110
Andy Green4b85c1d2015-12-04 11:08:32 +0800111int lws_free_header_table(struct lws *wsi)
Andrew Canaday37718812014-11-07 11:20:59 +0800112{
Andy Green3df58002015-12-25 12:44:12 +0800113 struct lws_context *context = wsi->context;
114
115 lwsl_debug("%s: wsi %p: ah %p (count = %d)\n", __func__, (void *)wsi,
116 (void *)wsi->u.hdr.ah, context->ah_count_in_use);
117
118 assert(wsi->u.hdr.ah);
119 if (!wsi->u.hdr.ah)
120 return 0;
121
122 /* if we think we're freeing one, there should be one to free */
123 assert(context->ah_count_in_use > 0);
124
125 assert(wsi->u.hdr.ah->in_use);
126 wsi->u.hdr.ah->in_use = 0;
127
128 /* if we just freed up one ah, allow new server connection */
129 if (context->ah_count_in_use == context->max_http_header_pool)
130 if (_lws_server_listen_accept_flow_control(context, 1))
131 return 1;
132
133 context->ah_count_in_use--;
Alejandro Meryac3ec392014-12-05 00:09:20 +0100134 wsi->u.hdr.ah = NULL;
Andy Green3df58002015-12-25 12:44:12 +0800135
Alejandro Mery6ff28242014-12-04 23:59:35 +0100136 return 0;
Andy Green3df58002015-12-25 12:44:12 +0800137}
Andrew Canaday37718812014-11-07 11:20:59 +0800138
Andy Greene974f0c2015-12-19 07:35:23 +0800139LWS_VISIBLE int
140lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
141{
142 int n;
143
144 n = wsi->u.hdr.ah->frag_index[h];
145 if (!n)
146 return 0;
147 do {
148 if (!frag_idx)
149 return wsi->u.hdr.ah->frags[n].len;
150 n = wsi->u.hdr.ah->frags[n].nfrag;
151 } while (frag_idx-- && n);
152
153 return 0;
154}
155
Andy Green4b85c1d2015-12-04 11:08:32 +0800156LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800157{
158 int n;
159 int len = 0;
160
161 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +0800162 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +0800163 return 0;
Andy Green16ab3182013-02-10 18:02:31 +0800164 do {
165 len += wsi->u.hdr.ah->frags[n].len;
Andy Green6b5de702015-12-15 21:15:58 +0800166 n = wsi->u.hdr.ah->frags[n].nfrag;
Andy Green16ab3182013-02-10 18:02:31 +0800167 } while (n);
168
169 return len;
170}
171
Andy Green566eb432015-12-15 22:59:23 +0800172LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
173 enum lws_token_indexes h, int frag_idx)
174{
175 int n = 0;
176 int f = wsi->u.hdr.ah->frag_index[h];
177
178 while (n < frag_idx) {
179 f = wsi->u.hdr.ah->frags[f].nfrag;
180 if (!f)
181 return -1;
182 n++;
183 }
184
Andy Green9f54c1f2015-12-18 16:40:02 +0800185 if (wsi->u.hdr.ah->frags[f].len >= len)
Andy Green566eb432015-12-15 22:59:23 +0800186 return -1;
187
Andy Green3df58002015-12-25 12:44:12 +0800188 memcpy(dst, wsi->u.hdr.ah->data + wsi->u.hdr.ah->frags[f].offset,
Andy Green566eb432015-12-15 22:59:23 +0800189 wsi->u.hdr.ah->frags[f].len);
190 dst[wsi->u.hdr.ah->frags[f].len] = '\0';
191
192 return wsi->u.hdr.ah->frags[f].len;
193}
194
Andy Green6b5de702015-12-15 21:15:58 +0800195LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
Andy Green5c9660d2015-12-04 11:30:53 +0800196 enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800197{
198 int toklen = lws_hdr_total_length(wsi, h);
199 int n;
200
201 if (toklen >= len)
202 return -1;
203
204 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +0800205 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +0800206 return 0;
207
208 do {
Andy Green6b5de702015-12-15 21:15:58 +0800209 strcpy(dst, &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
210 dst += wsi->u.hdr.ah->frags[n].len;
211 n = wsi->u.hdr.ah->frags[n].nfrag;
Andy Green16ab3182013-02-10 18:02:31 +0800212 } while (n);
213
214 return toklen;
215}
216
Andy Green4b85c1d2015-12-04 11:08:32 +0800217char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800218{
219 int n;
220
221 n = wsi->u.hdr.ah->frag_index[h];
222 if (!n)
223 return NULL;
224
Andy Green3df58002015-12-25 12:44:12 +0800225 return wsi->u.hdr.ah->data + wsi->u.hdr.ah->frags[n].offset;
Andy Green16ab3182013-02-10 18:02:31 +0800226}
Andy Green6d1fcb72013-01-18 01:55:48 +0800227
Andy Green6b5de702015-12-15 21:15:58 +0800228int lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h,
229 const char *s)
Andy Greene77fb802013-02-11 13:04:45 +0800230{
Andy Green6b5de702015-12-15 21:15:58 +0800231 wsi->u.hdr.ah->nfrag++;
232 if (wsi->u.hdr.ah->nfrag == ARRAY_SIZE(wsi->u.hdr.ah->frags)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800233 lwsl_warn("More hdr frags than we can deal with, dropping\n");
Andy Greene77fb802013-02-11 13:04:45 +0800234 return -1;
235 }
236
Andy Green6b5de702015-12-15 21:15:58 +0800237 wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->nfrag;
Andy Greene77fb802013-02-11 13:04:45 +0800238
Andy Green6b5de702015-12-15 21:15:58 +0800239 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].offset = wsi->u.hdr.ah->pos;
240 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len = 0;
241 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].nfrag = 0;
Andy Greene77fb802013-02-11 13:04:45 +0800242
243 do {
Andy Green3df58002015-12-25 12:44:12 +0800244 if (wsi->u.hdr.ah->pos == wsi->context->max_http_header_data) {
Andy Greene77fb802013-02-11 13:04:45 +0800245 lwsl_err("Ran out of header data space\n");
246 return -1;
247 }
248 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
249 if (*s)
Andy Green6b5de702015-12-15 21:15:58 +0800250 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len++;
Andy Greene77fb802013-02-11 13:04:45 +0800251 } while (*s++);
252
253 return 0;
254}
255
Andy Green2a5774e2015-03-30 18:56:52 +0800256static signed char char_to_hex(const char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800257{
258 if (c >= '0' && c <= '9')
259 return c - '0';
260
261 if (c >= 'a' && c <= 'f')
262 return c - 'a' + 10;
263
264 if (c >= 'A' && c <= 'F')
265 return c - 'A' + 10;
266
267 return -1;
268}
269
Andy Green4b85c1d2015-12-04 11:08:32 +0800270static int issue_char(struct lws *wsi, unsigned char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800271{
Andrew Canadayffe64562015-11-29 19:26:01 +0800272 unsigned short frag_len;
Andy Green6b5de702015-12-15 21:15:58 +0800273
Andy Green3df58002015-12-25 12:44:12 +0800274 if (wsi->u.hdr.ah->pos == wsi->context->max_http_header_data) {
Andy Greenb1a9e502013-11-10 15:15:21 +0800275 lwsl_warn("excessive header content\n");
276 return -1;
277 }
Andrew Canaday74b4a652014-06-29 00:25:19 -0400278
Andy Green6b5de702015-12-15 21:15:58 +0800279 frag_len = wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len;
280 /*
281 * If we haven't hit the token limit, just copy the character into
282 * the header
283 */
284 if (frag_len < wsi->u.hdr.current_token_limit) {
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800285 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
286 if (c)
Andy Green6b5de702015-12-15 21:15:58 +0800287 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len++;
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800288 return 0;
289 }
Andy Green6b5de702015-12-15 21:15:58 +0800290
291 /* Insert a null character when we *hit* the limit: */
292 if (frag_len == wsi->u.hdr.current_token_limit) {
293 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
Andy Green3df58002015-12-25 12:44:12 +0800294 lwsl_warn("header %i exceeds limit %d\n",
295 wsi->u.hdr.parser_state, wsi->u.hdr.current_token_limit);
Andy Green6b5de702015-12-15 21:15:58 +0800296 }
297
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800298 return 1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800299}
300
Andy Green6b5de702015-12-15 21:15:58 +0800301int lws_parse(struct lws *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000302{
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800303 static const unsigned char methods[] = {
304 WSI_TOKEN_GET_URI,
305 WSI_TOKEN_POST_URI,
306 WSI_TOKEN_OPTIONS_URI,
307 WSI_TOKEN_PUT_URI,
308 WSI_TOKEN_PATCH_URI,
309 WSI_TOKEN_DELETE_URI,
310 };
Andy Green6b5de702015-12-15 21:15:58 +0800311 struct allocated_headers *ah = wsi->u.hdr.ah;
312 struct lws_context *context = wsi->context;
Andy Green38f32252015-12-14 19:42:26 +0800313 unsigned int n, m, enc = 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000314
Andy Green623a98d2013-01-21 11:04:23 +0800315 switch (wsi->u.hdr.parser_state) {
Andy Greenb08cb502014-09-30 16:33:56 +0800316 default:
Andy Greena41314f2011-05-23 10:00:03 +0100317
Andy Greenb5b23192013-02-11 17:13:32 +0800318 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000319
320 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800321 /* optional initial space swallow */
Andy Green6b5de702015-12-15 21:15:58 +0800322 if (!ah->frags[ah->frag_index[
Andy Greenb5b23192013-02-11 17:13:32 +0800323 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000324 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000325
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800326 for (m = 0; m < ARRAY_SIZE(methods); m++)
327 if (wsi->u.hdr.parser_state == methods[m])
328 break;
329 if (m == ARRAY_SIZE(methods))
330 /* it was not any of the methods */
Andy Greenb1a9e502013-11-10 15:15:21 +0800331 goto check_eol;
332
333 /* special URI processing... end at space */
334
335 if (c == ' ') {
336 /* enforce starting with / */
Andy Green6b5de702015-12-15 21:15:58 +0800337 if (!ah->frags[ah->nfrag].len)
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400338 if (issue_char(wsi, '/') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800339 return -1;
Andrew Canadayafe26cf2014-07-13 01:07:36 -0400340
341 /* begin parsing HTTP version: */
342 if (issue_char(wsi, '\0') < 0)
343 return -1;
344 wsi->u.hdr.parser_state = WSI_TOKEN_HTTP;
345 goto start_fragment;
Andy Green7c212cc2010-11-08 20:20:42 +0000346 }
347
Andy Greenb1a9e502013-11-10 15:15:21 +0800348 /* special URI processing... convert %xx */
349
350 switch (wsi->u.hdr.ues) {
351 case URIES_IDLE:
352 if (c == '%') {
353 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
354 goto swallow;
355 }
356 break;
357 case URIES_SEEN_PERCENT:
358 if (char_to_hex(c) < 0) {
359 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400360 if (issue_char(wsi, '%') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800361 return -1;
362 wsi->u.hdr.ues = URIES_IDLE;
363 /* continue on to assess c */
364 break;
365 }
366 wsi->u.hdr.esc_stash = c;
367 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800368 goto swallow;
Andy Green40110e82015-12-14 08:52:03 +0800369
Andy Greenb1a9e502013-11-10 15:15:21 +0800370 case URIES_SEEN_PERCENT_H1:
371 if (char_to_hex(c) < 0) {
372 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400373 issue_char(wsi, '%');
Andy Greenb1a9e502013-11-10 15:15:21 +0800374 wsi->u.hdr.ues = URIES_IDLE;
375 /* regurgitate + assess */
Andy Green6b5de702015-12-15 21:15:58 +0800376 if (lws_parse(wsi, wsi->u.hdr.esc_stash) < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800377 return -1;
378 /* continue on to assess c */
379 break;
380 }
381 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
382 char_to_hex(c);
Andy Green38f32252015-12-14 19:42:26 +0800383 enc = 1;
Andy Green6f429102013-11-11 06:14:52 +0800384 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800385 break;
386 }
387
388 /*
Andy Green40110e82015-12-14 08:52:03 +0800389 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800390 * convert /.. or /... or /../ etc to /
391 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800392 * convert // or /// etc to /
393 * leave /.dir or whatever alone
394 */
395
396 switch (wsi->u.hdr.ups) {
397 case URIPS_IDLE:
Andy Green4eb36372015-12-15 22:57:19 +0800398 /* genuine delimiter */
Andy Green03d7e9d2015-12-18 15:20:09 +0800399 if ((c == '&' || c == ';') && !enc) {
Andy Green4eb36372015-12-15 22:57:19 +0800400 issue_char(wsi, c);
401 /* swallow the terminator */
402 ah->frags[ah->nfrag].len--;
403 /* link to next fragment */
404 ah->frags[ah->nfrag].nfrag = ah->nfrag + 1;
405 ah->nfrag++;
406 if (ah->nfrag >= ARRAY_SIZE(ah->frags))
407 goto excessive;
408 /* start next fragment after the & */
Andy Green3ba035d2015-12-18 15:40:03 +0800409 wsi->u.hdr.post_literal_equal = 0;
Andy Green4eb36372015-12-15 22:57:19 +0800410 ah->frags[ah->nfrag].offset = ah->pos;
411 ah->frags[ah->nfrag].len = 0;
412 ah->frags[ah->nfrag].nfrag = 0;
413 goto swallow;
414 }
Andy Green3ba035d2015-12-18 15:40:03 +0800415 /* uriencoded = in the name part, disallow */
416 if (c == '=' && enc && !wsi->u.hdr.post_literal_equal)
417 c = '_';
418
419 /* after the real =, we don't care how many = */
420 if (c == '=' && !enc)
421 wsi->u.hdr.post_literal_equal = 1;
422
Andy Green8b9fe992015-12-18 15:23:31 +0800423 /* + to space */
424 if (c == '+' && !enc)
425 c = ' ';
Andy Greenb1a9e502013-11-10 15:15:21 +0800426 /* issue the first / always */
Andy Green4eb36372015-12-15 22:57:19 +0800427 if (c == '/' && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS])
Andy Greenb1a9e502013-11-10 15:15:21 +0800428 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
429 break;
430 case URIPS_SEEN_SLASH:
431 /* swallow subsequent slashes */
432 if (c == '/')
433 goto swallow;
434 /* track and swallow the first . after / */
435 if (c == '.') {
436 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
437 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800438 }
439 wsi->u.hdr.ups = URIPS_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800440 break;
441 case URIPS_SEEN_SLASH_DOT:
442 /* swallow second . */
443 if (c == '.') {
Andy Green40110e82015-12-14 08:52:03 +0800444 /*
Andy Greend3f68732013-11-13 06:53:21 +0800445 * back up one dir level if possible
446 * safe against header fragmentation because
447 * the method URI can only be in 1 fragment
448 */
Andy Green6b5de702015-12-15 21:15:58 +0800449 if (ah->frags[ah->nfrag].len > 2) {
450 ah->pos--;
451 ah->frags[ah->nfrag].len--;
Andy Greend3f68732013-11-13 06:53:21 +0800452 do {
Andy Green6b5de702015-12-15 21:15:58 +0800453 ah->pos--;
454 ah->frags[ah->nfrag].len--;
455 } while (ah->frags[ah->nfrag].len > 1 &&
456 ah->data[ah->pos] != '/');
Andy Greend3f68732013-11-13 06:53:21 +0800457 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800458 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
459 goto swallow;
460 }
Andy Green6f429102013-11-11 06:14:52 +0800461 /* change /./ to / */
462 if (c == '/') {
463 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
464 goto swallow;
465 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800466 /* it was like /.dir ... regurgitate the . */
467 wsi->u.hdr.ups = URIPS_IDLE;
Andy Green4eb36372015-12-15 22:57:19 +0800468 if (issue_char(wsi, '.') < 0)
469 return -1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800470 break;
Andy Green40110e82015-12-14 08:52:03 +0800471
Andy Greenb1a9e502013-11-10 15:15:21 +0800472 case URIPS_SEEN_SLASH_DOT_DOT:
473 /* swallow prior .. chars and any subsequent . */
474 if (c == '.')
475 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800476 /* last issued was /, so another / == // */
477 if (c == '/')
478 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800479 /* last we issued was / so SEEN_SLASH */
480 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
Andy Greenb1a9e502013-11-10 15:15:21 +0800481 break;
482 }
483
Andy Green4eb36372015-12-15 22:57:19 +0800484 if (c == '?' && !enc &&
485 !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */
Andy Green1e3f7b82013-11-13 07:45:17 +0800486 /* seal off uri header */
Andy Green6b5de702015-12-15 21:15:58 +0800487 ah->data[ah->pos++] = '\0';
Andy Green1e3f7b82013-11-13 07:45:17 +0800488
489 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
Andy Green6b5de702015-12-15 21:15:58 +0800490 ah->nfrag++;
Andy Green4eb36372015-12-15 22:57:19 +0800491 if (ah->nfrag >= ARRAY_SIZE(ah->frags))
492 goto excessive;
Andy Green6b5de702015-12-15 21:15:58 +0800493 ah->frags[ah->nfrag].offset = ah->pos;
494 ah->frags[ah->nfrag].len = 0;
495 ah->frags[ah->nfrag].nfrag = 0;
Andy Green1e3f7b82013-11-13 07:45:17 +0800496
Andy Green3ba035d2015-12-18 15:40:03 +0800497 wsi->u.hdr.post_literal_equal = 0;
Andy Green6b5de702015-12-15 21:15:58 +0800498 ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag;
Andy Greenf35801b2015-12-15 23:05:23 +0800499 wsi->u.hdr.ups = URIPS_IDLE;
Andy Green1e3f7b82013-11-13 07:45:17 +0800500 goto swallow;
501 }
502
Andrew Canaday991f1cd2014-07-19 06:58:53 +0800503check_eol:
504
505 /* bail at EOL */
506 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
507 c == '\x0d') {
508 c = '\0';
509 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
510 lwsl_parser("*\n");
511 }
512
Andy Green4b812fe2014-08-19 18:34:31 +0800513 n = issue_char(wsi, c);
Andy Green2cd30742015-11-02 13:10:33 +0800514 if ((int)n < 0)
Andy Green4b812fe2014-08-19 18:34:31 +0800515 return -1;
516 if (n > 0)
517 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
518
Andy Greenb1a9e502013-11-10 15:15:21 +0800519swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000520 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000521
Andy Green16ab3182013-02-10 18:02:31 +0800522 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
523 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100524 break;
525
Andy Green7c212cc2010-11-08 20:20:42 +0000526 /* collecting and checking a name part */
527 case WSI_TOKEN_NAME_PART:
Andy Green8fb338f2015-04-07 08:19:30 +0800528 lwsl_parser("WSI_TOKEN_NAME_PART '%c' (mode=%d)\n", c, wsi->mode);
Andy Green7c212cc2010-11-08 20:20:42 +0000529
Andy Greenb5b23192013-02-11 17:13:32 +0800530 wsi->u.hdr.lextable_pos =
531 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green8fb338f2015-04-07 08:19:30 +0800532 /*
533 * Server needs to look out for unknown methods...
534 */
535 if (wsi->u.hdr.lextable_pos < 0 &&
Andy Green54806b12015-12-17 17:03:59 +0800536 wsi->mode == LWSCM_HTTP_SERVING) {
Andy Greene4dffc92013-02-04 09:24:18 +0800537 /* this is not a header we know about */
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800538 for (m = 0; m < ARRAY_SIZE(methods); m++)
Andy Green6b5de702015-12-15 21:15:58 +0800539 if (ah->frag_index[methods[m]]) {
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800540 /*
541 * already had the method, no idea what
Andy Green8fb338f2015-04-07 08:19:30 +0800542 * this crap from the client is, ignore
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800543 */
544 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
545 break;
546 }
Andy Green3ee9b312013-02-12 12:52:39 +0800547 /*
Andy Green8fb338f2015-04-07 08:19:30 +0800548 * hm it's an unknown http method from a client in fact,
Andy Green3ee9b312013-02-12 12:52:39 +0800549 * treat as dangerous
550 */
Drew Noakes2121e8a2015-01-30 12:04:43 +0000551 if (m == ARRAY_SIZE(methods)) {
552 lwsl_info("Unknown method - dropping\n");
553 return -1;
554 }
555 break;
Andy Greene4dffc92013-02-04 09:24:18 +0800556 }
Andy Green8fb338f2015-04-07 08:19:30 +0800557 /*
558 * ...otherwise for a client, let him ignore unknown headers
559 * coming from the server
560 */
561 if (wsi->u.hdr.lextable_pos < 0) {
562 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
563 break;
564 }
565
Andy Greenbbc5c072014-03-09 11:49:21 +0800566 if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
Andy Greene4dffc92013-02-04 09:24:18 +0800567 /* terminal state */
568
Andy Green59800b72014-11-30 12:36:09 +0800569 n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) |
570 lextable[wsi->u.hdr.lextable_pos + 1];
Andy Green6d1fcb72013-01-18 01:55:48 +0800571
Andy Greencc7cb682013-02-18 10:22:42 +0800572 lwsl_parser("known hdr %d\n", n);
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800573 for (m = 0; m < ARRAY_SIZE(methods); m++)
574 if (n == methods[m] &&
Andy Green6b5de702015-12-15 21:15:58 +0800575 ah->frag_index[
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800576 methods[m]]) {
577 lwsl_warn("Duplicated method\n");
578 return -1;
579 }
Andy Green94f94652013-02-12 13:10:19 +0800580
Andy Greenfd963302012-04-03 17:02:20 +0200581 /*
582 * WSORIGIN is protocol equiv to ORIGIN,
583 * JWebSocket likes to send it, map to ORIGIN
584 */
585 if (n == WSI_TOKEN_SWORIGIN)
586 n = WSI_TOKEN_ORIGIN;
587
Andy Green16ab3182013-02-10 18:02:31 +0800588 wsi->u.hdr.parser_state = (enum lws_token_indexes)
589 (WSI_TOKEN_GET_URI + n);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400590
Andy Greenf012f752014-08-22 19:38:17 +0800591 if (context->token_limits)
592 wsi->u.hdr.current_token_limit =
Andy Green6b5de702015-12-15 21:15:58 +0800593 context->token_limits->token_limit[
594 wsi->u.hdr.parser_state];
Andy Greenf012f752014-08-22 19:38:17 +0800595 else
Andy Green3df58002015-12-25 12:44:12 +0800596 wsi->u.hdr.current_token_limit =
597 wsi->context->max_http_header_data;
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400598
Andy Green16ab3182013-02-10 18:02:31 +0800599 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
600 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000601
Andy Green16ab3182013-02-10 18:02:31 +0800602 goto start_fragment;
603 }
604 break;
Nick Dowell30592632012-04-05 10:31:48 +0800605
Andy Green16ab3182013-02-10 18:02:31 +0800606start_fragment:
Andy Green6b5de702015-12-15 21:15:58 +0800607 ah->nfrag++;
Andy Green4eb36372015-12-15 22:57:19 +0800608excessive:
Andy Green6b5de702015-12-15 21:15:58 +0800609 if (ah->nfrag == ARRAY_SIZE(ah->frags)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800610 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800611 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000612 }
613
Andy Green6b5de702015-12-15 21:15:58 +0800614 ah->frags[ah->nfrag].offset = ah->pos;
615 ah->frags[ah->nfrag].len = 0;
616 ah->frags[ ah->nfrag].nfrag = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800617
Andy Green6b5de702015-12-15 21:15:58 +0800618 n = ah->frag_index[wsi->u.hdr.parser_state];
Andy Green16ab3182013-02-10 18:02:31 +0800619 if (!n) { /* first fragment */
Andy Green6b5de702015-12-15 21:15:58 +0800620 ah->frag_index[wsi->u.hdr.parser_state] = ah->nfrag;
Andy Greencc13c6f2013-11-09 10:09:09 +0800621 break;
622 }
623 /* continuation */
Andy Green6b5de702015-12-15 21:15:58 +0800624 while (ah->frags[n].nfrag)
625 n = ah->frags[n].nfrag;
626 ah->frags[n].nfrag = ah->nfrag;
Andy Green16ab3182013-02-10 18:02:31 +0800627
Andy Green3df58002015-12-25 12:44:12 +0800628 if (ah->pos == wsi->context->max_http_header_data) {
Andy Greencc13c6f2013-11-09 10:09:09 +0800629 lwsl_warn("excessive header content\n");
630 return -1;
Andy Green2b57a342013-02-06 15:15:25 +0900631 }
Andy Green7c212cc2010-11-08 20:20:42 +0000632
Andy Green6b5de702015-12-15 21:15:58 +0800633 ah->data[ah->pos++] = ' ';
634 ah->frags[ah->nfrag].len++;
Andy Greene4dffc92013-02-04 09:24:18 +0800635 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000636
Andy Green7c212cc2010-11-08 20:20:42 +0000637 /* skipping arg part of a name we didn't recognize */
638 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800639 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100640
Andy Green7c212cc2010-11-08 20:20:42 +0000641 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800642 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000643 break;
Andy Green177ca782013-02-04 09:09:19 +0800644
Andy Green7c212cc2010-11-08 20:20:42 +0000645 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800646 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800647 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800648 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
649 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800650 } else
Andy Green623a98d2013-01-21 11:04:23 +0800651 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000652 break;
653 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100654
Andy Green7c212cc2010-11-08 20:20:42 +0000655 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800656 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000657 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000658 }
Andy Greene77ddd82010-11-13 10:03:47 +0000659
Andy Green7c212cc2010-11-08 20:20:42 +0000660 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800661
662set_parsing_complete:
663
Andy Green16ab3182013-02-10 18:02:31 +0800664 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800665 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900666 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800667 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800668
Andy Greenb5b23192013-02-11 17:13:32 +0800669 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900670 }
Andy Green177ca782013-02-04 09:09:19 +0800671 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800672 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800673
674 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000675}
676
Andy Greenbfb051f2011-02-09 08:49:14 +0000677
Andy Green2fd3f2f2013-01-18 09:49:20 +0800678/**
679 * lws_frame_is_binary: true if the current frame was sent in binary mode
680 *
681 * @wsi: the connection we are inquiring about
682 *
683 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
684 * it's interested to see if the frame it's dealing with was sent in binary
685 * mode.
686 */
687
Andy Green4b85c1d2015-12-04 11:08:32 +0800688LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800689{
Andy Green623a98d2013-01-21 11:04:23 +0800690 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800691}
Andy Greenbfb051f2011-02-09 08:49:14 +0000692
Andy Greena41314f2011-05-23 10:00:03 +0100693int
Andy Green4b85c1d2015-12-04 11:08:32 +0800694lws_rx_sm(struct lws *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000695{
Andy Greena41314f2011-05-23 10:00:03 +0100696 struct lws_tokens eff_buf;
Andy Greenaedc9532013-02-10 21:21:24 +0800697 int ret = 0;
John Tarlton05fc6ba2015-10-05 11:35:52 +0100698 int callback_action = LWS_CALLBACK_RECEIVE;
Andy Green7c212cc2010-11-08 20:20:42 +0000699
700 switch (wsi->lws_rx_parse_state) {
701 case LWS_RXPS_NEW:
Andy Greene77ddd82010-11-13 10:03:47 +0000702
Andy Green7c212cc2010-11-08 20:20:42 +0000703 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100704 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100705 /*
706 * no prepended frame key any more
707 */
Andy Green623a98d2013-01-21 11:04:23 +0800708 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100709 goto handle_first;
710
Andy Greenbfb051f2011-02-09 08:49:14 +0000711 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800712 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
713 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000714 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000715 }
Andy Green6452f1e2010-11-11 09:22:22 +0000716 break;
Andy Green3e5eb782011-01-18 18:14:26 +0000717 case LWS_RXPS_04_MASK_NONCE_1:
Andy Green54806b12015-12-17 17:03:59 +0800718 wsi->u.ws.mask_nonce[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000719 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800720 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000721 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
722 break;
723 case LWS_RXPS_04_MASK_NONCE_2:
Andy Green54806b12015-12-17 17:03:59 +0800724 wsi->u.ws.mask_nonce[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000725 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800726 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000727 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
728 break;
729 case LWS_RXPS_04_MASK_NONCE_3:
Andy Green54806b12015-12-17 17:03:59 +0800730 wsi->u.ws.mask_nonce[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000731 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800732 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000733
Andy Green3e5eb782011-01-18 18:14:26 +0000734 /*
735 * start from the zero'th byte in the XOR key buffer since
736 * this is the start of a frame with a new key
737 */
738
Andy Green623a98d2013-01-21 11:04:23 +0800739 wsi->u.ws.frame_mask_index = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000740
Andy Green3e5eb782011-01-18 18:14:26 +0000741 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
742 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000743
744 /*
745 * 04 logical framing from the spec (all this is masked when incoming
746 * and has to be unmasked)
747 *
748 * We ignore the possibility of extension data because we don't
749 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000750 *
Andy Green38e57bb2011-01-19 12:20:27 +0000751 * 0 1 2 3
752 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
753 * +-+-+-+-+-------+-+-------------+-------------------------------+
754 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
755 * |I|S|S|S| (4) |S| (7) | (16/63) |
756 * |N|V|V|V| |V| | (if payload len==126/127) |
757 * | |1|2|3| |4| | |
758 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
759 * | Extended payload length continued, if payload len == 127 |
760 * + - - - - - - - - - - - - - - - +-------------------------------+
761 * | | Extension data |
762 * +-------------------------------+ - - - - - - - - - - - - - - - +
763 * : :
764 * +---------------------------------------------------------------+
765 * : Application data :
766 * +---------------------------------------------------------------+
767 *
768 * We pass payload through to userland as soon as we get it, ignoring
769 * FIN. It's up to userland to buffer it up if it wants to see a
770 * whole unfragmented block of the original size (which may be up to
771 * 2^63 long!)
772 */
773
774 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100775handle_first:
776
Andy Green623a98d2013-01-21 11:04:23 +0800777 wsi->u.ws.opcode = c & 0xf;
778 wsi->u.ws.rsv = c & 0x70;
779 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800780
Andy Green623a98d2013-01-21 11:04:23 +0800781 switch (wsi->u.ws.opcode) {
Andy Green54806b12015-12-17 17:03:59 +0800782 case LWSWSOPC_TEXT_FRAME:
783 case LWSWSOPC_BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +0800784 wsi->u.ws.frame_is_binary =
Andy Green54806b12015-12-17 17:03:59 +0800785 wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800786 break;
787 }
Andy Green38e57bb2011-01-19 12:20:27 +0000788 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
789 break;
790
791 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000792
Andy Green623a98d2013-01-21 11:04:23 +0800793 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100794
Andy Green5bf65782011-09-25 10:46:31 +0100795 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000796 case 126:
797 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800798 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100799 goto illegal_ctl_length;
800
Andy Green38e57bb2011-01-19 12:20:27 +0000801 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
802 break;
803 case 127:
804 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800805 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100806 goto illegal_ctl_length;
807
Andy Green38e57bb2011-01-19 12:20:27 +0000808 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
809 break;
810 default:
Andy Green623a98d2013-01-21 11:04:23 +0800811 wsi->u.ws.rx_packet_length = c & 0x7f;
812 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100813 wsi->lws_rx_parse_state =
814 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
815 else
Andy Green8ea19552014-02-15 16:00:37 +0800816 if (wsi->u.ws.rx_packet_length)
817 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000818 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800819 else {
820 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
821 goto spill;
822 }
Andy Green38e57bb2011-01-19 12:20:27 +0000823 break;
824 }
825 break;
826
827 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800828 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000829 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
830 break;
831
832 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800833 wsi->u.ws.rx_packet_length |= c;
834 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100835 wsi->lws_rx_parse_state =
836 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
837 else
838 wsi->lws_rx_parse_state =
839 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000840 break;
841
842 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000843 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800844 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000845 /* kill the connection */
846 return -1;
847 }
Andy Greenf55830d2011-01-27 06:45:53 +0000848#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800849 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000850#else
Andy Green623a98d2013-01-21 11:04:23 +0800851 wsi->u.ws.rx_packet_length = 0;
Andy Greenf55830d2011-01-27 06:45:53 +0000852#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000853 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
854 break;
855
856 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000857#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800858 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000859#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000860 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
861 break;
862
863 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000864#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800865 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Greenf55830d2011-01-27 06:45:53 +0000866#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000867 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
868 break;
869
870 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
Andy Greenf55830d2011-01-27 06:45:53 +0000871#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800872 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Greenf55830d2011-01-27 06:45:53 +0000873#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000874 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
875 break;
876
877 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800878 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000879 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
880 break;
881
882 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800883 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000884 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
885 break;
886
887 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800888 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000889 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
890 break;
891
892 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800893 wsi->u.ws.rx_packet_length |= ((size_t)c);
894 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100895 wsi->lws_rx_parse_state =
896 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
897 else
898 wsi->lws_rx_parse_state =
899 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000900 break;
901
Andy Green283d0a22011-04-24 05:46:23 +0100902 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green54806b12015-12-17 17:03:59 +0800903 wsi->u.ws.mask_nonce[0] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100904 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800905 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100906 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
907 break;
908
909 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green54806b12015-12-17 17:03:59 +0800910 wsi->u.ws.mask_nonce[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100911 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800912 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100913 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
914 break;
915
916 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green54806b12015-12-17 17:03:59 +0800917 wsi->u.ws.mask_nonce[2] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100918 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800919 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100920 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
921 break;
922
923 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green54806b12015-12-17 17:03:59 +0800924 wsi->u.ws.mask_nonce[3] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100925 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800926 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100927 wsi->lws_rx_parse_state =
928 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green623a98d2013-01-21 11:04:23 +0800929 wsi->u.ws.frame_mask_index = 0;
Andy Green8ea19552014-02-15 16:00:37 +0800930 if (wsi->u.ws.rx_packet_length == 0) {
931 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +0800932 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +0800933 }
Andy Green283d0a22011-04-24 05:46:23 +0100934 break;
935
936
Andy Green7c212cc2010-11-08 20:20:42 +0000937 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +0800938
Andy Greencd838502014-11-30 12:53:27 +0800939 if (!wsi->u.ws.rx_user_buffer) {
Andy Green54495112013-02-06 21:10:16 +0900940 lwsl_err("NULL user buffer...\n");
Andy Greencd838502014-11-30 12:53:27 +0800941 return 1;
942 }
Andy Green54495112013-02-06 21:10:16 +0900943
Andy Green623a98d2013-01-21 11:04:23 +0800944 if (wsi->u.ws.all_zero_nonce)
945 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
946 (wsi->u.ws.rx_user_buffer_head++)] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000947 else
Andy Green623a98d2013-01-21 11:04:23 +0800948 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
949 (wsi->u.ws.rx_user_buffer_head++)] =
Andy Green54806b12015-12-17 17:03:59 +0800950 c ^ wsi->u.ws.mask_nonce[
Andy Greenb5b23192013-02-11 17:13:32 +0800951 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green4739e5c2011-01-22 12:51:57 +0000952
Andy Green623a98d2013-01-21 11:04:23 +0800953 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800954 /* spill because we have the whole frame */
Andy Green4739e5c2011-01-22 12:51:57 +0000955 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
956 goto spill;
957 }
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800958
959 /*
960 * if there's no protocol max frame size given, we are
961 * supposed to default to LWS_MAX_SOCKET_IO_BUF
962 */
963
964 if (!wsi->protocol->rx_buffer_size &&
965 wsi->u.ws.rx_user_buffer_head !=
966 LWS_MAX_SOCKET_IO_BUF)
Andy Green4739e5c2011-01-22 12:51:57 +0000967 break;
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800968 else
969 if (wsi->protocol->rx_buffer_size &&
970 wsi->u.ws.rx_user_buffer_head !=
971 wsi->protocol->rx_buffer_size)
972 break;
973
974 /* spill because we filled our rx buffer */
Andy Green4739e5c2011-01-22 12:51:57 +0000975spill:
976 /*
977 * is this frame a control packet we should take care of at this
978 * layer? If so service it and hide it from the user callback
979 */
980
Andy Green43db0452013-01-10 19:50:35 +0800981 lwsl_parser("spill on %s\n", wsi->protocol->name);
Andy Greena41314f2011-05-23 10:00:03 +0100982
Andy Green623a98d2013-01-21 11:04:23 +0800983 switch (wsi->u.ws.opcode) {
Andy Green54806b12015-12-17 17:03:59 +0800984 case LWSWSOPC_CLOSE:
Andy Greenda527df2011-03-07 07:08:12 +0000985 /* is this an acknowledgement of our close? */
Andy Green54806b12015-12-17 17:03:59 +0800986 if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
Andy Greenda527df2011-03-07 07:08:12 +0000987 /*
988 * fine he has told us he is closing too, let's
989 * finish our close
990 */
Andy Green43db0452013-01-10 19:50:35 +0800991 lwsl_parser("seen client close ack\n");
Andy Greenda527df2011-03-07 07:08:12 +0000992 return -1;
993 }
Andy Green54806b12015-12-17 17:03:59 +0800994 if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY)
Andy Green40d5abc2015-04-17 20:29:58 +0800995 /* if he sends us 2 CLOSE, kill him */
996 return -1;
997
Andy Green43db0452013-01-10 19:50:35 +0800998 lwsl_parser("server sees client close packet\n");
Andy Green54806b12015-12-17 17:03:59 +0800999 wsi->state = LWSS_RETURNED_CLOSE_ALREADY;
Andy Green40d5abc2015-04-17 20:29:58 +08001000 /* deal with the close packet contents as a PONG */
1001 wsi->u.ws.payload_is_close = 1;
1002 goto process_as_ping;
Andy Green4739e5c2011-01-22 12:51:57 +00001003
Andy Green54806b12015-12-17 17:03:59 +08001004 case LWSWSOPC_PING:
Andy Greenb5b23192013-02-11 17:13:32 +08001005 lwsl_info("received %d byte ping, sending pong\n",
1006 wsi->u.ws.rx_user_buffer_head);
Andy Green82bac6b2014-08-24 14:39:19 +08001007
Andy Green2fd6e6f2015-03-24 21:07:01 +08001008 if (wsi->u.ws.ping_pending_flag) {
Andy Green40110e82015-12-14 08:52:03 +08001009 /*
Andy Green82bac6b2014-08-24 14:39:19 +08001010 * there is already a pending ping payload
1011 * we should just log and drop
1012 */
1013 lwsl_parser("DROP PING since one pending\n");
1014 goto ping_drop;
1015 }
Andy Green40d5abc2015-04-17 20:29:58 +08001016process_as_ping:
Andy Green82bac6b2014-08-24 14:39:19 +08001017 /* control packets can only be < 128 bytes long */
Andy Green106d4a82015-03-24 21:22:52 +08001018 if (wsi->u.ws.rx_user_buffer_head > 128 - 4) {
Andy Green82bac6b2014-08-24 14:39:19 +08001019 lwsl_parser("DROP PING payload too large\n");
1020 goto ping_drop;
1021 }
Andy Green40110e82015-12-14 08:52:03 +08001022
Andy Green82bac6b2014-08-24 14:39:19 +08001023 /* stash the pong payload */
1024 memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING,
1025 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
1026 wsi->u.ws.rx_user_buffer_head);
Andy Green40110e82015-12-14 08:52:03 +08001027
Andy Green82bac6b2014-08-24 14:39:19 +08001028 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head;
Andy Green2fd6e6f2015-03-24 21:07:01 +08001029 wsi->u.ws.ping_pending_flag = 1;
Andy Green40110e82015-12-14 08:52:03 +08001030
Andy Green82bac6b2014-08-24 14:39:19 +08001031 /* get it sent as soon as possible */
Andy Green11c05bf2015-12-16 18:19:08 +08001032 lws_callback_on_writable(wsi);
Andy Green82bac6b2014-08-24 14:39:19 +08001033ping_drop:
Andy Green623a98d2013-01-21 11:04:23 +08001034 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +00001035 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001036
Andy Green54806b12015-12-17 17:03:59 +08001037 case LWSWSOPC_PONG:
John Tarlton05fc6ba2015-10-05 11:35:52 +01001038 lwsl_info("received pong\n");
1039 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
1040 wsi->u.ws.rx_user_buffer_head);
1041
1042 /* issue it */
1043 callback_action = LWS_CALLBACK_RECEIVE_PONG;
1044 break;
Andy Green4739e5c2011-01-22 12:51:57 +00001045
Andy Green54806b12015-12-17 17:03:59 +08001046 case LWSWSOPC_TEXT_FRAME:
1047 case LWSWSOPC_BINARY_FRAME:
1048 case LWSWSOPC_CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +00001049 break;
Andy Greena41314f2011-05-23 10:00:03 +01001050
1051 default:
Andy Greenb5b23192013-02-11 17:13:32 +08001052 lwsl_parser("passing opc %x up to exts\n",
1053 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +01001054 /*
1055 * It's something special we can't understand here.
1056 * Pass the payload up to the extension's parsing
1057 * state machine.
1058 */
1059
Andy Green623a98d2013-01-21 11:04:23 +08001060 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Greena41314f2011-05-23 10:00:03 +01001061 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +08001062 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Greena41314f2011-05-23 10:00:03 +01001063
Andy Green54806b12015-12-17 17:03:59 +08001064 if (lws_ext_cb_wsi_active_exts(wsi,
Andy Green2c24ec02014-04-02 19:45:42 +08001065 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
1066 &eff_buf, 0) <= 0) /* not handle or fail */
Andy Greenb5b23192013-02-11 17:13:32 +08001067 lwsl_ext("ext opc opcode 0x%x unknown\n",
1068 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +01001069
Andy Green623a98d2013-01-21 11:04:23 +08001070 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +01001071 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001072 }
1073
1074 /*
1075 * No it's real payload, pass it up to the user callback.
1076 * It's nicely buffered with the pre-padding taken care of
Andy Green62304762015-12-04 08:43:54 +08001077 * so it can be sent straight out again using lws_write
Andy Green4739e5c2011-01-22 12:51:57 +00001078 */
1079
Andy Green623a98d2013-01-21 11:04:23 +08001080 eff_buf.token = &wsi->u.ws.rx_user_buffer[
David Galeanoe2cf9922013-01-09 18:06:55 +08001081 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +08001082 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green40110e82015-12-14 08:52:03 +08001083
Andy Green54806b12015-12-17 17:03:59 +08001084 if (lws_ext_cb_wsi_active_exts(wsi,
Andy Green2c24ec02014-04-02 19:45:42 +08001085 LWS_EXT_CALLBACK_PAYLOAD_RX, &eff_buf, 0) < 0)
1086 return -1;
1087
Andrejs Hanins765914c2015-12-01 14:44:33 +02001088 if (eff_buf.token_len > 0 ||
1089 callback_action == LWS_CALLBACK_RECEIVE_PONG) {
Andy Greenaedc9532013-02-10 21:21:24 +08001090 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +08001091
John Tarlton05fc6ba2015-10-05 11:35:52 +01001092 if (wsi->protocol->callback) {
1093
1094 if (callback_action == LWS_CALLBACK_RECEIVE_PONG)
1095 lwsl_info("Doing pong callback\n");
1096
Andy Greenb5b23192013-02-11 17:13:32 +08001097 ret = user_callback_handle_rxflow(
1098 wsi->protocol->callback,
John Tarlton05fc6ba2015-10-05 11:35:52 +01001099 wsi,
Andy Green4b85c1d2015-12-04 11:08:32 +08001100 (enum lws_callback_reasons)callback_action,
Andy Greenb5b23192013-02-11 17:13:32 +08001101 wsi->user_space,
1102 eff_buf.token,
1103 eff_buf.token_len);
John Tarlton05fc6ba2015-10-05 11:35:52 +01001104 }
1105 else
1106 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +08001107 }
Andy Greena41314f2011-05-23 10:00:03 +01001108
Andy Green623a98d2013-01-21 11:04:23 +08001109 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001110 break;
1111 }
1112
Andy Greenaedc9532013-02-10 21:21:24 +08001113 return ret;
Andy Green23545db2011-04-24 06:19:22 +01001114
1115illegal_ctl_length:
1116
Andy Greenb5b23192013-02-11 17:13:32 +08001117 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +01001118 /* kill the connection */
1119 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +00001120}
1121
1122
Andy Green38e57bb2011-01-19 12:20:27 +00001123/**
Andy Green62304762015-12-04 08:43:54 +08001124 * lws_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +00001125 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +00001126 * @wsi: Websocket instance (available from user callback)
1127 *
1128 * This function is intended to be called from the callback if the
1129 * user code is interested in "complete packets" from the client.
1130 * libwebsockets just passes through payload as it comes and issues a buffer
1131 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
1132 * callback handler can use this API to find out if the buffer it has just
1133 * been given is the last piece of a "complete packet" from the client --
Andy Green62304762015-12-04 08:43:54 +08001134 * when that is the case lws_remaining_packet_payload() will return
Andy Green38e57bb2011-01-19 12:20:27 +00001135 * 0.
1136 *
1137 * Many protocols won't care becuse their packets are always small.
1138 */
1139
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001140LWS_VISIBLE size_t
Andy Green4b85c1d2015-12-04 11:08:32 +08001141lws_remaining_packet_payload(struct lws *wsi)
Andy Green38e57bb2011-01-19 12:20:27 +00001142{
Andy Green623a98d2013-01-21 11:04:23 +08001143 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001144}