The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
id.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 170d9d103bbae2f33781296e65eac7197f07f076 $
19  *
20  * @file protocols/radius/id.c
21  * @brief Functions to allocate 8-bit IDs for a particular socket.
22  *
23  * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
24  */
25 RCSID("$Id: 170d9d103bbae2f33781296e65eac7197f07f076 $")
26 
27 #include <freeradius-devel/radius/id.h>
28 
30  int num_free_ids; //!< number of used IDs
31 
33  int free_end;
34 
35  fr_radius_id_ctx_t id[256]; //!< pointers to request / reply data
36 
37  int free_ids[256];
38 };
39 
40 
41 
42 /** Allocate a tracking structure for one packet code.
43  *
44  */
46 {
47  uint32_t i;
48  fr_radius_id_t *track;
49 
50  track = talloc_zero(ctx, fr_radius_id_t);
51  if (!track) return NULL;
52 
53  track->num_free_ids = 256;
54  track->free_start = 0;
55  track->free_end = 0;
56 
57  for (i = 0; i < 256; i++) {
58  track->free_ids[i] = i;
59  }
60 
61  /*
62  * Shuffle the entirs using a Fisher-Yates shuffle.
63  *
64  * We loop from i=255..1, choosing random numbers j, such that 0 <= j <= i
65  * And then swap a[j],a[i]
66  *
67  * We choose a 32-bit random number, and then take the modulo of that and i+1. Which means that
68  * the resulting random number j is [0..i], whereas taking the modulo with i, then the random
69  * number j will instead be chosen to be [0..i)
70  */
71  for (i = 255; i >= 1; i--) {
72  uint32_t j = fr_rand() % (i + 1); /* small bias, but we don't care much */
73  int tmp;
74 
75  if (j == i) continue;
76 
77  tmp = track->free_ids[j];
78  track->free_ids[j] = track->free_ids[i];
79  track->free_ids[i] = tmp;
80  }
81 
82 
83  return track;
84 }
85 
86 /** Allocate an ID for a packet, using LRU
87  *
88  */
90 {
91  int id;
92 
93  id = track->free_ids[track->free_start];
94  fr_assert(id >= 0);
95  fr_assert(id < 256);
96 
97  fr_assert(!track->id[id].packet);
98 
99  track->free_ids[track->free_start] = -1;
100 
101  track->free_start++;
102  track->free_start &= 0xff;
103 
104  fr_assert(track->num_free_ids > 0);
105  track->num_free_ids--;
106 
107  track->id[id] = (fr_radius_id_ctx_t) {
108  .packet = packet,
109  };
110  packet->id = id;
111 
112  return &track->id[id];
113 }
114 
115 /** De-allocate an ID for a packet, using LRU
116  *
117  */
118 void fr_radius_id_push(fr_radius_id_t *track, fr_packet_t const *packet)
119 {
120  fr_assert(packet->id >= 0);
121  fr_assert(packet->id < 256);
122 
123  fr_assert(track->id[packet->id].packet == packet);
124  fr_assert(track->num_free_ids < 256);
125  fr_assert(track->free_start != track->free_end);
126  fr_assert(track->free_end >= 0);
127  fr_assert(track->free_end < 256);
128  fr_assert(track->free_ids[track->free_end] == -1);
129 
130  track->free_ids[track->free_end] = packet->id;
131 
132  track->free_end++;
133  track->free_end &= 0xff;
134 
135  track->id[packet->id].packet = NULL;
136  track->num_free_ids++;
137 }
138 
140 {
141  fr_assert(id >= 0);
142  fr_assert(id < 256);
143 
144  return &track->id[id];
145 }
146 
147 /** Forces the next ID to be the given one
148  *
149  */
151 {
152  int i, first;
153 
154  fr_assert(id >= 0);
155  fr_assert(id < 256);
156 
157  for (i = 0; i < 256; i++) {
158  if (track->free_ids[(track->free_start + i) & 0xff] != id) continue;
159 
160  /*
161  * It's already the first one. We don't need to do any more.
162  */
163  if (i == 0) return 0;
164 
165  first = track->free_ids[track->free_start];
166  track->free_ids[track->free_start] = id;
167  track->free_ids[(track->free_start + i) & 0xff] = first;
168 
169  return 0;
170  }
171 
172  fr_strerror_const("Cannot assign ID");
173  return -1;
174 }
#define RCSID(id)
Definition: build.h:444
unsigned int uint32_t
Definition: merged_model.c:33
void fr_radius_id_push(fr_radius_id_t *track, fr_packet_t const *packet)
De-allocate an ID for a packet, using LRU.
Definition: id.c:118
int free_ids[256]
Definition: id.c:37
int free_start
Definition: id.c:32
int fr_radius_id_force(fr_radius_id_t *track, int id)
Forces the next ID to be the given one.
Definition: id.c:150
int free_end
Definition: id.c:33
fr_radius_id_t * fr_radius_id_alloc(TALLOC_CTX *ctx)
Allocate a tracking structure for one packet code.
Definition: id.c:45
fr_radius_id_ctx_t id[256]
pointers to request / reply data
Definition: id.c:35
fr_radius_id_ctx_t * fr_radius_id_find(fr_radius_id_t *track, int id)
Definition: id.c:139
int num_free_ids
number of used IDs
Definition: id.c:30
fr_radius_id_ctx_t * fr_radius_id_pop(fr_radius_id_t *track, fr_packet_t *packet)
Allocate an ID for a packet, using LRU.
Definition: id.c:89
fr_packet_t * packet
outgoing packet
Definition: id.h:36
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
fr_assert(0)
int id
Packet ID (used to link requests/responses).
Definition: packet.h:60
#define fr_strerror_const(_msg)
Definition: strerror.h:223