simplified _gnutls_writev() by requiring the total length
[gnutls:gnutls.git] / lib / gnutls_buffers.c
1 /*
2  * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>
20  *
21  */
22
23 /* 
24  * This file holds all the buffering code used in gnutls.
25  * The buffering code works as:
26  *
27  * RECORD LAYER: 
28  *  1. uses a buffer to hold data (application/handshake),
29  *    we got but they were not requested, yet.
30  *  (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
31  *
32  *  2. uses a buffer to hold data that were incomplete (ie the read/write
33  *    was interrupted)
34  *  (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
35  * 
36  * HANDSHAKE LAYER:
37  *  1. Uses buffer to hold the last received handshake message.
38  *  (see _gnutls_handshake_hash_buffer_put() etc.)
39  *
40  */
41
42 #include <gnutls_int.h>
43 #include <gnutls_errors.h>
44 #include <gnutls_num.h>
45 #include <gnutls_record.h>
46 #include <gnutls_buffers.h>
47 #include <gnutls_mbuffers.h>
48 #include <gnutls_state.h>
49 #include <gnutls_dtls.h>
50 #include <system.h>
51 #include <gnutls_constate.h>    /* gnutls_epoch_get */
52 #include <gnutls_handshake.h>   /* remaining_time() */
53 #include <errno.h>
54 #include <system.h>
55 #include "debug.h"
56
57 #ifndef EAGAIN
58 #define EAGAIN EWOULDBLOCK
59 #endif
60
61 /* this is the maximum number of messages allowed to queue.
62  */
63 #define MAX_QUEUE 32
64
65 /* Buffers received packets of type APPLICATION DATA,
66  * HANDSHAKE DATA and HEARTBEAT.
67  */
68 void
69 _gnutls_record_buffer_put(gnutls_session_t session,
70                           content_type_t type, uint64 * seq,
71                           mbuffer_st * bufel)
72 {
73
74         bufel->type = type;
75         memcpy(&bufel->record_sequence, seq, sizeof(*seq));
76
77         _mbuffer_enqueue(&session->internals.record_buffer, bufel);
78         _gnutls_buffers_log("BUF[REC]: Inserted %d bytes of Data(%d)\n",
79                             (int) bufel->msg.size, (int) type);
80
81         return;
82 }
83
84 /**
85  * gnutls_record_check_pending:
86  * @session: is a #gnutls_session_t structure.
87  *
88  * This function checks if there are unread data
89  * in the gnutls buffers. If the return value is
90  * non-zero the next call to gnutls_record_recv()
91  * is guaranteed not to block.
92  *
93  * Returns: Returns the size of the data or zero.
94  **/
95 size_t gnutls_record_check_pending(gnutls_session_t session)
96 {
97         return _gnutls_record_buffer_get_size(session);
98 }
99
100 /**
101  * gnutls_record_check_corked:
102  * @session: is a #gnutls_session_t structure.
103  *
104  * This function checks if there pending corked
105  * data in the gnutls buffers --see gnutls_record_cork(). 
106  *
107  * Returns: Returns the size of the corked data or zero.
108  *
109  * Since: 3.2.8
110  **/
111 size_t gnutls_record_check_corked(gnutls_session_t session)
112 {
113         return session->internals.record_presend_buffer.length;
114 }
115
116 int
117 _gnutls_record_buffer_get(content_type_t type,
118                           gnutls_session_t session, uint8_t * data,
119                           size_t length, uint8_t seq[8])
120 {
121         gnutls_datum_t msg;
122         mbuffer_st *bufel;
123
124         if (length == 0 || data == NULL) {
125                 gnutls_assert();
126                 return GNUTLS_E_INVALID_REQUEST;
127         }
128
129         bufel =
130             _mbuffer_head_get_first(&session->internals.record_buffer,
131                                     &msg);
132         if (bufel == NULL)
133                 return
134                     gnutls_assert_val
135                     (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
136
137         if (type != bufel->type) {
138                 if (IS_DTLS(session))
139                         _gnutls_audit_log(session,
140                                           "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
141                                           _gnutls_packet2str(bufel->type),
142                                           (int) bufel->type,
143                                           _gnutls_packet2str(type),
144                                           (int) type);
145                 else
146                         _gnutls_debug_log("received unexpected packet: %s(%d)\n",
147                                                 _gnutls_packet2str(bufel->type), (int)bufel->type);
148
149                 _mbuffer_head_remove_bytes(&session->internals.
150                                            record_buffer, msg.size);
151                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
152         }
153
154         if (msg.size <= length)
155                 length = msg.size;
156
157         if (seq)
158                 memcpy(seq, bufel->record_sequence.i, 8);
159
160         memcpy(data, msg.data, length);
161         _mbuffer_head_remove_bytes(&session->internals.record_buffer,
162                                    length);
163
164         return length;
165 }
166
167 int
168 _gnutls_record_buffer_get_packet(content_type_t type, gnutls_session_t session, gnutls_packet_t *packet)
169 {
170         mbuffer_st *bufel;
171
172         bufel =
173             _mbuffer_head_pop_first(&session->internals.record_buffer);
174         if (bufel == NULL)
175                 return
176                     gnutls_assert_val
177                     (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
178
179         if (type != bufel->type) {
180                 if (IS_DTLS(session))
181                         _gnutls_audit_log(session,
182                                           "Discarded unexpected %s (%d) packet (expecting: %s)\n",
183                                           _gnutls_packet2str(bufel->type),
184                                           (int) bufel->type,
185                                           _gnutls_packet2str(type));
186                 _mbuffer_head_remove_bytes(&session->internals.
187                                            record_buffer, bufel->msg.size);
188                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
189         }
190
191         *packet = bufel;
192
193         return bufel->msg.size - bufel->mark;
194 }
195
196 inline static void reset_errno(gnutls_session_t session)
197 {
198         session->internals.errnum = 0;
199 }
200
201 inline static int get_errno(gnutls_session_t session)
202 {
203         int ret;
204
205         if (session->internals.errnum != 0)
206                 ret = session->internals.errnum;
207         else
208                 ret =
209                     session->internals.errno_func(session->internals.
210                                                   transport_recv_ptr);
211         return ret;
212 }
213
214 inline static
215 int errno_to_gerr(int err, unsigned dtls)
216 {
217         switch (err) {
218         case EAGAIN:
219                 return GNUTLS_E_AGAIN;
220         case EINTR:
221                 return GNUTLS_E_INTERRUPTED;
222         case EMSGSIZE:
223                 if (dtls != 0)
224                         return GNUTLS_E_LARGE_PACKET;
225                 else
226                         return GNUTLS_E_PUSH_ERROR;
227         default:
228                 gnutls_assert();
229                 return GNUTLS_E_PUSH_ERROR;
230         }
231 }
232
233 static ssize_t
234 _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel,
235                    gnutls_pull_func pull_func, unsigned int *ms)
236 {
237         ssize_t i, ret;
238         uint8_t *ptr;
239         struct timespec t1, t2;
240         size_t max_size, recv_size;
241         gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
242         unsigned int diff;
243
244         max_size = max_record_recv_size(session);
245         recv_size = max_size;
246
247         session->internals.direction = 0;
248
249         if (ms && *ms > 0) {
250                 ret = _gnutls_io_check_recv(session, *ms);
251                 if (ret < 0)
252                         return gnutls_assert_val(ret);
253                 gettime(&t1);
254         }
255
256         *bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session));
257         if (*bufel == NULL)
258                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
259
260         ptr = (*bufel)->msg.data;
261
262         reset_errno(session);
263         i = pull_func(fd, ptr, recv_size);
264
265         if (i < 0) {
266                 int err = get_errno(session);
267
268                 _gnutls_read_log
269                     ("READ: %d returned from %p, errno=%d gerrno=%d\n",
270                      (int) i, fd, errno, session->internals.errnum);
271
272                 ret = errno_to_gerr(err, 1);
273                 goto cleanup;
274         } else {
275                 _gnutls_read_log("READ: Got %d bytes from %p\n", (int) i,
276                                  fd);
277                 if (i == 0) {
278                         /* If we get here, we likely have a stream socket.
279                          * FIXME: this probably breaks DCCP. */
280                         gnutls_assert();
281                         ret = 0;
282                         goto cleanup;
283                 }
284
285                 _mbuffer_set_udata_size(*bufel, i);
286         }
287
288         if (ms && *ms > 0) {
289                 gettime(&t2);
290                 diff = timespec_sub_ms(&t2, &t1);
291                 if (diff < *ms)
292                         *ms -= diff;
293                 else {
294                         ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
295                         goto cleanup;
296                 }
297         }
298
299         _gnutls_read_log("READ: read %d bytes from %p\n", (int) i, fd);
300
301         return i;
302
303       cleanup:
304         _mbuffer_xfree(bufel);
305         return ret;
306 }
307
308 static ssize_t
309 _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel,
310                     size_t size, gnutls_pull_func pull_func,
311                     unsigned int *ms)
312 {
313         size_t left;
314         ssize_t i = 0;
315         size_t max_size = max_record_recv_size(session);
316         uint8_t *ptr;
317         gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
318         int ret;
319         struct timespec t1, t2;
320         unsigned int diff;
321
322         session->internals.direction = 0;
323
324         *bufel = _mbuffer_alloc_align16(MAX(max_size, size), get_total_headers(session));
325         if (!*bufel) {
326                 gnutls_assert();
327                 return GNUTLS_E_MEMORY_ERROR;
328         }
329         ptr = (*bufel)->msg.data;
330
331         left = size;
332         while (left > 0) {
333                 if (ms && *ms > 0) {
334                         ret = _gnutls_io_check_recv(session, *ms);
335                         if (ret < 0) {
336                                 gnutls_assert();
337                                 goto cleanup;
338                         }
339
340                         gettime(&t1);
341                 }
342
343                 reset_errno(session);
344
345                 i = pull_func(fd, &ptr[size - left], left);
346
347                 if (i < 0) {
348                         int err = get_errno(session);
349
350                         _gnutls_read_log
351                             ("READ: %d returned from %p, errno=%d gerrno=%d\n",
352                              (int) i, fd, errno,
353                              session->internals.errnum);
354
355                         if (err == EAGAIN || err == EINTR) {
356                                 if (size - left > 0) {
357
358                                         _gnutls_read_log
359                                             ("READ: returning %d bytes from %p\n",
360                                              (int) (size - left), fd);
361
362                                         goto finish;
363                                 }
364
365                                 ret = errno_to_gerr(err, 0);
366                                 goto cleanup;
367                         } else {
368                                 gnutls_assert();
369                                 ret = GNUTLS_E_PULL_ERROR;
370                                 goto cleanup;
371                         }
372                 } else {
373
374                         _gnutls_read_log("READ: Got %d bytes from %p\n",
375                                          (int) i, fd);
376
377                         if (i == 0)
378                                 break;  /* EOF */
379                 }
380
381                 left -= i;
382                 (*bufel)->msg.size += i;
383
384                 if (ms && *ms > 0) {
385                         gettime(&t2);
386                         diff = timespec_sub_ms(&t2, &t1);
387                         if (diff < *ms)
388                                 *ms -= diff;
389                         else {
390                                 ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
391                                 goto cleanup;
392                         }
393                 }
394         }
395
396       finish:
397
398         _gnutls_read_log("READ: read %d bytes from %p\n",
399                          (int) (size - left), fd);
400
401         if (size - left == 0)
402                 _mbuffer_xfree(bufel);
403
404         return (size - left);
405
406       cleanup:
407         _mbuffer_xfree(bufel);
408         return ret;
409 }
410
411
412 /* This function is like read. But it does not return -1 on error.
413  * It does return gnutls_errno instead.
414  *
415  * Flags are only used if the default recv() function is being used.
416  */
417 static ssize_t
418 _gnutls_read(gnutls_session_t session, mbuffer_st ** bufel,
419              size_t size, gnutls_pull_func pull_func, unsigned int *ms)
420 {
421         if (IS_DTLS(session))
422                 /* Size is not passed, since a whole datagram will be read. */
423                 return _gnutls_dgram_read(session, bufel, pull_func, ms);
424         else
425                 return _gnutls_stream_read(session, bufel, size, pull_func,
426                                            ms);
427 }
428
429 /* @vec: if non-zero then the vector function will be used to
430  *       push the data.
431  */
432 static ssize_t
433 _gnutls_writev_emu(gnutls_session_t session, gnutls_transport_ptr_t fd,
434                    const giovec_t * giovec, unsigned int giovec_cnt, unsigned vec)
435 {
436         unsigned int j = 0;
437         size_t total = 0;
438         ssize_t ret = 0;
439
440         for (j = 0; j < giovec_cnt; j++) {
441                 if (vec) {
442                         ret = session->internals.vec_push_func(fd, &giovec[j], 1);
443                 } else {
444                         ret =
445                             session->internals.push_func(fd, giovec[j].iov_base,
446                                                          giovec[j].iov_len);
447                 }
448
449                 if (ret == -1) {
450                         gnutls_assert();
451                         break;
452                 }
453
454                 total += ret;
455
456                 if ((size_t) ret != giovec[j].iov_len)
457                         break;
458         }
459
460         if (total > 0)
461                 return total;
462
463         return ret;
464 }
465
466 /* @total: The sum of the data in giovec
467  */
468 static ssize_t
469 _gnutls_writev(gnutls_session_t session, const giovec_t * giovec,
470                unsigned giovec_cnt, unsigned total)
471 {
472         int i;
473         bool is_dtls = IS_DTLS(session);
474         unsigned no_writev = 0;
475         gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
476
477         reset_errno(session);
478
479         if (session->internals.vec_push_func != NULL) {
480                 if (is_dtls && giovec_cnt > 1) {
481                         if (total > session->internals.dtls.mtu) {
482                                 no_writev = 1;
483                         }
484                 }
485
486                 if (no_writev == 0) {
487                         i = session->internals.vec_push_func(fd, giovec,
488                                                              giovec_cnt);
489                 } else {
490                         i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 1);
491                 }
492         } else if (session->internals.push_func != NULL) {
493                 i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 0);
494         } else
495                 return gnutls_assert_val(GNUTLS_E_PUSH_ERROR);
496
497         if (i == -1) {
498                 int err = get_errno(session);
499                 _gnutls_debug_log("errno: %d\n", err);
500
501                 return errno_to_gerr(err, is_dtls);
502         }
503         return i;
504 }
505
506 /* 
507  * @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
508  *
509  * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
510  * It does return gnutls_errno instead.
511  * This function reads data from the socket and keeps them in a buffer, of up to
512  * max_record_recv_size. 
513  *
514  * This is not a general purpose function. It returns EXACTLY the data requested,
515  * which are stored in a local (in the session) buffer.
516  *
517  * If the @ms parameter is non zero then this function will return before
518  * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
519  *
520  */
521 ssize_t
522 _gnutls_io_read_buffered(gnutls_session_t session, size_t total,
523                          content_type_t recv_type, unsigned int *ms)
524 {
525         ssize_t ret;
526         size_t min;
527         mbuffer_st *bufel = NULL;
528         size_t recvdata, readsize;
529
530         if (total > max_record_recv_size(session) || total == 0) {
531                 gnutls_assert();        /* internal error */
532                 return GNUTLS_E_INVALID_REQUEST;
533         }
534
535         /* calculate the actual size, ie. get the minimum of the
536          * buffered data and the requested data.
537          */
538         min =
539             MIN(session->internals.record_recv_buffer.byte_length, total);
540         if (min > 0) {
541                 /* if we have enough buffered data
542                  * then just return them.
543                  */
544                 if (min == total) {
545                         return min;
546                 }
547         }
548
549         /* min is over zero. recvdata is the data we must
550          * receive in order to return the requested data.
551          */
552         recvdata = total - min;
553         readsize = recvdata;
554
555         /* Check if the previously read data plus the new data to
556          * receive are longer than the maximum receive buffer size.
557          */
558         if ((session->internals.record_recv_buffer.byte_length +
559              recvdata) > max_record_recv_size(session)) {
560                 gnutls_assert();        /* internal error */
561                 return GNUTLS_E_INVALID_REQUEST;
562         }
563
564         /* READ DATA
565          */
566         if (readsize > 0) {
567                 ret =
568                     _gnutls_read(session, &bufel, readsize,
569                                  session->internals.pull_func, ms);
570
571                 /* return immediately if we got an interrupt or eagain
572                  * error.
573                  */
574                 if (ret < 0) {
575                         return gnutls_assert_val(ret);
576                 }
577
578                 if (ret == 0)   /* EOF */
579                         return gnutls_assert_val(0);
580
581                 /* copy fresh data to our buffer.
582                  */
583                 _gnutls_read_log
584                     ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
585                      (int) session->internals.record_recv_buffer.
586                      byte_length, (int) ret);
587                 _gnutls_read_log("RB: Requested %d bytes\n", (int) total);
588
589                 _mbuffer_enqueue(&session->internals.record_recv_buffer,
590                                  bufel);
591
592                 if (IS_DTLS(session))
593                         ret =
594                             MIN(total,
595                                 session->internals.record_recv_buffer.
596                                 byte_length);
597                 else
598                         ret =
599                             session->internals.record_recv_buffer.
600                             byte_length;
601
602                 if ((ret > 0) && ((size_t) ret < total))        /* Short Read */
603                         return gnutls_assert_val(GNUTLS_E_AGAIN);
604                 else
605                         return ret;
606         } else
607                 return gnutls_assert_val(0);
608 }
609
610 /* This function is like write. But it does not return -1 on error.
611  * It does return gnutls_errno instead.
612  *
613  * This function takes full responsibility of freeing msg->data.
614  *
615  * In case of E_AGAIN and E_INTERRUPTED errors, you must call
616  * gnutls_write_flush(), until it returns ok (0).
617  *
618  * We need to push exactly the data in msg->size, since we cannot send
619  * less data. In TLS the peer must receive the whole packet in order
620  * to decrypt and verify the integrity.
621  *
622  */
623 ssize_t
624 _gnutls_io_write_buffered(gnutls_session_t session,
625                           mbuffer_st * bufel, unsigned int mflag)
626 {
627         mbuffer_head_st *const send_buffer =
628             &session->internals.record_send_buffer;
629
630         /* to know where the procedure was interrupted.
631          */
632         session->internals.direction = 1;
633
634         _mbuffer_enqueue(send_buffer, bufel);
635
636         _gnutls_write_log
637             ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
638              (int) bufel->msg.size, session->internals.transport_recv_ptr,
639              (int) send_buffer->byte_length);
640
641         if (mflag == MBUFFER_FLUSH)
642                 return _gnutls_io_write_flush(session);
643         else
644                 return bufel->msg.size;
645 }
646
647 typedef ssize_t(*send_func) (gnutls_session_t, const giovec_t *, int);
648
649 /* This function writes the data that are left in the
650  * TLS write buffer (ie. because the previous write was
651  * interrupted.
652  */
653 ssize_t _gnutls_io_write_flush(gnutls_session_t session)
654 {
655         gnutls_datum_t msg;
656         mbuffer_head_st *send_buffer =
657             &session->internals.record_send_buffer;
658         int ret;
659         ssize_t sent = 0, tosend = 0;
660         giovec_t iovec[MAX_QUEUE];
661         int i = 0;
662         mbuffer_st *cur;
663
664         _gnutls_write_log("WRITE FLUSH: %d bytes in buffer.\n",
665                           (int) send_buffer->byte_length);
666
667         for (cur = _mbuffer_head_get_first(send_buffer, &msg);
668              cur != NULL; cur = _mbuffer_head_get_next(cur, &msg)) {
669                 iovec[i].iov_base = msg.data;
670                 iovec[i++].iov_len = msg.size;
671                 tosend += msg.size;
672
673                 /* we buffer up to MAX_QUEUE messages */
674                 if (i >= MAX_QUEUE) {
675                         gnutls_assert();
676                         return GNUTLS_E_INTERNAL_ERROR;
677                 }
678         }
679
680         if (tosend == 0) {
681                 gnutls_assert();
682                 return 0;
683         }
684
685         ret = _gnutls_writev(session, iovec, i, tosend);
686         if (ret >= 0) {
687                 _mbuffer_head_remove_bytes(send_buffer, ret);
688                 _gnutls_write_log
689                     ("WRITE: wrote %d bytes, %d bytes left.\n", ret,
690                      (int) send_buffer->byte_length);
691
692                 sent += ret;
693         } else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
694                 _gnutls_write_log("WRITE interrupted: %d bytes left.\n",
695                                   (int) send_buffer->byte_length);
696                 return ret;
697         } else if (ret == GNUTLS_E_LARGE_PACKET) {
698                 _mbuffer_head_remove_bytes(send_buffer, tosend);
699                 _gnutls_write_log
700                     ("WRITE cannot send large packet (%u bytes).\n",
701                      (unsigned int) tosend);
702                 return ret;
703         } else {
704                 _gnutls_write_log("WRITE error: code %d, %d bytes left.\n",
705                                   ret, (int) send_buffer->byte_length);
706
707                 gnutls_assert();
708                 return ret;
709         }
710
711         if (sent < tosend) {
712                 return gnutls_assert_val(GNUTLS_E_AGAIN);
713         }
714
715         return sent;
716 }
717
718 /* Checks whether there are received data within
719  * a timeframe.
720  *
721  * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
722  * on timeout and a negative error code on error.
723  */
724 int _gnutls_io_check_recv(gnutls_session_t session, unsigned int ms)
725 {
726         gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
727         int ret = 0, err;
728
729         if (unlikely
730             (session->internals.pull_timeout_func == system_recv_timeout
731              && session->internals.pull_func != system_read)) {
732                 _gnutls_debug_log("The pull function has been replaced but not the pull timeout.");
733                 return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
734         }
735
736         reset_errno(session);
737
738         ret = session->internals.pull_timeout_func(fd, ms);
739         if (ret == -1) {
740                 err = get_errno(session);
741                 _gnutls_read_log
742                     ("READ_TIMEOUT: %d returned from %p, errno=%d (timeout: %u)\n",
743                      (int) ret, fd, err, ms);
744                 return errno_to_gerr(err, IS_DTLS(session));
745         }
746
747         if (ret > 0)
748                 return 0;
749         else
750                 return GNUTLS_E_TIMEDOUT;
751 }
752
753 /* HANDSHAKE buffers part 
754  */
755
756 /* This function writes the data that are left in the
757  * Handshake write buffer (ie. because the previous write was
758  * interrupted.
759  *
760  */
761 ssize_t _gnutls_handshake_io_write_flush(gnutls_session_t session)
762 {
763         mbuffer_head_st *const send_buffer =
764             &session->internals.handshake_send_buffer;
765         gnutls_datum_t msg;
766         int ret;
767         uint16_t epoch;
768         ssize_t total = 0;
769         mbuffer_st *cur;
770
771         _gnutls_write_log("HWRITE FLUSH: %d bytes in buffer.\n",
772                           (int) send_buffer->byte_length);
773
774         if (IS_DTLS(session))
775                 return _dtls_transmit(session);
776
777         for (cur = _mbuffer_head_get_first(send_buffer, &msg);
778              cur != NULL; cur = _mbuffer_head_get_first(send_buffer, &msg))
779         {
780                 epoch = cur->epoch;
781
782                 ret = _gnutls_send_int(session, cur->type,
783                                        cur->htype,
784                                        epoch, msg.data, msg.size, 0);
785
786                 if (ret >= 0) {
787                         total += ret;
788
789                         ret = _mbuffer_head_remove_bytes(send_buffer, ret);
790                         if (ret == 1)
791                                 _gnutls_epoch_refcount_dec(session, epoch);
792
793                         _gnutls_write_log
794                             ("HWRITE: wrote %d bytes, %d bytes left.\n",
795                              ret, (int) send_buffer->byte_length);
796
797                 } else {
798                         _gnutls_write_log
799                             ("HWRITE error: code %d, %d bytes left.\n",
800                              ret, (int) send_buffer->byte_length);
801
802                         gnutls_assert();
803                         return ret;
804                 }
805         }
806
807         return _gnutls_io_write_flush(session);
808 }
809
810
811 /* This is a send function for the gnutls handshake 
812  * protocol. Just makes sure that all data have been sent.
813  *
814  */
815 int
816 _gnutls_handshake_io_cache_int(gnutls_session_t session,
817                                gnutls_handshake_description_t htype,
818                                mbuffer_st * bufel)
819 {
820         mbuffer_head_st *send_buffer;
821
822         if (IS_DTLS(session)) {
823                 bufel->handshake_sequence =
824                     session->internals.dtls.hsk_write_seq - 1;
825         }
826
827         send_buffer = &session->internals.handshake_send_buffer;
828
829         bufel->epoch =
830             (uint16_t) _gnutls_epoch_refcount_inc(session,
831                                                   EPOCH_WRITE_CURRENT);
832         bufel->htype = htype;
833         if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
834                 bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
835         else
836                 bufel->type = GNUTLS_HANDSHAKE;
837
838         _mbuffer_enqueue(send_buffer, bufel);
839
840         _gnutls_write_log
841             ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
842              _gnutls_handshake2str(bufel->htype), (int) bufel->msg.size,
843              (int) send_buffer->byte_length);
844
845         return 0;
846 }
847
848 static int handshake_compare(const void *_e1, const void *_e2)
849 {
850         const handshake_buffer_st *e1 = _e1;
851         const handshake_buffer_st *e2 = _e2;
852
853         if (e1->sequence <= e2->sequence)
854                 return 1;
855         else
856                 return -1;
857 }
858
859 #define SSL2_HEADERS 1
860 static int
861 parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
862                        handshake_buffer_st * hsk)
863 {
864         uint8_t *dataptr = NULL;        /* for realloc */
865         size_t handshake_header_size =
866             HANDSHAKE_HEADER_SIZE(session), data_size;
867
868         /* Note: SSL2_HEADERS == 1 */
869         if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
870                 return
871                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
872
873         dataptr = _mbuffer_get_udata_ptr(bufel);
874
875         /* if reading a client hello of SSLv2 */
876         if (unlikely
877             (!IS_DTLS(session)
878              && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
879                 handshake_header_size = SSL2_HEADERS;   /* we've already read one byte */
880
881                 hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size;   /* we've read the first byte */
882
883                 if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
884                         return
885                             gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
886
887                 hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
888
889                 hsk->sequence = 0;
890                 hsk->start_offset = 0;
891                 hsk->end_offset = hsk->length;
892         } else {                /* TLS or DTLS handshake headers */
893
894
895                 hsk->htype = dataptr[0];
896
897                 /* we do not use DECR_LEN because we know
898                  * that the packet has enough data.
899                  */
900                 hsk->length = _gnutls_read_uint24(&dataptr[1]);
901                 handshake_header_size = HANDSHAKE_HEADER_SIZE(session);
902
903                 if (IS_DTLS(session)) {
904                         hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
905                         hsk->start_offset =
906                             _gnutls_read_uint24(&dataptr[6]);
907                         hsk->end_offset =
908                             hsk->start_offset +
909                             _gnutls_read_uint24(&dataptr[9]);
910                 } else {
911                         hsk->sequence = 0;
912                         hsk->start_offset = 0;
913                         hsk->end_offset =
914                             MIN((_mbuffer_get_udata_size(bufel) -
915                                  handshake_header_size), hsk->length);
916                 }
917         }
918         data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
919
920         /* make the length offset */
921         if (hsk->end_offset > 0)
922                 hsk->end_offset--;
923
924         _gnutls_handshake_log
925             ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
926              session, _gnutls_handshake2str(hsk->htype),
927              (unsigned) hsk->htype, (int) hsk->length, (int) data_size,
928              hsk->start_offset, hsk->end_offset - hsk->start_offset + 1,
929              (int) hsk->sequence);
930
931         hsk->header_size = handshake_header_size;
932         memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
933                handshake_header_size);
934
935         if (hsk->length > 0 &&
936             (hsk->end_offset - hsk->start_offset >= data_size))
937                 return
938                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
939
940         if (hsk->length > 0 && (hsk->start_offset >= hsk->end_offset ||
941                                 hsk->end_offset - hsk->start_offset >=
942                                 data_size
943                                 || hsk->end_offset >= hsk->length))
944                 return
945                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
946         else if (hsk->length == 0 && hsk->end_offset != 0
947                  && hsk->start_offset != 0)
948                 return
949                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
950
951         return handshake_header_size;
952 }
953
954 static void _gnutls_handshake_buffer_move(handshake_buffer_st * dst,
955                                           handshake_buffer_st * src)
956 {
957         memcpy(dst, src, sizeof(*dst));
958         memset(src, 0, sizeof(*src));
959         src->htype = -1;
960 }
961
962 /* will merge the given handshake_buffer_st to the handshake_recv_buffer
963  * list. The given hsk packet will be released in any case (success or failure).
964  * Only used in DTLS.
965  */
966 static int merge_handshake_packet(gnutls_session_t session,
967                                   handshake_buffer_st * hsk)
968 {
969         int exists = 0, i, pos = 0;
970         int ret;
971
972         for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
973                 if (session->internals.handshake_recv_buffer[i].htype ==
974                     hsk->htype) {
975                         exists = 1;
976                         pos = i;
977                         break;
978                 }
979         }
980
981         if (exists == 0)
982                 pos = session->internals.handshake_recv_buffer_size;
983
984         if (pos >= MAX_HANDSHAKE_MSGS)
985                 return
986                     gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
987
988         if (exists == 0) {
989                 if (hsk->length > 0 && hsk->end_offset > 0
990                     && hsk->end_offset - hsk->start_offset + 1 !=
991                     hsk->length) {
992                         ret =
993                             _gnutls_buffer_resize(&hsk->data, hsk->length);
994                         if (ret < 0)
995                                 return gnutls_assert_val(ret);
996
997                         hsk->data.length = hsk->length;
998
999                         memmove(&hsk->data.data[hsk->start_offset],
1000                                 hsk->data.data,
1001                                 hsk->end_offset - hsk->start_offset + 1);
1002                 }
1003
1004                 session->internals.handshake_recv_buffer_size++;
1005
1006                 /* rewrite headers to make them look as each packet came as a single fragment */
1007                 _gnutls_write_uint24(hsk->length, &hsk->header[1]);
1008                 _gnutls_write_uint24(0, &hsk->header[6]);
1009                 _gnutls_write_uint24(hsk->length, &hsk->header[9]);
1010
1011                 _gnutls_handshake_buffer_move(&session->internals.
1012                                               handshake_recv_buffer[pos],
1013                                               hsk);
1014
1015         } else {
1016                 if (hsk->start_offset <
1017                     session->internals.handshake_recv_buffer[pos].
1018                     start_offset
1019                     && hsk->end_offset >=
1020                     session->internals.handshake_recv_buffer[pos].
1021                     start_offset) {
1022                         memcpy(&session->internals.
1023                                handshake_recv_buffer[pos].data.data[hsk->
1024                                                                     start_offset],
1025                                hsk->data.data, hsk->data.length);
1026                         session->internals.handshake_recv_buffer[pos].
1027                             start_offset = hsk->start_offset;
1028                         session->internals.handshake_recv_buffer[pos].
1029                             end_offset =
1030                             MIN(hsk->end_offset,
1031                                 session->internals.
1032                                 handshake_recv_buffer[pos].end_offset);
1033                 } else if (hsk->end_offset >
1034                            session->internals.handshake_recv_buffer[pos].
1035                            end_offset
1036                            && hsk->start_offset <=
1037                            session->internals.handshake_recv_buffer[pos].
1038                            end_offset + 1) {
1039                         memcpy(&session->internals.
1040                                handshake_recv_buffer[pos].data.data[hsk->
1041                                                                     start_offset],
1042                                hsk->data.data, hsk->data.length);
1043
1044                         session->internals.handshake_recv_buffer[pos].
1045                             end_offset = hsk->end_offset;
1046                         session->internals.handshake_recv_buffer[pos].
1047                             start_offset =
1048                             MIN(hsk->start_offset,
1049                                 session->internals.
1050                                 handshake_recv_buffer[pos].start_offset);
1051                 }
1052                 _gnutls_handshake_buffer_clear(hsk);
1053         }
1054
1055         return 0;
1056 }
1057
1058 /* returns non-zero on match and zero on mismatch
1059  */
1060 inline static int cmp_hsk_types(gnutls_handshake_description_t expected,
1061                                 gnutls_handshake_description_t recvd)
1062 {
1063         if ((expected != GNUTLS_HANDSHAKE_CLIENT_HELLO
1064              || recvd != GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
1065             && (expected != recvd))
1066                 return 0;
1067
1068         return 1;
1069 }
1070
1071 #define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1)
1072
1073 /* returns the last stored handshake packet.
1074  */
1075 static int get_last_packet(gnutls_session_t session,
1076                            gnutls_handshake_description_t htype,
1077                            handshake_buffer_st * hsk,
1078                            unsigned int optional)
1079 {
1080         handshake_buffer_st *recv_buf =
1081             session->internals.handshake_recv_buffer;
1082
1083         if (IS_DTLS(session)) {
1084                 if (session->internals.handshake_recv_buffer_size == 0 ||
1085                     (session->internals.dtls.hsk_read_seq !=
1086                      recv_buf[LAST_ELEMENT].sequence))
1087                         goto timeout;
1088
1089                 if (htype != recv_buf[LAST_ELEMENT].htype) {
1090                         if (optional == 0)
1091                                 _gnutls_audit_log(session,
1092                                                   "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
1093                                                   _gnutls_handshake2str
1094                                                   (recv_buf[0].htype),
1095                                                   (int) recv_buf[0].htype,
1096                                                   _gnutls_handshake2str
1097                                                   (htype), (int) htype);
1098
1099                         return
1100                             gnutls_assert_val
1101                             (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
1102                 }
1103
1104                 else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
1105                           recv_buf[LAST_ELEMENT].end_offset ==
1106                           recv_buf[LAST_ELEMENT].length - 1)
1107                          || recv_buf[LAST_ELEMENT].length == 0) {
1108                         session->internals.dtls.hsk_read_seq++;
1109                         _gnutls_handshake_buffer_move(hsk,
1110                                                       &recv_buf
1111                                                       [LAST_ELEMENT]);
1112                         session->internals.handshake_recv_buffer_size--;
1113                         return 0;
1114                 } else {
1115                         /* if we don't have a complete handshake message, but we
1116                          * have queued data waiting, try again to reconstruct the
1117                          * handshake packet, using the queued */
1118                         if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
1119                             record_check_unprocessed(session) > 0)
1120                                 return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
1121                         else
1122                                 goto timeout;
1123                 }
1124         } else {                /* TLS */
1125
1126                 if (session->internals.handshake_recv_buffer_size > 0
1127                     && recv_buf[0].length == recv_buf[0].data.length) {
1128                         if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) {
1129                                 return
1130                                     gnutls_assert_val
1131                                     (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
1132                         }
1133
1134                         _gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
1135                         session->internals.handshake_recv_buffer_size--;
1136                         return 0;
1137                 } else
1138                         return
1139                             gnutls_assert_val
1140                             (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1141         }
1142
1143       timeout:
1144         RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
1145 }
1146
1147 /* This is a receive function for the gnutls handshake 
1148  * protocol. Makes sure that we have received all data.
1149  *
1150  * htype is the next handshake packet expected.
1151  */
1152 int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
1153 {
1154         gnutls_datum_t msg;
1155         mbuffer_st *bufel = NULL, *prev = NULL;
1156         int ret;
1157         size_t data_size;
1158         handshake_buffer_st *recv_buf =
1159             session->internals.handshake_recv_buffer;
1160
1161         bufel =
1162             _mbuffer_head_get_first(&session->internals.record_buffer,
1163                                     &msg);
1164         if (bufel == NULL)
1165                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1166
1167         if (!IS_DTLS(session)) {
1168                 ssize_t remain, append, header_size;
1169
1170                 do {
1171                         if (bufel->type != GNUTLS_HANDSHAKE)
1172                                 return
1173                                     gnutls_assert_val
1174                                     (GNUTLS_E_UNEXPECTED_PACKET);
1175
1176                         /* if we have a half received message the complete it.
1177                          */
1178                         remain = recv_buf[0].length -
1179                             recv_buf[0].data.length;
1180
1181                         /* this is the rest of a previous message */
1182                         if (session->internals.handshake_recv_buffer_size >
1183                             0 && recv_buf[0].length > 0 && remain > 0) {
1184                                 if ((ssize_t) msg.size <= remain)
1185                                         append = msg.size;
1186                                 else
1187                                         append = remain;
1188
1189                                 ret =
1190                                     _gnutls_buffer_append_data(&recv_buf
1191                                                                [0].data,
1192                                                                msg.data,
1193                                                                append);
1194                                 if (ret < 0)
1195                                         return gnutls_assert_val(ret);
1196
1197                                 _mbuffer_head_remove_bytes(&session->
1198                                                            internals.
1199                                                            record_buffer,
1200                                                            append);
1201                         } else {        /* received new message */
1202
1203                                 ret =
1204                                     parse_handshake_header(session, bufel,
1205                                                            &recv_buf[0]);
1206                                 if (ret < 0)
1207                                         return gnutls_assert_val(ret);
1208
1209                                 header_size = ret;
1210                                 session->internals.
1211                                     handshake_recv_buffer_size = 1;
1212
1213                                 _mbuffer_set_uhead_size(bufel,
1214                                                         header_size);
1215
1216                                 data_size =
1217                                     MIN(recv_buf[0].length,
1218                                         _mbuffer_get_udata_size(bufel));
1219                                 ret =
1220                                     _gnutls_buffer_append_data(&recv_buf
1221                                                                [0].data,
1222                                                                _mbuffer_get_udata_ptr
1223                                                                (bufel),
1224                                                                data_size);
1225                                 if (ret < 0)
1226                                         return gnutls_assert_val(ret);
1227                                 _mbuffer_set_uhead_size(bufel, 0);
1228                                 _mbuffer_head_remove_bytes(&session->
1229                                                            internals.
1230                                                            record_buffer,
1231                                                            data_size +
1232                                                            header_size);
1233                         }
1234
1235                         /* if packet is complete then return it
1236                          */
1237                         if (recv_buf[0].length == recv_buf[0].data.length) {
1238                                 return 0;
1239                         }
1240                         bufel =
1241                             _mbuffer_head_get_first(&session->internals.
1242                                                     record_buffer, &msg);
1243                 }
1244                 while (bufel != NULL);
1245
1246                 /* if we are here it means that the received packets were not
1247                  * enough to complete the handshake packet.
1248                  */
1249                 return gnutls_assert_val(GNUTLS_E_AGAIN);
1250         } else {                /* DTLS */
1251
1252                 handshake_buffer_st tmp;
1253
1254                 do {
1255                         /* we now 
1256                          * 0. parse headers
1257                          * 1. insert to handshake_recv_buffer
1258                          * 2. sort handshake_recv_buffer on sequence numbers
1259                          * 3. return first packet if completed or GNUTLS_E_AGAIN.
1260                          */
1261                         do {
1262                                 if (bufel->type != GNUTLS_HANDSHAKE) {
1263                                         gnutls_assert();
1264                                         goto next;      /* ignore packet */
1265                                 }
1266
1267                                 _gnutls_handshake_buffer_init(&tmp);
1268
1269                                 ret =
1270                                     parse_handshake_header(session, bufel,
1271                                                            &tmp);
1272                                 if (ret < 0) {
1273                                         gnutls_assert();
1274                                         _gnutls_audit_log(session,
1275                                                           "Invalid handshake packet headers. Discarding.\n");
1276                                         break;
1277                                 }
1278
1279                                 _mbuffer_consume(&session->internals.
1280                                                  record_buffer, bufel,
1281                                                  ret);
1282
1283                                 data_size =
1284                                     MIN(tmp.length,
1285                                         tmp.end_offset - tmp.start_offset +
1286                                         1);
1287
1288                                 ret =
1289                                     _gnutls_buffer_append_data(&tmp.data,
1290                                                                _mbuffer_get_udata_ptr
1291                                                                (bufel),
1292                                                                data_size);
1293                                 if (ret < 0)
1294                                         return gnutls_assert_val(ret);
1295
1296                                 _mbuffer_consume(&session->internals.
1297                                                  record_buffer, bufel,
1298                                                  data_size);
1299
1300                                 ret =
1301                                     merge_handshake_packet(session, &tmp);
1302                                 if (ret < 0)
1303                                         return gnutls_assert_val(ret);
1304
1305                         }
1306                         while (_mbuffer_get_udata_size(bufel) > 0);
1307
1308                         prev = bufel;
1309                         bufel =
1310                             _mbuffer_dequeue(&session->internals.
1311                                              record_buffer, bufel);
1312
1313                         _mbuffer_xfree(&prev);
1314                         continue;
1315
1316                       next:
1317                         bufel = _mbuffer_head_get_next(bufel, NULL);
1318                 }
1319                 while (bufel != NULL);
1320
1321                 /* sort in descending order */
1322                 if (session->internals.handshake_recv_buffer_size > 1)
1323                         qsort(recv_buf,
1324                               session->internals.
1325                               handshake_recv_buffer_size,
1326                               sizeof(recv_buf[0]), handshake_compare);
1327
1328                 while (session->internals.handshake_recv_buffer_size > 0 &&
1329                        recv_buf[LAST_ELEMENT].sequence <
1330                        session->internals.dtls.hsk_read_seq) {
1331                         _gnutls_audit_log(session,
1332                                           "Discarded replayed handshake packet with sequence %d\n",
1333                                           recv_buf[LAST_ELEMENT].sequence);
1334                         _gnutls_handshake_buffer_clear(&recv_buf
1335                                                        [LAST_ELEMENT]);
1336                         session->internals.handshake_recv_buffer_size--;
1337                 }
1338
1339                 return 0;
1340         }
1341 }
1342
1343 /* This is a receive function for the gnutls handshake 
1344  * protocol. Makes sure that we have received all data.
1345  */
1346 ssize_t
1347 _gnutls_handshake_io_recv_int(gnutls_session_t session,
1348                               gnutls_handshake_description_t htype,
1349                               handshake_buffer_st * hsk,
1350                               unsigned int optional)
1351 {
1352         int ret;
1353         unsigned int tleft = 0;
1354         int retries = 7;
1355
1356         ret = get_last_packet(session, htype, hsk, optional);
1357         if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED
1358             && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1359                 return gnutls_assert_val(ret);
1360         }
1361
1362         /* try using the already existing records before
1363          * trying to receive.
1364          */
1365         ret = _gnutls_parse_record_buffered_msgs(session);
1366
1367         if (ret == 0)
1368                 ret = get_last_packet(session, htype, hsk, optional);
1369
1370         if (IS_DTLS(session)) {
1371                 if (ret >= 0)
1372                         return ret;
1373         } else {
1374                 if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1375                      && ret < 0) || ret >= 0)
1376                         return gnutls_assert_val(ret);
1377         }
1378
1379         if (htype != (gnutls_handshake_description_t) -1) {
1380                 ret = handshake_remaining_time(session);
1381                 if (ret < 0)
1382                         return gnutls_assert_val(ret);
1383                 tleft = ret;
1384         }
1385
1386         do {
1387                 /* if we don't have a complete message waiting for us, try 
1388                  * receiving more */
1389                 ret =
1390                     _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
1391                                             tleft);
1392                 if (ret < 0)
1393                         return gnutls_assert_val_fatal(ret);
1394
1395                 ret = _gnutls_parse_record_buffered_msgs(session);
1396                 if (ret == 0) {
1397                         ret = get_last_packet(session, htype, hsk, optional);
1398                 }
1399                 /* we put an upper limit (retries) to the number of partial handshake
1400                  * messages in a record packet. */
1401         } while(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN && retries-- > 0);
1402
1403         if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
1404                 ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
1405         }
1406
1407         return ret;
1408 }