Get rid of loopbreak as a mean for signalling successful packet handling.
[libradsec.git] / lib / packet.c
1 /* See the file COPYING for licensing information.  */
2
3 #if defined HAVE_CONFIG_H
4 #include <config.h>
5 #endif
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <sys/time.h>
11 #include <assert.h>
12 #include <freeradius/libradius.h>
13 #include <event2/event.h>
14 #include <event2/bufferevent.h>
15 #include <radsec/radsec.h>
16 #include <radsec/radsec-impl.h>
17 #include "tls.h"
18 #include "debug.h"
19 #if defined (RS_ENABLE_TLS)
20 #include <event2/bufferevent_ssl.h>
21 #include <openssl/err.h>
22 #endif
23 #if defined (DEBUG)
24 #include <netdb.h>
25 #include <sys/socket.h>
26 #include <event2/buffer.h>
27 #endif
28
29 static int
30 _do_send (struct rs_packet *pkt)
31 {
32   int err;
33   VALUE_PAIR *vp;
34
35   assert (pkt->rpkt);
36   assert (!pkt->original);
37
38   vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
39   if (!vp)
40     return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__,
41                                 "paircreate: %s", fr_strerror ());
42   pairadd (&pkt->rpkt->vps, vp);
43
44   if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret))
45     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
46                                 "rad_encode: %s", fr_strerror ());
47   if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret))
48     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
49                                 "rad_sign: %s", fr_strerror ());
50 #if defined (DEBUG)
51   {
52     char host[80], serv[80];
53
54     getnameinfo (pkt->conn->active_peer->addr->ai_addr,
55                  pkt->conn->active_peer->addr->ai_addrlen,
56                  host, sizeof(host), serv, sizeof(serv),
57                  0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
58     rs_debug (("%s: about to send this to %s:%s:\n", __func__, host, serv));
59     rs_dump_packet (pkt);
60   }
61 #endif
62
63   err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data,
64                            pkt->rpkt->data_len);
65   if (err < 0)
66     return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
67                                 "bufferevent_write: %s",
68                                 evutil_gai_strerror (err));
69   return RSE_OK;
70 }
71
72 static void
73 _on_connect (struct rs_connection *conn)
74 {
75   conn->is_connected = 1;
76   rs_debug (("%s: %p connected\n", __func__, conn->active_peer));
77   if (conn->callbacks.connected_cb)
78     conn->callbacks.connected_cb (conn->user_data);
79 }
80
81 static void
82 _on_disconnect (struct rs_connection *conn)
83 {
84   conn->is_connecting = 0;
85   conn->is_connected = 0;
86   rs_debug (("%s: %p disconnected\n", __func__, conn->active_peer));
87   if (conn->callbacks.disconnected_cb)
88     conn->callbacks.disconnected_cb (conn->user_data);
89 }
90
91 static void
92 _event_cb (struct bufferevent *bev, short events, void *ctx)
93 {
94   struct rs_packet *pkt = (struct rs_packet *)ctx;
95   struct rs_connection *conn = NULL;
96   struct rs_peer *p = NULL;
97   int sockerr = 0;
98 #if defined (RS_ENABLE_TLS)
99   unsigned long tlserr = 0;
100 #endif
101
102   assert (pkt);
103   assert (pkt->conn);
104   assert (pkt->conn->active_peer);
105   conn = pkt->conn;
106   p = conn->active_peer;
107
108   conn->is_connecting = 0;
109   if (events & BEV_EVENT_CONNECTED)
110     {
111       _on_connect (conn);
112       if (_do_send (pkt))
113         rs_debug (("%s: error sending\n", __func__));
114     }
115   else if (events & BEV_EVENT_EOF)
116     {
117       _on_disconnect (conn);
118     }
119   else if (events & BEV_EVENT_TIMEOUT)
120     {
121       rs_debug (("%s: %p times out on %s\n", __func__, p,
122                  (events & BEV_EVENT_READING) ? "read" : "write"));
123       rs_err_conn_push_fl (pkt->conn, RSE_IOTIMEOUT, __FILE__, __LINE__, NULL);
124     }
125   else if (events & BEV_EVENT_ERROR)
126     {
127       sockerr = evutil_socket_geterror (conn->active_peer->fd);
128       if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */
129         {
130           _on_disconnect (conn);
131         }
132       else
133         {
134           rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__,
135                                "%d: socket error %d (%s)",
136                                conn->fd,
137                                sockerr,
138                                evutil_socket_error_to_string (sockerr));
139           rs_debug (("%s: socket error on fd %d: %s (%d)\n", __func__,
140                      conn->fd,
141                      evutil_socket_error_to_string (sockerr),
142                      sockerr));
143         }
144 #if defined (RS_ENABLE_TLS)
145       if (conn->tls_ssl)        /* FIXME: correct check?  */
146         {
147           for (tlserr = bufferevent_get_openssl_error (conn->bev);
148                tlserr;
149                tlserr = bufferevent_get_openssl_error (conn->bev))
150             {
151               rs_debug (("%s: openssl error: %s\n", __func__,
152                          ERR_error_string (tlserr, NULL)));
153               rs_err_conn_push_fl (pkt->conn, RSE_SSLERR, __FILE__, __LINE__,
154                                    ERR_error_string (tlserr, NULL));
155             }
156         }
157 #endif  /* RS_ENABLE_TLS */
158     }
159
160 #if defined (DEBUG)
161   if (events & BEV_EVENT_ERROR && events != BEV_EVENT_ERROR)
162     rs_debug (("%s: BEV_EVENT_ERROR and more: 0x%x\n", __func__, events));
163 #endif
164 }
165
166 static void
167 _write_cb (struct bufferevent *bev, void *ctx)
168 {
169   struct rs_packet *pkt = (struct rs_packet *) ctx;
170
171   assert (pkt);
172   assert (pkt->conn);
173
174   if (pkt->conn->callbacks.sent_cb)
175     pkt->conn->callbacks.sent_cb (pkt->conn->user_data);
176 }
177
178 /* Read one RADIUS packet header.  Return !0 on error.  A return value
179    of 0 means that we need more data.  */
180 static int
181 _read_header (struct rs_packet *pkt)
182 {
183   size_t n = 0;
184
185   n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN);
186   if (n == RS_HEADER_LEN)
187     {
188       pkt->hdr_read_flag = 1;
189       pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3];
190       if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096)
191         {
192           bufferevent_free (pkt->conn->bev); /* Close connection.  */
193           return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT,
194                                    "invalid packet length: %d",
195                                    pkt->rpkt->data_len);
196         }
197       pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len);
198       if (!pkt->rpkt->data)
199         {
200           bufferevent_free (pkt->conn->bev); /* Close connection.  */
201           return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__,
202                                       NULL);
203         }
204       memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN);
205       bufferevent_setwatermark (pkt->conn->bev, EV_READ,
206                                 pkt->rpkt->data_len - RS_HEADER_LEN, 0);
207       rs_debug (("%s: packet header read, total pkt len=%d\n",
208                  __func__, pkt->rpkt->data_len));
209     }
210   else if (n < 0)
211     {
212       rs_debug (("%s: buffer frozen while reading header\n", __func__));
213     }
214   else      /* Error: libevent gave us less than the low watermark. */
215     {
216       bufferevent_free (pkt->conn->bev); /* Close connection.  */
217       return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__,
218                                   "got %d octets reading header", n);
219     }
220
221   return 0;
222 }
223
224 static int
225 _read_packet (struct rs_packet *pkt)
226 {
227   size_t n = 0;
228
229   rs_debug (("%s: trying to read %d octets of packet data\n", __func__,
230              pkt->rpkt->data_len - RS_HEADER_LEN));
231
232   n = bufferevent_read (pkt->conn->bev,
233                         pkt->rpkt->data + RS_HEADER_LEN,
234                         pkt->rpkt->data_len - RS_HEADER_LEN);
235
236   rs_debug (("%s: read %ld octets of packet data\n", __func__, n));
237
238   if (n == pkt->rpkt->data_len - RS_HEADER_LEN)
239     {
240       bufferevent_disable (pkt->conn->bev, EV_READ);
241       rs_debug (("%s: complete packet read\n", __func__));
242       pkt->hdr_read_flag = 0;
243       memset (pkt->hdr, 0, sizeof(*pkt->hdr));
244
245       /* Checks done by rad_packet_ok:
246          - lenghts (FIXME: checks really ok for tcp?)
247          - invalid code field
248          - attribute lengths >= 2
249          - attribute sizes adding up correctly  */
250       if (!rad_packet_ok (pkt->rpkt, 0) != 0)
251         {
252           bufferevent_free (pkt->conn->bev); /* Close connection.  */
253           return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
254                                       "invalid packet: %s", fr_strerror ());
255         }
256
257       /* TODO: Verify that reception of an unsolicited response packet
258          results in connection being closed.  */
259
260       /* If we have a request to match this response against, verify
261          and decode the response.  */
262       if (pkt->original)
263         {
264           /* Verify header and message authenticator.  */
265           if (rad_verify (pkt->rpkt, pkt->original->rpkt,
266                           pkt->conn->active_peer->secret))
267             {
268               bufferevent_free (pkt->conn->bev); /* Close connection.  */
269               return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
270                                           "rad_verify: %s", fr_strerror ());
271             }
272
273           /* Decode and decrypt.  */
274           if (rad_decode (pkt->rpkt, pkt->original->rpkt,
275                           pkt->conn->active_peer->secret))
276             {
277               bufferevent_free (pkt->conn->bev); /* Close connection.  */
278               return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
279                                           "rad_decode: %s", fr_strerror ());
280             }
281         }
282
283 #if defined (DEBUG)
284       /* Find out what happens if there's data left in the buffer.  */
285       {
286         size_t rest = 0;
287         rest = evbuffer_get_length (bufferevent_get_input (pkt->conn->bev));
288         if (rest)
289           rs_debug (("%s: returning with %d octets left in buffer\n", __func__,
290                      rest));
291       }
292 #endif
293
294       /* Hand over message to user, changes ownership of pkt.  Don't
295          touch it afterwards -- it might have been freed.  */
296       if (pkt->conn->callbacks.received_cb)
297         pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data);
298     }
299   else if (n < 0)               /* Buffer frozen.  */
300     rs_debug (("%s: buffer frozen when reading packet\n", __func__));
301   else                          /* Short packet.  */
302     rs_debug (("%s: waiting for another %d octets\n", __func__,
303                pkt->rpkt->data_len - RS_HEADER_LEN - n));
304
305   return 0;
306 }
307
308 /* Read callback for TCP.
309
310    Read exactly one RADIUS message from BEV and store it in struct
311    rs_packet passed in CTX (hereby called 'pkt').
312
313    Verify the received packet against pkt->original, if !NULL.
314
315    Inform upper layer about successful reception of valid RADIUS
316    message by invoking conn->callbacks.recevied_cb(), if !NULL.  */
317 static void
318 _read_cb (struct bufferevent *bev, void *ctx)
319 {
320   struct rs_packet *pkt = (struct rs_packet *) ctx;
321
322   assert (pkt);
323   assert (pkt->conn);
324   assert (pkt->rpkt);
325
326   pkt->rpkt->sockfd = pkt->conn->fd;
327   pkt->rpkt->vps = NULL;
328
329   if (!pkt->hdr_read_flag)
330     if (_read_header (pkt))
331       return;
332   _read_packet (pkt);
333 }
334
335 static void
336 _evlog_cb (int severity, const char *msg)
337 {
338   const char *sevstr;
339   switch (severity)
340     {
341     case _EVENT_LOG_DEBUG:
342 #if !defined (DEBUG_LEVENT)
343       return;
344 #endif
345       sevstr = "debug";
346       break;
347     case _EVENT_LOG_MSG:
348       sevstr = "msg";
349       break;
350     case _EVENT_LOG_WARN:
351       sevstr = "warn";
352       break;
353     case _EVENT_LOG_ERR:
354       sevstr = "err";
355       break;
356     default:
357       sevstr = "???";
358       break;
359     }
360   fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr?  */
361 }
362
363 static int
364 _init_evb (struct rs_connection *conn)
365 {
366   if (conn->evb)
367     return RSE_OK;
368
369 #if defined (DEBUG)
370   event_enable_debug_mode ();
371 #endif
372   event_set_log_callback (_evlog_cb);
373   conn->evb = event_base_new ();
374   if (!conn->evb)
375     return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
376                                 "event_base_new");
377
378   return RSE_OK;
379 }
380
381 static int
382 _init_socket (struct rs_connection *conn, struct rs_peer *p)
383 {
384   if (conn->fd != -1)
385     return RSE_OK;
386
387   assert (p->addr);
388   conn->fd = socket (p->addr->ai_family, p->addr->ai_socktype,
389                      p->addr->ai_protocol);
390   if (conn->fd < 0)
391     return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
392                                 strerror (errno));
393   if (evutil_make_socket_nonblocking (conn->fd) < 0)
394     {
395       evutil_closesocket (conn->fd);
396       conn->fd = -1;
397       return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
398                                   strerror (errno));
399     }
400   return RSE_OK;
401 }
402
403 static struct rs_peer *
404 _pick_peer (struct rs_connection *conn)
405 {
406   assert (conn);
407
408   if (conn->active_peer)
409     conn->active_peer = conn->active_peer->next; /* Next.  */
410   if (!conn->active_peer)
411     conn->active_peer = conn->peers; /* From the top.  */
412
413   return conn->active_peer;
414 }
415
416 static int
417 _init_bev (struct rs_connection *conn, struct rs_peer *peer)
418 {
419   if (conn->bev)
420     return RSE_OK;
421
422   switch (conn->realm->type)
423     {
424     case RS_CONN_TYPE_UDP:
425       /* Fall through.  */
426       /* NOTE: We know this is wrong for several reasons, most notably
427          because libevent doesn't work as expected with UDP.  The
428          timeout handling is wrong too.  */
429     case RS_CONN_TYPE_TCP:
430       conn->bev = bufferevent_socket_new (conn->evb, conn->fd, 0);
431       if (!conn->bev)
432         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
433                                     "bufferevent_socket_new");
434       break;
435
436 #if defined (RS_ENABLE_TLS)
437     case RS_CONN_TYPE_TLS:
438       if (rs_tls_init (conn))
439         return -1;
440       /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things
441          seem to break when be_openssl_ctrl() (in libevent) calls
442          SSL_set_bio() after BIO_new_socket() with flag=1.  */
443       conn->bev =
444         bufferevent_openssl_socket_new (conn->evb, conn->fd, conn->tls_ssl,
445                                         BUFFEREVENT_SSL_CONNECTING, 0);
446       if (!conn->bev)
447         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
448                                     "bufferevent_openssl_socket_new");
449       break;
450
451     case RS_CONN_TYPE_DTLS:
452       return rs_err_conn_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
453                                   "%s: NYI", __func__);
454 #endif  /* RS_ENABLE_TLS */
455
456     default:
457       return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__,
458                                   "%s: unknown connection type: %d", __func__,
459                                   conn->realm->type);
460     }
461
462   return RSE_OK;
463 }
464
465 static void
466 _do_connect (struct rs_connection *conn)
467 {
468   struct rs_peer *p;
469   int err;
470
471   assert (conn);
472   assert (conn->active_peer);
473   p = conn->active_peer;
474
475 #if defined (DEBUG)
476   {
477     char host[80], serv[80];
478
479     getnameinfo (p->addr->ai_addr,
480                  p->addr->ai_addrlen,
481                  host, sizeof(host), serv, sizeof(serv),
482                  0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
483     rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv));
484   }
485 #endif
486
487   err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
488                                     p->addr->ai_addrlen);
489   if (err < 0)
490     rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
491                          "bufferevent_socket_connect: %s",
492                          evutil_gai_strerror (err));
493   else
494     p->conn->is_connecting = 1;
495 }
496
497 static int
498 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
499 {
500   if (_init_evb (conn))
501     return -1;
502
503   if (!conn->active_peer)
504     _pick_peer (conn);
505   if (!conn->active_peer)
506     return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
507
508   if (_init_socket (conn, conn->active_peer))
509     return -1;
510
511   if (_init_bev (conn, conn->active_peer))
512     return -1;
513
514   if (!conn->is_connected)
515     if (!conn->is_connecting)
516       _do_connect (conn);
517
518   return RSE_OK;
519 }
520
521 static int
522 _conn_is_open_p (struct rs_connection *conn)
523 {
524   return conn->active_peer && conn->is_connected;
525 }
526
527 /* Public functions.  */
528 int
529 rs_packet_create (struct rs_connection *conn, struct rs_packet **pkt_out)
530 {
531   struct rs_packet *p;
532   RADIUS_PACKET *rpkt;
533
534   *pkt_out = NULL;
535
536   rpkt = rad_alloc (1);
537   if (!rpkt)
538     return rs_err_conn_push (conn, RSE_NOMEM, __func__);
539   rpkt->id = conn->nextid++;
540
541   p = (struct rs_packet *) malloc (sizeof (struct rs_packet));
542   if (!p)
543     {
544       rad_free (&rpkt);
545       return rs_err_conn_push (conn, RSE_NOMEM, __func__);
546     }
547   memset (p, 0, sizeof (struct rs_packet));
548   p->conn = conn;
549   p->rpkt = rpkt;
550
551   *pkt_out = p;
552   return RSE_OK;
553 }
554
555 int
556 rs_packet_create_auth_request (struct rs_connection *conn,
557                                struct rs_packet **pkt_out,
558                                const char *user_name, const char *user_pw)
559 {
560   struct rs_packet *pkt;
561   struct rs_attr *attr;
562
563   if (rs_packet_create (conn, pkt_out))
564     return -1;
565   pkt = *pkt_out;
566   pkt->rpkt->code = PW_AUTHENTICATION_REQUEST;
567
568   if (user_name)
569     {
570       if (rs_attr_create (conn, &attr, "User-Name", user_name))
571         return -1;
572       rs_packet_add_attr (pkt, attr);
573
574       if (user_pw)
575         {
576           if (rs_attr_create (conn, &attr, "User-Password", user_pw))
577             return -1;
578           rs_packet_add_attr (pkt, attr);
579         }
580     }
581
582   return RSE_OK;
583 }
584
585 /* User callback used when we're dispatching for user.  */
586 static void
587 _wcb (void *user_data)
588 {
589   struct rs_packet *pkt = (struct rs_packet *) user_data;
590   assert (pkt);
591   pkt->written_flag = 1;
592   bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ);
593 }
594
595 int
596 rs_packet_send (struct rs_packet *pkt, void *user_data)
597 {
598   struct rs_connection *conn = NULL;
599   int err = 0;
600
601   assert (pkt);
602   assert (pkt->conn);
603   conn = pkt->conn;
604
605   if (_conn_is_open_p (conn))
606     _do_send (pkt);
607   else
608     if (_conn_open (conn, pkt))
609       return -1;
610
611   assert (conn->evb);
612   assert (conn->bev);
613   assert (conn->active_peer);
614   assert (conn->fd >= 0);
615
616   conn->user_data = user_data;
617   bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt);
618   bufferevent_enable (conn->bev, EV_WRITE);
619
620   /* Do dispatch, unless the user wants to do it herself.  */
621   if (!conn->user_dispatch_flag)
622     {
623       conn->callbacks.sent_cb = _wcb;
624       conn->user_data = pkt;
625       rs_debug (("%s: entering event loop\n", __func__));
626       err = event_base_dispatch (conn->evb);
627       if (err < 0)
628         return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
629                                     "event_base_dispatch: %s",
630                                     evutil_gai_strerror (err));
631       rs_debug (("%s: event loop done\n", __func__));
632       conn->callbacks.sent_cb = NULL;
633       conn->user_data = NULL;
634
635       if (!pkt->written_flag)
636         return -1;
637     }
638
639   return RSE_OK;
640 }
641
642 static void
643 _rcb (struct rs_packet *packet, void *user_data)
644 {
645   struct rs_packet *pkt = (struct rs_packet *) user_data;
646   assert (pkt);
647   pkt->valid_flag = 1;
648   bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ);
649 }
650
651 /* Special function used in libradsec blocking dispatching mode,
652    i.e. with socket set to block on read/write and with no libradsec
653    callbacks registered.
654
655    For any other use of libradsec, a the received_cb callback should
656    be registered in the callbacks member of struct rs_connection.
657
658    On successful reception, verification and decoding of a RADIUS
659    message, PKT_OUT will upon return point at a pointer to a struct
660    rs_packet containing the message.
661
662    If anything goes wrong or if the read times out (TODO: explain),
663    PKT_OUT will point at the NULL pointer and one or more errors are
664    pushed on the connection (available through rs_err_conn_pop()).  */
665
666 int
667 rs_conn_receive_packet (struct rs_connection *conn,
668                         struct rs_packet *request,
669                         struct rs_packet **pkt_out)
670 {
671   int err = 0;
672   struct rs_packet *pkt = NULL;
673
674   assert (conn);
675   assert (conn->realm);
676   assert (!conn->user_dispatch_flag); /* Dispatching mode only.  */
677
678   if (rs_packet_create (conn, pkt_out))
679     return -1;
680   pkt = *pkt_out;
681   pkt->conn = conn;
682   pkt->original = request;
683
684   assert (conn->evb);
685   assert (conn->bev);
686   assert (conn->active_peer);
687   assert (conn->fd >= 0);
688
689   bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0);
690   bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt);
691   bufferevent_enable (conn->bev, EV_READ);
692   conn->callbacks.received_cb = _rcb;
693   conn->user_data = pkt;
694
695   /* Dispatch.  */
696   rs_debug (("%s: entering event loop\n", __func__));
697   err = event_base_dispatch (conn->evb);
698   conn->callbacks.received_cb = NULL;
699   if (err < 0)
700     return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
701                                 "event_base_dispatch: %s",
702                                 evutil_gai_strerror (err));
703   rs_debug (("%s: event loop done\n", __func__));
704
705   if (!pkt->valid_flag)
706     return -1;
707
708 #if defined (DEBUG)
709       rs_dump_packet (pkt);
710 #endif
711
712   pkt->original = NULL;         /* FIXME: Why?  */
713   return RSE_OK;
714 }
715
716 void
717 rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
718 {
719   pairadd (&pkt->rpkt->vps, attr->vp);
720   attr->pkt = pkt;
721 }
722
723 struct radius_packet *
724 rs_packet_frpkt(struct rs_packet *pkt)
725 {
726   assert (pkt);
727   return pkt->rpkt;
728 }
729
730 void
731 rs_packet_destroy(struct rs_packet *pkt)
732 {
733   if (pkt)
734     {
735       // FIXME: memory leak! TODO: free all attributes
736       rad_free (&pkt->rpkt);
737       rs_free (pkt->conn->ctx, pkt);
738     }
739 }