Remove redundant file from freeradius-abfab list.
[freeradius.git] / src / lib / packet.c
1 /*
2  * packet.c     Generic packet manipulation functions.
3  *
4  * Version:     $Id$
5  *
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; either
9  *   version 2.1 of the License, or (at your option) any later version.
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 St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2006  The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include        <freeradius-devel/libradius.h>
26
27 #ifdef WITH_UDPFROMTO
28 #include        <freeradius-devel/udpfromto.h>
29 #endif
30
31 #include <fcntl.h>
32
33 /*
34  *      See if two packets are identical.
35  *
36  *      Note that we do NOT compare the authentication vectors.
37  *      That's because if the authentication vector is different,
38  *      it means that the NAS has given up on the earlier request.
39  */
40 int fr_packet_cmp(RADIUS_PACKET const *a, RADIUS_PACKET const *b)
41 {
42         int rcode;
43
44         /*
45          *      256-way fanout.
46          */
47         if (a->id < b->id) return -1;
48         if (a->id > b->id) return +1;
49
50         if (a->sockfd < b->sockfd) return -1;
51         if (a->sockfd > b->sockfd) return +1;
52
53         /*
54          *      Source ports are pretty much random.
55          */
56         rcode = (int) a->src_port - (int) b->src_port;
57         if (rcode != 0) return rcode;
58
59         /*
60          *      Usually many client IPs, and few server IPs
61          */
62         rcode = fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
63         if (rcode != 0) return rcode;
64
65         /*
66          *      One socket can receive packets for multiple
67          *      destination IPs, so we check that before checking the
68          *      file descriptor.
69          */
70         rcode = fr_ipaddr_cmp(&a->dst_ipaddr, &b->dst_ipaddr);
71         if (rcode != 0) return rcode;
72
73         /*
74          *      At this point, the order of comparing socket FDs
75          *      and/or destination ports doesn't matter.  One of those
76          *      fields will make the socket unique, and the other is
77          *      pretty much redundant.
78          */
79         rcode = (int) a->dst_port - (int) b->dst_port;
80         return rcode;
81 }
82
83 int fr_inaddr_any(fr_ipaddr_t *ipaddr)
84 {
85
86         if (ipaddr->af == AF_INET) {
87                 if (ipaddr->ipaddr.ip4addr.s_addr == INADDR_ANY) {
88                         return 1;
89                 }
90
91 #ifdef HAVE_STRUCT_SOCKADDR_IN6
92         } else if (ipaddr->af == AF_INET6) {
93                 if (IN6_IS_ADDR_UNSPECIFIED(&(ipaddr->ipaddr.ip6addr))) {
94                         return 1;
95                 }
96 #endif
97
98         } else {
99                 fr_strerror_printf("Unknown address family");
100                 return -1;
101         }
102
103         return 0;
104 }
105
106
107 /*
108  *      Create a fake "request" from a reply, for later lookup.
109  */
110 void fr_request_from_reply(RADIUS_PACKET *request,
111                            RADIUS_PACKET const *reply)
112 {
113         request->sockfd = reply->sockfd;
114         request->id = reply->id;
115 #ifdef WITH_TCP
116         request->proto = reply->proto;
117 #endif
118         request->src_port = reply->dst_port;
119         request->dst_port = reply->src_port;
120         request->src_ipaddr = reply->dst_ipaddr;
121         request->dst_ipaddr = reply->src_ipaddr;
122 }
123
124 /*
125  *      Open a socket on the given IP and port.
126  */
127 int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
128 {
129         int sockfd;
130         struct sockaddr_storage salocal;
131         socklen_t       salen;
132
133         sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
134         if (sockfd < 0) {
135                 fr_strerror_printf("cannot open socket: %s", fr_syserror(errno));
136                 return sockfd;
137         }
138
139 #ifdef WITH_UDPFROMTO
140         /*
141          *      Initialize udpfromto for all sockets.
142          */
143         if (udpfromto_init(sockfd) != 0) {
144                 close(sockfd);
145                 fr_strerror_printf("cannot initialize udpfromto: %s", fr_syserror(errno));
146                 return -1;
147         }
148 #endif
149
150         if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
151                 return sockfd;
152         }
153
154 #ifdef HAVE_STRUCT_SOCKADDR_IN6
155         if (ipaddr->af == AF_INET6) {
156                 /*
157                  *      Listening on '::' does NOT get you IPv4 to
158                  *      IPv6 mapping.  You've got to listen on an IPv4
159                  *      address, too.  This makes the rest of the server
160                  *      design a little simpler.
161                  */
162 #ifdef IPV6_V6ONLY
163
164                 if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
165                         int on = 1;
166
167                         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
168                                        (char *)&on, sizeof(on)) < 0) {
169                                 close(sockfd);
170                                 fr_strerror_printf("Failed setting sockopt "
171                                                    "IPPROTO_IPV6 - IPV6_V6ONLY"
172                                                    ": %s", fr_syserror(errno));
173                                 return -1;
174                         }
175                 }
176 #endif /* IPV6_V6ONLY */
177         }
178 #endif /* HAVE_STRUCT_SOCKADDR_IN6 */
179
180 #if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
181         if (ipaddr->af == AF_INET) {
182                 int flag;
183
184 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
185
186                 /*
187                  *      Disable PMTU discovery.  On Linux, this
188                  *      also makes sure that the "don't fragment"
189                  *      flag is zero.
190                  */
191                 flag = IP_PMTUDISC_DONT;
192                 if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER,
193                                &flag, sizeof(flag)) < 0) {
194                         close(sockfd);
195                         fr_strerror_printf("Failed setting sockopt "
196                                            "IPPROTO_IP - IP_MTU_DISCOVER: %s",
197                                            fr_syserror(errno));
198                         return -1;
199                 }
200 #endif
201
202 #if defined(IP_DONTFRAG)
203                 /*
204                  *      Ensure that the "don't fragment" flag is zero.
205                  */
206                 flag = 0;
207                 if (setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG,
208                            &flag, sizeof(flag)) < 0) {
209                         close(sockfd);
210                         fr_strerror_printf("Failed setting sockopt "
211                                            "IPPROTO_IP - IP_DONTFRAG: %s",
212                                            fr_syserror(errno));
213                         return -1;
214                 }
215 #endif
216         }
217 #endif
218
219         if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
220                 close(sockfd);
221                 fr_strerror_printf("cannot bind socket: %s", fr_syserror(errno));
222                 return -1;
223         }
224
225         return sockfd;
226 }
227
228
229 /*
230  *      We need to keep track of the socket & it's IP/port.
231  */
232 typedef struct fr_packet_socket_t {
233         int             sockfd;
234         void            *ctx;
235
236         uint32_t        num_outgoing;
237
238         int             src_any;
239         fr_ipaddr_t     src_ipaddr;
240         uint16_t        src_port;
241
242         int             dst_any;
243         fr_ipaddr_t     dst_ipaddr;
244         uint16_t        dst_port;
245
246         bool            dont_use;
247
248 #ifdef WITH_TCP
249         int             proto;
250 #endif
251
252         uint8_t         id[32];
253 } fr_packet_socket_t;
254
255
256 #define FNV_MAGIC_PRIME (0x01000193)
257 #define MAX_SOCKETS (256)
258 #define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
259 #define SOCK2OFFSET(sockfd) ((sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
260
261 /*
262  *      Structure defining a list of packets (incoming or outgoing)
263  *      that should be managed.
264  */
265 struct fr_packet_list_t {
266         rbtree_t        *tree;
267
268         int             alloc_id;
269         uint32_t        num_outgoing;
270         int             last_recv;
271         int             num_sockets;
272
273         fr_packet_socket_t sockets[MAX_SOCKETS];
274 };
275
276
277 /*
278  *      Ugh.  Doing this on every sent/received packet is not nice.
279  */
280 static fr_packet_socket_t *fr_socket_find(fr_packet_list_t *pl,
281                                           int sockfd)
282 {
283         int i, start;
284
285         i = start = SOCK2OFFSET(sockfd);
286
287         do {                    /* make this hack slightly more efficient */
288                 if (pl->sockets[i].sockfd == sockfd) return &pl->sockets[i];
289
290                 i = (i + 1) & SOCKOFFSET_MASK;
291         } while (i != start);
292
293         return NULL;
294 }
295
296 bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
297 {
298         fr_packet_socket_t *ps;
299
300         if (!pl) {
301                 fr_strerror_printf("Invalid argument");
302                 return false;
303         }
304
305         ps = fr_socket_find(pl, sockfd);
306         if (!ps) {
307                 fr_strerror_printf("No such socket");
308                 return false;
309         }
310
311         ps->dont_use = true;
312         return true;
313 }
314
315 bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd)
316 {
317         fr_packet_socket_t *ps;
318
319         if (!pl) return false;
320
321         ps = fr_socket_find(pl, sockfd);
322         if (!ps) return false;
323
324         ps->dont_use = false;
325         return true;
326 }
327
328
329 bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd)
330 {
331         fr_packet_socket_t *ps;
332
333         if (!pl) return false;
334
335         ps = fr_socket_find(pl, sockfd);
336         if (!ps) return false;
337
338         if (ps->num_outgoing != 0) {
339                 fr_strerror_printf("socket is still in use");
340                 return false;
341         }
342
343         ps->sockfd = -1;
344         pl->num_sockets--;
345
346         return true;
347 }
348
349
350 bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
351                               fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
352                               void *ctx)
353 {
354         int i, start;
355         struct sockaddr_storage src;
356         socklen_t               sizeof_src;
357         fr_packet_socket_t      *ps;
358
359         if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
360                 fr_strerror_printf("Invalid argument");
361                 return false;
362         }
363
364         if (pl->num_sockets >= MAX_SOCKETS) {
365                 fr_strerror_printf("Too many open sockets");
366                 return false;
367         }
368
369 #ifndef WITH_TCP
370         if (proto != IPPROTO_UDP) {
371                 fr_strerror_printf("only UDP is supported");
372                 return false;
373         }
374 #endif
375
376         ps = NULL;
377         i = start = SOCK2OFFSET(sockfd);
378
379         do {
380                 if (pl->sockets[i].sockfd == -1) {
381                         ps =  &pl->sockets[i];
382                         break;
383                 }
384
385                 i = (i + 1) & SOCKOFFSET_MASK;
386         } while (i != start);
387
388         if (!ps) {
389                 fr_strerror_printf("All socket entries are full");
390                 return false;
391         }
392
393         memset(ps, 0, sizeof(*ps));
394         ps->ctx = ctx;
395 #ifdef WITH_TCP
396         ps->proto = proto;
397 #endif
398
399         /*
400          *      Get address family, etc. first, so we know if we
401          *      need to do udpfromto.
402          *
403          *      FIXME: udpfromto also does this, but it's not
404          *      a critical problem.
405          */
406         sizeof_src = sizeof(src);
407         memset(&src, 0, sizeof_src);
408         if (getsockname(sockfd, (struct sockaddr *) &src,
409                         &sizeof_src) < 0) {
410                 fr_strerror_printf("%s", fr_syserror(errno));
411                 return false;
412         }
413
414         if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->src_ipaddr,
415                                 &ps->src_port)) {
416                 fr_strerror_printf("Failed to get IP");
417                 return false;
418         }
419
420         ps->dst_ipaddr = *dst_ipaddr;
421         ps->dst_port = dst_port;
422
423         ps->src_any = fr_inaddr_any(&ps->src_ipaddr);
424         if (ps->src_any < 0) return false;
425
426         ps->dst_any = fr_inaddr_any(&ps->dst_ipaddr);
427         if (ps->dst_any < 0) return false;
428
429         /*
430          *      As the last step before returning.
431          */
432         ps->sockfd = sockfd;
433         pl->num_sockets++;
434
435         return true;
436 }
437
438 static int packet_entry_cmp(void const *one, void const *two)
439 {
440         RADIUS_PACKET const * const *a = one;
441         RADIUS_PACKET const * const *b = two;
442
443         return fr_packet_cmp(*a, *b);
444 }
445
446 void fr_packet_list_free(fr_packet_list_t *pl)
447 {
448         if (!pl) return;
449
450         rbtree_free(pl->tree);
451         free(pl);
452 }
453
454
455 /*
456  *      Caller is responsible for managing the packet entries.
457  */
458 fr_packet_list_t *fr_packet_list_create(int alloc_id)
459 {
460         int i;
461         fr_packet_list_t        *pl;
462
463         pl = malloc(sizeof(*pl));
464         if (!pl) return NULL;
465         memset(pl, 0, sizeof(*pl));
466
467         pl->tree = rbtree_create(NULL, packet_entry_cmp, NULL, 0);
468         if (!pl->tree) {
469                 fr_packet_list_free(pl);
470                 return NULL;
471         }
472
473         for (i = 0; i < MAX_SOCKETS; i++) {
474                 pl->sockets[i].sockfd = -1;
475         }
476
477         pl->alloc_id = alloc_id;
478
479         return pl;
480 }
481
482
483 /*
484  *      If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
485  *      be called before inserting the packet into the list!
486  */
487 bool fr_packet_list_insert(fr_packet_list_t *pl,
488                             RADIUS_PACKET **request_p)
489 {
490         if (!pl || !request_p || !*request_p) return 0;
491
492         VERIFY_PACKET(*request_p);
493
494         return rbtree_insert(pl->tree, request_p);
495 }
496
497 RADIUS_PACKET **fr_packet_list_find(fr_packet_list_t *pl,
498                                       RADIUS_PACKET *request)
499 {
500         if (!pl || !request) return 0;
501
502         VERIFY_PACKET(request);
503
504         return rbtree_finddata(pl->tree, &request);
505 }
506
507
508 /*
509  *      This presumes that the reply has dst_ipaddr && dst_port set up
510  *      correctly (i.e. real IP, or "*").
511  */
512 RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
513                                               RADIUS_PACKET *reply)
514 {
515         RADIUS_PACKET my_request, *request;
516         fr_packet_socket_t *ps;
517
518         if (!pl || !reply) return NULL;
519
520         VERIFY_PACKET(reply);
521
522         ps = fr_socket_find(pl, reply->sockfd);
523         if (!ps) return NULL;
524
525         /*
526          *      Initialize request from reply, AND from the source
527          *      IP & port of this socket.  The client may have bound
528          *      the socket to 0, in which case it's some random port,
529          *      that is NOT in the original request->src_port.
530          */
531         my_request.sockfd = reply->sockfd;
532         my_request.id = reply->id;
533
534 #ifdef WITH_TCP
535         /*
536          *      TCP sockets are always bound to the correct src/dst IP/port
537          */
538         if (ps->proto == IPPROTO_TCP) {
539                 my_request.src_ipaddr = reply->dst_ipaddr;
540                 my_request.src_port = reply->dst_port;
541         } else
542 #endif
543         {
544                 if (ps->src_any) {
545                         my_request.src_ipaddr = ps->src_ipaddr;
546                 } else {
547                         my_request.src_ipaddr = reply->dst_ipaddr;
548                 }
549                 my_request.src_port = ps->src_port;
550         }
551
552         my_request.dst_ipaddr = reply->src_ipaddr;
553         my_request.dst_port = reply->src_port;
554
555 #ifdef WITH_TCP
556         my_request.proto = reply->proto;
557 #endif
558         request = &my_request;
559
560         return rbtree_finddata(pl->tree, &request);
561 }
562
563
564 bool fr_packet_list_yank(fr_packet_list_t *pl, RADIUS_PACKET *request)
565 {
566         rbnode_t *node;
567
568         if (!pl || !request) return false;
569
570         VERIFY_PACKET(request);
571
572         node = rbtree_find(pl->tree, &request);
573         if (!node) return false;
574
575         rbtree_delete(pl->tree, node);
576         return true;
577 }
578
579 uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
580 {
581         if (!pl) return 0;
582
583         return rbtree_num_elements(pl->tree);
584 }
585
586
587 /*
588  *      1 == ID was allocated & assigned
589  *      0 == couldn't allocate ID.
590  *
591  *      Note that this ALSO assigns a socket to use, and updates
592  *      packet->request->src_ipaddr && packet->request->src_port
593  *
594  *      In multi-threaded systems, the calls to id_alloc && id_free
595  *      should be protected by a mutex.  This does NOT have to be
596  *      the same mutex as the one protecting the insert/find/yank
597  *      calls!
598  *
599  *      We assume that the packet has dst_ipaddr && dst_port
600  *      already initialized.  We will use those to find an
601  *      outgoing socket.  The request MAY also have src_ipaddr set.
602  *
603  *      We also assume that the sender doesn't care which protocol
604  *      should be used.
605  */
606 bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
607                             RADIUS_PACKET **request_p, void **pctx)
608 {
609         int i, j, k, fd, id, start_i, start_j, start_k;
610         int src_any = 0;
611         fr_packet_socket_t *ps= NULL;
612         RADIUS_PACKET *request = *request_p;
613
614         VERIFY_PACKET(request);
615
616         if ((request->dst_ipaddr.af == AF_UNSPEC) ||
617             (request->dst_port == 0)) {
618                 fr_strerror_printf("No destination address/port specified");
619                 return false;
620         }
621
622 #ifndef WITH_TCP
623         if ((proto != 0) && (proto != IPPROTO_UDP)) {
624                 fr_strerror_printf("Invalid destination protocol");
625                 return false;
626         }
627 #endif
628
629         /*
630          *      Special case: unspec == "don't care"
631          */
632         if (request->src_ipaddr.af == AF_UNSPEC) {
633                 memset(&request->src_ipaddr, 0, sizeof(request->src_ipaddr));
634                 request->src_ipaddr.af = request->dst_ipaddr.af;
635         }
636
637         src_any = fr_inaddr_any(&request->src_ipaddr);
638         if (src_any < 0) {
639                 fr_strerror_printf("Can't check src_ipaddr");
640                 return false;
641         }
642
643         /*
644          *      MUST specify a destination address.
645          */
646         if (fr_inaddr_any(&request->dst_ipaddr) != 0) {
647                 fr_strerror_printf("Must specify a dst_ipaddr");
648                 return false;
649         }
650
651         /*
652          *      FIXME: Go to an LRU system.  This prevents ID re-use
653          *      for as long as possible.  The main problem with that
654          *      approach is that it requires us to populate the
655          *      LRU/FIFO when we add a new socket, or a new destination,
656          *      which can be expensive.
657          *
658          *      The LRU can be avoided if the caller takes care to free
659          *      Id's only when all responses have been received, OR after
660          *      a timeout.
661          *
662          *      Right now, the random approach is almost OK... it's
663          *      brute-force over all of the available ID's, BUT using
664          *      random numbers for everything spreads the load a bit.
665          *
666          *      The old method had a hash lookup on allocation AND
667          *      on free.  The new method has brute-force on allocation,
668          *      and near-zero cost on free.
669          */
670
671         id = fd = -1;
672         start_i = fr_rand() & SOCKOFFSET_MASK;
673
674 #define ID_i ((i + start_i) & SOCKOFFSET_MASK)
675         for (i = 0; i < MAX_SOCKETS; i++) {
676                 if (pl->sockets[ID_i].sockfd == -1) continue; /* paranoia */
677
678                 ps = &(pl->sockets[ID_i]);
679
680                 /*
681                  *      This socket is marked as "don't use for new
682                  *      packets".  But we can still receive packets
683                  *      that are outstanding.
684                  */
685                 if (ps->dont_use) continue;
686
687                 /*
688                  *      All IDs are allocated: ignore it.
689                  */
690                 if (ps->num_outgoing == 256) continue;
691
692 #ifdef WITH_TCP
693                 if (ps->proto != proto) continue;
694 #endif
695
696                 /*
697                  *      Address families don't match, skip it.
698                  */
699                 if (ps->src_ipaddr.af != request->dst_ipaddr.af) continue;
700
701                 /*
702                  *      MUST match dst port, if we have one.
703                  */
704                 if ((ps->dst_port != 0) &&
705                     (ps->dst_port != request->dst_port)) continue;
706
707                 /*
708                  *      MUST match requested src port, if one has been given.
709                  */
710                 if ((request->src_port != 0) &&
711                     (ps->src_port != request->src_port)) continue;
712
713                 /*
714                  *      We don't care about the source IP, but this
715                  *      socket is link local, and the requested
716                  *      destination is not link local.  Ignore it.
717                  */
718                 if (src_any && (ps->src_ipaddr.af == AF_INET) &&
719                     (((ps->src_ipaddr.ipaddr.ip4addr.s_addr >> 24) & 0xff) == 127) &&
720                     (((request->dst_ipaddr.ipaddr.ip4addr.s_addr >> 24) & 0xff) != 127)) continue;
721
722                 /*
723                  *      We're sourcing from *, and they asked for a
724                  *      specific source address: ignore it.
725                  */
726                 if (ps->src_any && !src_any) continue;
727
728                 /*
729                  *      We're sourcing from a specific IP, and they
730                  *      asked for a source IP that isn't us: ignore
731                  *      it.
732                  */
733                 if (!ps->src_any && !src_any &&
734                     (fr_ipaddr_cmp(&request->src_ipaddr,
735                                    &ps->src_ipaddr) != 0)) continue;
736
737                 /*
738                  *      UDP sockets are allowed to match
739                  *      destination IPs exactly, OR a socket
740                  *      with destination * is allowed to match
741                  *      any requested destination.
742                  *
743                  *      TCP sockets must match the destination
744                  *      exactly.  They *always* have dst_any=0,
745                  *      so the first check always matches.
746                  */
747                 if (!ps->dst_any &&
748                     (fr_ipaddr_cmp(&request->dst_ipaddr,
749                                    &ps->dst_ipaddr) != 0)) continue;
750
751                 /*
752                  *      Otherwise, this socket is OK to use.
753                  */
754
755                 /*
756                  *      Look for a free Id, starting from a random number.
757                  */
758                 start_j = fr_rand() & 0x1f;
759 #define ID_j ((j + start_j) & 0x1f)
760                 for (j = 0; j < 32; j++) {
761                         if (ps->id[ID_j] == 0xff) continue;
762
763
764                         start_k = fr_rand() & 0x07;
765 #define ID_k ((k + start_k) & 0x07)
766                         for (k = 0; k < 8; k++) {
767                                 if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
768
769                                 ps->id[ID_j] |= (1 << ID_k);
770                                 id = (ID_j * 8) + ID_k;
771                                 fd = i;
772                                 break;
773                         }
774                         if (fd >= 0) break;
775                 }
776 #undef ID_i
777 #undef ID_j
778 #undef ID_k
779                 if (fd >= 0) break;
780                 break;
781         }
782
783         /*
784          *      Ask the caller to allocate a new ID.
785          */
786         if (fd < 0) {
787                 fr_strerror_printf("Failed finding socket, caller must allocate a new one");
788                 return false;
789         }
790
791         /*
792          *      Set the ID, source IP, and source port.
793          */
794         request->id = id;
795
796         request->sockfd = ps->sockfd;
797         request->src_ipaddr = ps->src_ipaddr;
798         request->src_port = ps->src_port;
799
800         /*
801          *      If we managed to insert it, we're done.
802          */
803         if (fr_packet_list_insert(pl, request_p)) {
804                 if (pctx) *pctx = ps->ctx;
805                 ps->num_outgoing++;
806                 pl->num_outgoing++;
807                 return true;
808         }
809
810         /*
811          *      Mark the ID as free.  This is the one line from
812          *      id_free() that we care about here.
813          */
814         ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
815
816         request->id = -1;
817         request->sockfd = -1;
818         request->src_ipaddr.af = AF_UNSPEC;
819         request->src_port = 0;
820
821         return false;
822 }
823
824 /*
825  *      Should be called AFTER yanking it from the list, so that
826  *      any newly inserted entries don't collide with this one.
827  */
828 bool fr_packet_list_id_free(fr_packet_list_t *pl,
829                             RADIUS_PACKET *request, bool yank)
830 {
831         fr_packet_socket_t *ps;
832
833         if (!pl || !request) return false;
834
835         VERIFY_PACKET(request);
836
837         if (yank && !fr_packet_list_yank(pl, request)) return false;
838
839         ps = fr_socket_find(pl, request->sockfd);
840         if (!ps) return false;
841
842 #if 0
843         if (!ps->id[(request->id >> 3) & 0x1f] & (1 << (request->id & 0x07))) {
844                 fr_exit(1);
845         }
846 #endif
847
848         ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
849
850         ps->num_outgoing--;
851         pl->num_outgoing--;
852
853         request->id = -1;
854         request->src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
855         request->src_port = 0;
856
857         return true;
858 }
859
860 /*
861  *      We always walk RBTREE_DELETE_ORDER, which is like RBTREE_IN_ORDER, except that
862  *      <0 means error, stop
863  *      0  means OK, continue
864  *      1  means delete current node and stop
865  *      2  means delete current node and continue
866  */
867 int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx, rb_walker_t callback)
868 {
869         if (!pl || !callback) return 0;
870
871         return rbtree_walk(pl->tree, RBTREE_DELETE_ORDER, callback, ctx);
872 }
873
874 int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
875 {
876         int i, maxfd;
877
878         if (!pl || !set) return 0;
879
880         maxfd = -1;
881
882         for (i = 0; i < MAX_SOCKETS; i++) {
883                 if (pl->sockets[i].sockfd == -1) continue;
884                 FD_SET(pl->sockets[i].sockfd, set);
885                 if (pl->sockets[i].sockfd > maxfd) {
886                         maxfd = pl->sockets[i].sockfd;
887                 }
888         }
889
890         if (maxfd < 0) return -1;
891
892         return maxfd + 1;
893 }
894
895 /*
896  *      Round-robins the receivers, without priority.
897  *
898  *      FIXME: Add sockfd, if -1, do round-robin, else do sockfd
899  *              IF in fdset.
900  */
901 RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
902 {
903         int start;
904         RADIUS_PACKET *packet;
905
906         if (!pl || !set) return NULL;
907
908         start = pl->last_recv;
909         do {
910                 start++;
911                 start &= SOCKOFFSET_MASK;
912
913                 if (pl->sockets[start].sockfd == -1) continue;
914
915                 if (!FD_ISSET(pl->sockets[start].sockfd, set)) continue;
916
917 #ifdef WITH_TCP
918                 if (pl->sockets[start].proto == IPPROTO_TCP) {
919                         packet = fr_tcp_recv(pl->sockets[start].sockfd, 0);
920                 } else
921 #endif
922                 packet = rad_recv(NULL, pl->sockets[start].sockfd, 0);
923                 if (!packet) continue;
924
925                 /*
926                  *      Call fr_packet_list_find_byreply().  If it
927                  *      doesn't find anything, discard the reply.
928                  */
929
930                 pl->last_recv = start;
931 #ifdef WITH_TCP
932                 packet->proto = pl->sockets[start].proto;
933 #endif
934                 return packet;
935         } while (start != pl->last_recv);
936
937         return NULL;
938 }
939
940 uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
941 {
942         uint32_t num_elements;
943
944         if (!pl) return 0;
945
946         num_elements = rbtree_num_elements(pl->tree);
947         if (num_elements < pl->num_outgoing) return 0; /* panic! */
948
949         return num_elements - pl->num_outgoing;
950 }
951
952 uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
953 {
954         if (!pl) return 0;
955
956         return pl->num_outgoing;
957 }
958
959 /*
960  *      Debug the packet if requested.
961  */
962 void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
963 {
964         char src_ipaddr[128];
965         char dst_ipaddr[128];
966
967         if (!fp) return;
968         if (!packet) return;
969
970         /*
971          *      Client-specific debugging re-prints the input
972          *      packet into the client log.
973          *
974          *      This really belongs in a utility library
975          */
976         if (is_radius_code(packet->code)) {
977                 fprintf(fp, "%s %s Id %i from %s%s%s:%i to %s%s%s:%i length %zu\n",
978                         received ? "Received" : "Sent",
979                         fr_packet_codes[packet->code],
980                         packet->id,
981                         packet->src_ipaddr.af == AF_INET6 ? "[" : "",
982                         inet_ntop(packet->src_ipaddr.af,
983                                   &packet->src_ipaddr.ipaddr,
984                                   src_ipaddr, sizeof(src_ipaddr)),
985                         packet->src_ipaddr.af == AF_INET6 ? "]" : "",
986                         packet->src_port,
987                         packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
988                         inet_ntop(packet->dst_ipaddr.af,
989                                   &packet->dst_ipaddr.ipaddr,
990                                   dst_ipaddr, sizeof(dst_ipaddr)),
991                         packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
992                         packet->dst_port,
993                         packet->data_len);
994         } else {
995                 fprintf(fp, "%s code %u Id %i from %s%s%s:%i to %s%s%s:%i length %zu\n",
996                         received ? "Received" : "Sent",
997                         packet->code,
998                         packet->id,
999                         packet->src_ipaddr.af == AF_INET6 ? "[" : "",
1000                         inet_ntop(packet->src_ipaddr.af,
1001                                   &packet->src_ipaddr.ipaddr,
1002                                   src_ipaddr, sizeof(src_ipaddr)),
1003                         packet->src_ipaddr.af == AF_INET6 ? "]" : "",
1004                         packet->src_port,
1005                         packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
1006                         inet_ntop(packet->dst_ipaddr.af,
1007                                   &packet->dst_ipaddr.ipaddr,
1008                                   dst_ipaddr, sizeof(dst_ipaddr)),
1009                         packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
1010                         packet->dst_port,
1011                         packet->data_len);
1012         }
1013 }
1014