ntp_peer.c revision 1.12 1 1.11 christos /* $NetBSD: ntp_peer.c,v 1.12 2018/04/07 00:19:53 christos Exp $ */
2 1.1 kardel
3 1.1 kardel /*
4 1.1 kardel * ntp_peer.c - management of data maintained for peer associations
5 1.1 kardel */
6 1.1 kardel #ifdef HAVE_CONFIG_H
7 1.1 kardel #include <config.h>
8 1.1 kardel #endif
9 1.1 kardel
10 1.1 kardel #include <stdio.h>
11 1.1 kardel #include <sys/types.h>
12 1.1 kardel
13 1.1 kardel #include "ntpd.h"
14 1.1 kardel #include "ntp_lists.h"
15 1.1 kardel #include "ntp_stdlib.h"
16 1.1 kardel #include "ntp_control.h"
17 1.1 kardel #include <ntp_random.h>
18 1.1 kardel
19 1.1 kardel /*
20 1.4 christos * Table of valid association combinations
21 1.4 christos * ---------------------------------------
22 1.1 kardel *
23 1.1 kardel * packet->mode
24 1.1 kardel * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST
25 1.1 kardel * ---------- | ---------------------------------------------
26 1.1 kardel * NO_PEER | e 1 0 1 1 1
27 1.1 kardel * ACTIVE | e 1 1 0 0 0
28 1.1 kardel * PASSIVE | e 1 e 0 0 0
29 1.1 kardel * CLIENT | e 0 0 0 1 0
30 1.1 kardel * SERVER | e 0 0 0 0 0
31 1.1 kardel * BCAST | e 0 0 0 0 0
32 1.1 kardel * BCLIENT | e 0 0 0 e 1
33 1.1 kardel *
34 1.1 kardel * One point to note here: a packet in BCAST mode can potentially match
35 1.1 kardel * a peer in CLIENT mode, but we that is a special case and we check for
36 1.1 kardel * that early in the decision process. This avoids having to keep track
37 1.1 kardel * of what kind of associations are possible etc... We actually
38 1.1 kardel * circumvent that problem by requiring that the first b(m)roadcast
39 1.1 kardel * received after the change back to BCLIENT mode sets the clock.
40 1.1 kardel */
41 1.1 kardel #define AM_MODES 7 /* number of rows and columns */
42 1.1 kardel #define NO_PEER 0 /* action when no peer is found */
43 1.1 kardel
44 1.1 kardel int AM[AM_MODES][AM_MODES] = {
45 1.4 christos /* packet->mode */
46 1.4 christos /* peer { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */
47 1.4 christos /* mode */
48 1.1 kardel /*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, AM_FXMIT, AM_MANYCAST, AM_NEWBCL},
49 1.1 kardel
50 1.1 kardel /*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
51 1.1 kardel
52 1.1 kardel /*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
53 1.1 kardel
54 1.1 kardel /*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_NOMATCH},
55 1.1 kardel
56 1.1 kardel /*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
57 1.1 kardel
58 1.1 kardel /*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
59 1.1 kardel
60 1.1 kardel /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT},
61 1.1 kardel };
62 1.1 kardel
63 1.1 kardel #define MATCH_ASSOC(x, y) AM[(x)][(y)]
64 1.1 kardel
65 1.1 kardel /*
66 1.1 kardel * These routines manage the allocation of memory to peer structures
67 1.4 christos * and the maintenance of three data structures involving all peers:
68 1.4 christos *
69 1.4 christos * - peer_list is a single list with all peers, suitable for scanning
70 1.4 christos * operations over all peers.
71 1.4 christos * - peer_adr_hash is an array of lists indexed by hashed peer address.
72 1.4 christos * - peer_aid_hash is an array of lists indexed by hashed associd.
73 1.4 christos *
74 1.4 christos * They also maintain a free list of peer structures, peer_free.
75 1.4 christos *
76 1.4 christos * The three main entry points are findpeer(), which looks for matching
77 1.4 christos * peer structures in the peer list, newpeer(), which allocates a new
78 1.4 christos * peer structure and adds it to the list, and unpeer(), which
79 1.4 christos * demobilizes the association and deallocates the structure.
80 1.1 kardel */
81 1.1 kardel /*
82 1.1 kardel * Peer hash tables
83 1.1 kardel */
84 1.1 kardel struct peer *peer_hash[NTP_HASH_SIZE]; /* peer hash table */
85 1.1 kardel int peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
86 1.1 kardel struct peer *assoc_hash[NTP_HASH_SIZE]; /* association ID hash table */
87 1.4 christos int assoc_hash_count[NTP_HASH_SIZE];/* peers in each bucket */
88 1.4 christos struct peer *peer_list; /* peer structures list */
89 1.1 kardel static struct peer *peer_free; /* peer structures free list */
90 1.1 kardel int peer_free_count; /* count of free structures */
91 1.1 kardel
92 1.1 kardel /*
93 1.1 kardel * Association ID. We initialize this value randomly, then assign a new
94 1.4 christos * value every time an association is mobilized.
95 1.1 kardel */
96 1.1 kardel static associd_t current_association_ID; /* association ID */
97 1.6 christos static associd_t initial_association_ID; /* association ID */
98 1.1 kardel
99 1.1 kardel /*
100 1.1 kardel * Memory allocation watermarks.
101 1.1 kardel */
102 1.4 christos #define INIT_PEER_ALLOC 8 /* static preallocation */
103 1.4 christos #define INC_PEER_ALLOC 4 /* add N more when empty */
104 1.1 kardel
105 1.1 kardel /*
106 1.1 kardel * Miscellaneous statistic counters which may be queried.
107 1.1 kardel */
108 1.1 kardel u_long peer_timereset; /* time stat counters zeroed */
109 1.1 kardel u_long findpeer_calls; /* calls to findpeer */
110 1.1 kardel u_long assocpeer_calls; /* calls to findpeerbyassoc */
111 1.1 kardel u_long peer_allocations; /* allocations from free list */
112 1.1 kardel u_long peer_demobilizations; /* structs freed to free list */
113 1.1 kardel int total_peer_structs; /* peer structs */
114 1.1 kardel int peer_associations; /* mobilized associations */
115 1.1 kardel int peer_preempt; /* preemptable associations */
116 1.1 kardel static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
117 1.1 kardel
118 1.4 christos static struct peer * findexistingpeer_name(const char *, u_short,
119 1.4 christos struct peer *, int);
120 1.4 christos static struct peer * findexistingpeer_addr(sockaddr_u *,
121 1.4 christos struct peer *, int,
122 1.12 christos u_char, int *);
123 1.4 christos static void free_peer(struct peer *, int);
124 1.4 christos static void getmorepeermem(void);
125 1.4 christos static int score(struct peer *);
126 1.1 kardel
127 1.1 kardel
128 1.1 kardel /*
129 1.1 kardel * init_peer - initialize peer data structures and counters
130 1.1 kardel *
131 1.1 kardel * N.B. We use the random number routine in here. It had better be
132 1.1 kardel * initialized prior to getting here.
133 1.1 kardel */
134 1.1 kardel void
135 1.1 kardel init_peer(void)
136 1.1 kardel {
137 1.4 christos int i;
138 1.1 kardel
139 1.1 kardel /*
140 1.4 christos * Initialize peer free list from static allocation.
141 1.1 kardel */
142 1.4 christos for (i = COUNTOF(init_peer_alloc) - 1; i >= 0; i--)
143 1.4 christos LINK_SLIST(peer_free, &init_peer_alloc[i], p_link);
144 1.4 christos total_peer_structs = COUNTOF(init_peer_alloc);
145 1.4 christos peer_free_count = COUNTOF(init_peer_alloc);
146 1.1 kardel
147 1.1 kardel /*
148 1.1 kardel * Initialize our first association ID
149 1.1 kardel */
150 1.4 christos do
151 1.4 christos current_association_ID = ntp_random() & ASSOCID_MAX;
152 1.4 christos while (!current_association_ID);
153 1.6 christos initial_association_ID = current_association_ID;
154 1.1 kardel }
155 1.1 kardel
156 1.1 kardel
157 1.1 kardel /*
158 1.1 kardel * getmorepeermem - add more peer structures to the free list
159 1.1 kardel */
160 1.1 kardel static void
161 1.1 kardel getmorepeermem(void)
162 1.1 kardel {
163 1.4 christos int i;
164 1.4 christos struct peer *peers;
165 1.1 kardel
166 1.11 christos peers = eallocarray(INC_PEER_ALLOC, sizeof(*peers));
167 1.4 christos
168 1.4 christos for (i = INC_PEER_ALLOC - 1; i >= 0; i--)
169 1.4 christos LINK_SLIST(peer_free, &peers[i], p_link);
170 1.1 kardel
171 1.1 kardel total_peer_structs += INC_PEER_ALLOC;
172 1.1 kardel peer_free_count += INC_PEER_ALLOC;
173 1.1 kardel }
174 1.1 kardel
175 1.1 kardel
176 1.4 christos static struct peer *
177 1.4 christos findexistingpeer_name(
178 1.4 christos const char * hostname,
179 1.4 christos u_short hname_fam,
180 1.4 christos struct peer * start_peer,
181 1.4 christos int mode
182 1.4 christos )
183 1.4 christos {
184 1.4 christos struct peer *p;
185 1.4 christos
186 1.4 christos if (NULL == start_peer)
187 1.4 christos p = peer_list;
188 1.4 christos else
189 1.4 christos p = start_peer->p_link;
190 1.4 christos for (; p != NULL; p = p->p_link)
191 1.4 christos if (p->hostname != NULL
192 1.4 christos && (-1 == mode || p->hmode == mode)
193 1.4 christos && (AF_UNSPEC == hname_fam
194 1.4 christos || AF_UNSPEC == AF(&p->srcadr)
195 1.4 christos || hname_fam == AF(&p->srcadr))
196 1.4 christos && !strcasecmp(p->hostname, hostname))
197 1.4 christos break;
198 1.4 christos return p;
199 1.4 christos }
200 1.4 christos
201 1.4 christos
202 1.4 christos static
203 1.4 christos struct peer *
204 1.4 christos findexistingpeer_addr(
205 1.3 kardel sockaddr_u * addr,
206 1.3 kardel struct peer * start_peer,
207 1.3 kardel int mode,
208 1.12 christos u_char cast_flags,
209 1.12 christos int * ip_count
210 1.1 kardel )
211 1.1 kardel {
212 1.4 christos struct peer *peer;
213 1.4 christos
214 1.12 christos DPRINTF(2, ("findexistingpeer_addr(%s, %s, %d, 0x%x, %p)\n",
215 1.4 christos sptoa(addr),
216 1.4 christos (start_peer)
217 1.4 christos ? sptoa(&start_peer->srcadr)
218 1.4 christos : "NULL",
219 1.12 christos mode, (u_int)cast_flags, ip_count));
220 1.1 kardel
221 1.1 kardel /*
222 1.1 kardel * start_peer is included so we can locate instances of the
223 1.1 kardel * same peer through different interfaces in the hash table.
224 1.3 kardel * Without MDF_BCLNT, a match requires the same mode and remote
225 1.3 kardel * address. MDF_BCLNT associations start out as MODE_CLIENT
226 1.3 kardel * if broadcastdelay is not specified, and switch to
227 1.3 kardel * MODE_BCLIENT after estimating the one-way delay. Duplicate
228 1.3 kardel * associations are expanded in definition to match any other
229 1.3 kardel * MDF_BCLNT with the same srcadr (remote, unicast address).
230 1.1 kardel */
231 1.1 kardel if (NULL == start_peer)
232 1.1 kardel peer = peer_hash[NTP_HASH_ADDR(addr)];
233 1.1 kardel else
234 1.4 christos peer = start_peer->adr_link;
235 1.1 kardel
236 1.1 kardel while (peer != NULL) {
237 1.4 christos DPRINTF(3, ("%s %s %d %d 0x%x 0x%x ", sptoa(addr),
238 1.4 christos sptoa(&peer->srcadr), mode, peer->hmode,
239 1.4 christos (u_int)cast_flags, (u_int)peer->cast_flags));
240 1.12 christos if (ip_count) {
241 1.12 christos if (SOCK_EQ(addr, &peer->srcadr)) {
242 1.12 christos (*ip_count)++;
243 1.12 christos }
244 1.12 christos }
245 1.4 christos if ((-1 == mode || peer->hmode == mode ||
246 1.4 christos ((MDF_BCLNT & peer->cast_flags) &&
247 1.4 christos (MDF_BCLNT & cast_flags))) &&
248 1.4 christos ADDR_PORT_EQ(addr, &peer->srcadr)) {
249 1.4 christos DPRINTF(3, ("found.\n"));
250 1.1 kardel break;
251 1.4 christos }
252 1.4 christos DPRINTF(3, ("\n"));
253 1.4 christos peer = peer->adr_link;
254 1.1 kardel }
255 1.3 kardel
256 1.3 kardel return peer;
257 1.1 kardel }
258 1.1 kardel
259 1.1 kardel
260 1.1 kardel /*
261 1.4 christos * findexistingpeer - search by address and return a pointer to a peer.
262 1.4 christos */
263 1.4 christos struct peer *
264 1.4 christos findexistingpeer(
265 1.4 christos sockaddr_u * addr,
266 1.4 christos const char * hostname,
267 1.4 christos struct peer * start_peer,
268 1.4 christos int mode,
269 1.12 christos u_char cast_flags,
270 1.12 christos int * ip_count
271 1.4 christos )
272 1.4 christos {
273 1.4 christos if (hostname != NULL)
274 1.4 christos return findexistingpeer_name(hostname, AF(addr),
275 1.4 christos start_peer, mode);
276 1.4 christos else
277 1.4 christos return findexistingpeer_addr(addr, start_peer, mode,
278 1.12 christos cast_flags, ip_count);
279 1.4 christos }
280 1.4 christos
281 1.4 christos
282 1.4 christos /*
283 1.3 kardel * findpeer - find and return a peer match for a received datagram in
284 1.3 kardel * the peer_hash table.
285 1.10 christos *
286 1.10 christos * [Bug 3072] To faciliate a faster reorganisation after routing changes
287 1.10 christos * the original code re-assigned the peer address to be the destination
288 1.10 christos * of the received packet and initiated another round on a mismatch.
289 1.10 christos * Unfortunately this leaves us wide open for a DoS attack where the
290 1.10 christos * attacker directs a packet with forged destination address to us --
291 1.10 christos * this results in a wrong interface assignment, actually creating a DoS
292 1.10 christos * situation.
293 1.10 christos *
294 1.10 christos * This condition would persist until the next update of the interface
295 1.10 christos * list, but a continued attack would put us out of business again soon
296 1.10 christos * enough. Authentication alone does not help here, since it does not
297 1.10 christos * protect the UDP layer and leaves us open for a replay attack.
298 1.10 christos *
299 1.10 christos * So we do not update the adresses and wait until the next interface
300 1.10 christos * list update does the right thing for us.
301 1.1 kardel */
302 1.1 kardel struct peer *
303 1.1 kardel findpeer(
304 1.3 kardel struct recvbuf *rbufp,
305 1.3 kardel int pkt_mode,
306 1.3 kardel int * action
307 1.1 kardel )
308 1.1 kardel {
309 1.3 kardel struct peer * p;
310 1.3 kardel sockaddr_u * srcadr;
311 1.3 kardel u_int hash;
312 1.3 kardel struct pkt * pkt;
313 1.3 kardel l_fp pkt_org;
314 1.1 kardel
315 1.1 kardel findpeer_calls++;
316 1.3 kardel srcadr = &rbufp->recv_srcadr;
317 1.1 kardel hash = NTP_HASH_ADDR(srcadr);
318 1.4 christos for (p = peer_hash[hash]; p != NULL; p = p->adr_link) {
319 1.1 kardel
320 1.10 christos /* [Bug 3072] ensure interface of peer matches */
321 1.11 christos /* [Bug 3356] ... if NOT a broadcast peer! */
322 1.11 christos if (p->hmode != MODE_BCLIENT && p->dstadr != rbufp->dstadr)
323 1.10 christos continue;
324 1.10 christos
325 1.10 christos /* ensure peer source address matches */
326 1.10 christos if ( ! ADDR_PORT_EQ(srcadr, &p->srcadr))
327 1.10 christos continue;
328 1.10 christos
329 1.10 christos /* If the association matching rules determine that this
330 1.10 christos * is not a valid combination, then look for the next
331 1.10 christos * valid peer association.
332 1.10 christos */
333 1.10 christos *action = MATCH_ASSOC(p->hmode, pkt_mode);
334 1.3 kardel
335 1.10 christos /* A response to our manycastclient solicitation might
336 1.10 christos * be misassociated with an ephemeral peer already spun
337 1.10 christos * for the server. If the packet's org timestamp
338 1.10 christos * doesn't match the peer's, check if it matches the
339 1.10 christos * ACST prototype peer's. If so it is a redundant
340 1.10 christos * solicitation response, return AM_ERR to discard it.
341 1.10 christos * [Bug 1762]
342 1.10 christos */
343 1.10 christos if (MODE_SERVER == pkt_mode && AM_PROCPKT == *action) {
344 1.10 christos pkt = &rbufp->recv_pkt;
345 1.10 christos NTOHL_FP(&pkt->org, &pkt_org);
346 1.10 christos if (!L_ISEQU(&p->aorg, &pkt_org) &&
347 1.10 christos findmanycastpeer(rbufp))
348 1.10 christos *action = AM_ERR;
349 1.10 christos }
350 1.1 kardel
351 1.10 christos /* if an error was returned, exit back right here. */
352 1.10 christos if (*action == AM_ERR)
353 1.10 christos return NULL;
354 1.1 kardel
355 1.10 christos /* if a match is found, we stop our search. */
356 1.10 christos if (*action != AM_NOMATCH)
357 1.10 christos break;
358 1.1 kardel }
359 1.1 kardel
360 1.10 christos /* If no matching association is found... */
361 1.10 christos if (NULL == p)
362 1.1 kardel *action = MATCH_ASSOC(NO_PEER, pkt_mode);
363 1.10 christos
364 1.3 kardel return p;
365 1.1 kardel }
366 1.1 kardel
367 1.1 kardel /*
368 1.4 christos * findpeerbyassoc - find and return a peer using his association ID
369 1.1 kardel */
370 1.1 kardel struct peer *
371 1.1 kardel findpeerbyassoc(
372 1.4 christos associd_t assoc
373 1.1 kardel )
374 1.1 kardel {
375 1.3 kardel struct peer *p;
376 1.1 kardel u_int hash;
377 1.1 kardel
378 1.1 kardel assocpeer_calls++;
379 1.1 kardel hash = assoc & NTP_HASH_MASK;
380 1.4 christos for (p = assoc_hash[hash]; p != NULL; p = p->aid_link)
381 1.3 kardel if (assoc == p->associd)
382 1.4 christos break;
383 1.4 christos return p;
384 1.1 kardel }
385 1.1 kardel
386 1.1 kardel
387 1.1 kardel /*
388 1.1 kardel * clear_all - flush all time values for all associations
389 1.1 kardel */
390 1.1 kardel void
391 1.1 kardel clear_all(void)
392 1.1 kardel {
393 1.4 christos struct peer *p;
394 1.1 kardel
395 1.1 kardel /*
396 1.1 kardel * This routine is called when the clock is stepped, and so all
397 1.1 kardel * previously saved time values are untrusted.
398 1.1 kardel */
399 1.4 christos for (p = peer_list; p != NULL; p = p->p_link)
400 1.4 christos if (!(MDF_TXONLY_MASK & p->cast_flags))
401 1.4 christos peer_clear(p, "STEP");
402 1.4 christos
403 1.4 christos DPRINTF(1, ("clear_all: at %lu\n", current_time));
404 1.1 kardel }
405 1.1 kardel
406 1.1 kardel
407 1.1 kardel /*
408 1.1 kardel * score_all() - determine if an association can be demobilized
409 1.1 kardel */
410 1.1 kardel int
411 1.1 kardel score_all(
412 1.1 kardel struct peer *peer /* peer structure pointer */
413 1.1 kardel )
414 1.1 kardel {
415 1.4 christos struct peer *speer;
416 1.1 kardel int temp, tamp;
417 1.4 christos int x;
418 1.1 kardel
419 1.1 kardel /*
420 1.4 christos * This routine finds the minimum score for all preemptible
421 1.4 christos * associations and returns > 0 if the association can be
422 1.1 kardel * demobilized.
423 1.1 kardel */
424 1.1 kardel tamp = score(peer);
425 1.1 kardel temp = 100;
426 1.4 christos for (speer = peer_list; speer != NULL; speer = speer->p_link)
427 1.4 christos if (speer->flags & FLAG_PREEMPT) {
428 1.4 christos x = score(speer);
429 1.4 christos if (x < temp)
430 1.1 kardel temp = x;
431 1.1 kardel }
432 1.4 christos DPRINTF(1, ("score_all: at %lu score %d min %d\n",
433 1.4 christos current_time, tamp, temp));
434 1.4 christos
435 1.1 kardel if (tamp != temp)
436 1.1 kardel temp = 0;
437 1.4 christos
438 1.4 christos return temp;
439 1.1 kardel }
440 1.1 kardel
441 1.1 kardel
442 1.1 kardel /*
443 1.1 kardel * score() - calculate preemption score
444 1.1 kardel */
445 1.1 kardel static int
446 1.1 kardel score(
447 1.1 kardel struct peer *peer /* peer structure pointer */
448 1.1 kardel )
449 1.1 kardel {
450 1.1 kardel int temp;
451 1.1 kardel
452 1.1 kardel /*
453 1.1 kardel * This routine calculates the premption score from the peer
454 1.1 kardel * error bits and status. Increasing values are more cherished.
455 1.1 kardel */
456 1.1 kardel temp = 0;
457 1.1 kardel if (!(peer->flash & TEST10))
458 1.1 kardel temp++; /* 1 good synch and stratum */
459 1.1 kardel if (!(peer->flash & TEST13))
460 1.1 kardel temp++; /* 2 reachable */
461 1.1 kardel if (!(peer->flash & TEST12))
462 1.1 kardel temp++; /* 3 no loop */
463 1.1 kardel if (!(peer->flash & TEST11))
464 1.1 kardel temp++; /* 4 good distance */
465 1.1 kardel if (peer->status >= CTL_PST_SEL_SELCAND)
466 1.1 kardel temp++; /* 5 in the hunt */
467 1.1 kardel if (peer->status != CTL_PST_SEL_EXCESS)
468 1.1 kardel temp++; /* 6 not spare tire */
469 1.1 kardel return (temp); /* selection status */
470 1.1 kardel }
471 1.1 kardel
472 1.1 kardel
473 1.1 kardel /*
474 1.4 christos * free_peer - internal routine to free memory referred to by a struct
475 1.4 christos * peer and return it to the peer free list. If unlink is
476 1.4 christos * nonzero, unlink from the various lists.
477 1.4 christos */
478 1.4 christos static void
479 1.4 christos free_peer(
480 1.4 christos struct peer * p,
481 1.4 christos int unlink_peer
482 1.4 christos )
483 1.4 christos {
484 1.4 christos struct peer * unlinked;
485 1.4 christos int hash;
486 1.4 christos
487 1.4 christos if (unlink_peer) {
488 1.4 christos hash = NTP_HASH_ADDR(&p->srcadr);
489 1.4 christos peer_hash_count[hash]--;
490 1.4 christos
491 1.4 christos UNLINK_SLIST(unlinked, peer_hash[hash], p, adr_link,
492 1.4 christos struct peer);
493 1.4 christos if (NULL == unlinked) {
494 1.4 christos peer_hash_count[hash]++;
495 1.4 christos msyslog(LOG_ERR, "peer %s not in address table!",
496 1.4 christos stoa(&p->srcadr));
497 1.4 christos }
498 1.4 christos
499 1.4 christos /*
500 1.4 christos * Remove him from the association hash as well.
501 1.4 christos */
502 1.4 christos hash = p->associd & NTP_HASH_MASK;
503 1.4 christos assoc_hash_count[hash]--;
504 1.4 christos
505 1.4 christos UNLINK_SLIST(unlinked, assoc_hash[hash], p, aid_link,
506 1.4 christos struct peer);
507 1.4 christos if (NULL == unlinked) {
508 1.4 christos assoc_hash_count[hash]++;
509 1.4 christos msyslog(LOG_ERR,
510 1.4 christos "peer %s not in association ID table!",
511 1.4 christos stoa(&p->srcadr));
512 1.4 christos }
513 1.4 christos
514 1.4 christos /* Remove him from the overall list. */
515 1.4 christos UNLINK_SLIST(unlinked, peer_list, p, p_link,
516 1.4 christos struct peer);
517 1.4 christos if (NULL == unlinked)
518 1.4 christos msyslog(LOG_ERR, "%s not in peer list!",
519 1.4 christos stoa(&p->srcadr));
520 1.4 christos }
521 1.4 christos
522 1.4 christos if (p->hostname != NULL)
523 1.4 christos free(p->hostname);
524 1.4 christos
525 1.4 christos if (p->ident != NULL)
526 1.4 christos free(p->ident);
527 1.4 christos
528 1.4 christos if (p->addrs != NULL)
529 1.4 christos free(p->addrs); /* from copy_addrinfo_list() */
530 1.4 christos
531 1.4 christos /* Add his corporeal form to peer free list */
532 1.4 christos ZERO(*p);
533 1.4 christos LINK_SLIST(peer_free, p, p_link);
534 1.4 christos peer_free_count++;
535 1.4 christos }
536 1.4 christos
537 1.4 christos
538 1.4 christos /*
539 1.1 kardel * unpeer - remove peer structure from hash table and free structure
540 1.1 kardel */
541 1.1 kardel void
542 1.1 kardel unpeer(
543 1.4 christos struct peer *peer
544 1.1 kardel )
545 1.1 kardel {
546 1.4 christos mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd);
547 1.4 christos restrict_source(&peer->srcadr, 1, 0);
548 1.4 christos set_peerdstadr(peer, NULL);
549 1.1 kardel peer_demobilizations++;
550 1.1 kardel peer_associations--;
551 1.4 christos if (FLAG_PREEMPT & peer->flags)
552 1.1 kardel peer_preempt--;
553 1.1 kardel #ifdef REFCLOCK
554 1.1 kardel /*
555 1.1 kardel * If this peer is actually a clock, shut it down first
556 1.1 kardel */
557 1.4 christos if (FLAG_REFCLOCK & peer->flags)
558 1.4 christos refclock_unpeer(peer);
559 1.1 kardel #endif
560 1.1 kardel
561 1.4 christos free_peer(peer, TRUE);
562 1.1 kardel }
563 1.1 kardel
564 1.1 kardel
565 1.1 kardel /*
566 1.1 kardel * peer_config - configure a new association
567 1.1 kardel */
568 1.1 kardel struct peer *
569 1.1 kardel peer_config(
570 1.4 christos sockaddr_u * srcadr,
571 1.4 christos const char * hostname,
572 1.4 christos endpt * dstadr,
573 1.12 christos int ippeerlimit,
574 1.4 christos u_char hmode,
575 1.4 christos u_char version,
576 1.4 christos u_char minpoll,
577 1.4 christos u_char maxpoll,
578 1.4 christos u_int flags,
579 1.4 christos u_int32 ttl,
580 1.4 christos keyid_t key,
581 1.4 christos const char * ident /* autokey group */
582 1.1 kardel )
583 1.1 kardel {
584 1.1 kardel u_char cast_flags;
585 1.1 kardel
586 1.1 kardel /*
587 1.1 kardel * We do a dirty little jig to figure the cast flags. This is
588 1.1 kardel * probably not the best place to do this, at least until the
589 1.1 kardel * configure code is rebuilt. Note only one flag can be set.
590 1.1 kardel */
591 1.1 kardel switch (hmode) {
592 1.1 kardel case MODE_BROADCAST:
593 1.1 kardel if (IS_MCAST(srcadr))
594 1.1 kardel cast_flags = MDF_MCAST;
595 1.1 kardel else
596 1.1 kardel cast_flags = MDF_BCAST;
597 1.1 kardel break;
598 1.1 kardel
599 1.1 kardel case MODE_CLIENT:
600 1.4 christos if (hostname != NULL && SOCK_UNSPEC(srcadr))
601 1.4 christos cast_flags = MDF_POOL;
602 1.4 christos else if (IS_MCAST(srcadr))
603 1.1 kardel cast_flags = MDF_ACAST;
604 1.1 kardel else
605 1.1 kardel cast_flags = MDF_UCAST;
606 1.1 kardel break;
607 1.1 kardel
608 1.1 kardel default:
609 1.1 kardel cast_flags = MDF_UCAST;
610 1.1 kardel }
611 1.1 kardel
612 1.1 kardel /*
613 1.1 kardel * Mobilize the association and initialize its variables. If
614 1.4 christos * emulating ntpdate, force iburst. For pool and manycastclient
615 1.4 christos * strip FLAG_PREEMPT as the prototype associations are not
616 1.4 christos * themselves preemptible, though the resulting associations
617 1.4 christos * are.
618 1.1 kardel */
619 1.4 christos flags |= FLAG_CONFIG;
620 1.1 kardel if (mode_ntpdate)
621 1.1 kardel flags |= FLAG_IBURST;
622 1.4 christos if ((MDF_ACAST | MDF_POOL) & cast_flags)
623 1.4 christos flags &= ~FLAG_PREEMPT;
624 1.12 christos return newpeer(srcadr, hostname, dstadr, ippeerlimit, hmode, version,
625 1.4 christos minpoll, maxpoll, flags, cast_flags, ttl, key, ident);
626 1.1 kardel }
627 1.1 kardel
628 1.1 kardel /*
629 1.1 kardel * setup peer dstadr field keeping it in sync with the interface
630 1.1 kardel * structures
631 1.1 kardel */
632 1.1 kardel void
633 1.1 kardel set_peerdstadr(
634 1.3 kardel struct peer * p,
635 1.3 kardel endpt * dstadr
636 1.1 kardel )
637 1.1 kardel {
638 1.3 kardel struct peer * unlinked;
639 1.1 kardel
640 1.10 christos DEBUG_INSIST(p != NULL);
641 1.10 christos
642 1.10 christos if (p == NULL)
643 1.10 christos return;
644 1.10 christos
645 1.10 christos /* check for impossible or identical assignment */
646 1.3 kardel if (p->dstadr == dstadr)
647 1.3 kardel return;
648 1.1 kardel
649 1.3 kardel /*
650 1.3 kardel * Don't accept updates to a separate multicast receive-only
651 1.3 kardel * endpt while a BCLNT peer is running its unicast protocol.
652 1.3 kardel */
653 1.3 kardel if (dstadr != NULL && (FLAG_BC_VOL & p->flags) &&
654 1.3 kardel (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) {
655 1.3 kardel return;
656 1.3 kardel }
657 1.10 christos
658 1.10 christos /* unlink from list if we have an address prior to assignment */
659 1.3 kardel if (p->dstadr != NULL) {
660 1.3 kardel p->dstadr->peercnt--;
661 1.3 kardel UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink,
662 1.3 kardel struct peer);
663 1.4 christos msyslog(LOG_INFO, "%s local addr %s -> %s",
664 1.4 christos stoa(&p->srcadr), latoa(p->dstadr),
665 1.4 christos latoa(dstadr));
666 1.3 kardel }
667 1.10 christos
668 1.3 kardel p->dstadr = dstadr;
669 1.10 christos
670 1.10 christos /* link to list if we have an address after assignment */
671 1.10 christos if (p->dstadr != NULL) {
672 1.3 kardel LINK_SLIST(dstadr->peers, p, ilink);
673 1.3 kardel dstadr->peercnt++;
674 1.1 kardel }
675 1.1 kardel }
676 1.1 kardel
677 1.1 kardel /*
678 1.1 kardel * attempt to re-rebind interface if necessary
679 1.1 kardel */
680 1.1 kardel static void
681 1.1 kardel peer_refresh_interface(
682 1.4 christos struct peer *p
683 1.1 kardel )
684 1.1 kardel {
685 1.3 kardel endpt * niface;
686 1.3 kardel endpt * piface;
687 1.1 kardel
688 1.4 christos niface = select_peerinterface(p, &p->srcadr, NULL);
689 1.1 kardel
690 1.3 kardel DPRINTF(4, (
691 1.4 christos "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %u key %08x: new interface: ",
692 1.4 christos p->dstadr == NULL ? "<null>" :
693 1.4 christos stoa(&p->dstadr->sin), stoa(&p->srcadr), p->hmode,
694 1.4 christos p->version, p->minpoll, p->maxpoll, p->flags, p->cast_flags,
695 1.4 christos p->ttl, p->keyid));
696 1.3 kardel if (niface != NULL) {
697 1.3 kardel DPRINTF(4, (
698 1.3 kardel "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s",
699 1.3 kardel niface->fd, niface->bfd, niface->name,
700 1.3 kardel niface->flags, niface->ifindex,
701 1.3 kardel stoa(&niface->sin)));
702 1.3 kardel if (niface->flags & INT_BROADCAST)
703 1.3 kardel DPRINTF(4, (", bcast=%s",
704 1.3 kardel stoa(&niface->bcast)));
705 1.3 kardel DPRINTF(4, (", mask=%s\n", stoa(&niface->mask)));
706 1.3 kardel } else {
707 1.3 kardel DPRINTF(4, ("<NONE>\n"));
708 1.1 kardel }
709 1.1 kardel
710 1.4 christos piface = p->dstadr;
711 1.4 christos set_peerdstadr(p, niface);
712 1.4 christos if (p->dstadr != NULL) {
713 1.1 kardel /*
714 1.1 kardel * clear crypto if we change the local address
715 1.1 kardel */
716 1.4 christos if (p->dstadr != piface && !(MDF_ACAST & p->cast_flags)
717 1.4 christos && MODE_BROADCAST != p->pmode)
718 1.4 christos peer_clear(p, "XFAC");
719 1.1 kardel
720 1.1 kardel /*
721 1.1 kardel * Broadcast needs the socket enabled for broadcast
722 1.1 kardel */
723 1.4 christos if (MDF_BCAST & p->cast_flags)
724 1.4 christos enable_broadcast(p->dstadr, &p->srcadr);
725 1.1 kardel
726 1.1 kardel /*
727 1.1 kardel * Multicast needs the socket interface enabled for
728 1.1 kardel * multicast
729 1.1 kardel */
730 1.4 christos if (MDF_MCAST & p->cast_flags)
731 1.4 christos enable_multicast_if(p->dstadr, &p->srcadr);
732 1.1 kardel }
733 1.1 kardel }
734 1.1 kardel
735 1.4 christos
736 1.1 kardel /*
737 1.1 kardel * refresh_all_peerinterfaces - see that all interface bindings are up
738 1.1 kardel * to date
739 1.1 kardel */
740 1.1 kardel void
741 1.1 kardel refresh_all_peerinterfaces(void)
742 1.1 kardel {
743 1.4 christos struct peer *p;
744 1.1 kardel
745 1.1 kardel /*
746 1.1 kardel * this is called when the interface list has changed
747 1.1 kardel * give all peers a chance to find a better interface
748 1.8 christos * but only if either they don't have an address already
749 1.8 christos * or if the one they have hasn't worked for a while.
750 1.1 kardel */
751 1.8 christos for (p = peer_list; p != NULL; p = p->p_link) {
752 1.8 christos if (!(p->dstadr && (p->reach & 0x3))) // Bug 2849 XOR 2043
753 1.8 christos peer_refresh_interface(p);
754 1.8 christos }
755 1.1 kardel }
756 1.1 kardel
757 1.1 kardel
758 1.1 kardel /*
759 1.1 kardel * newpeer - initialize a new peer association
760 1.1 kardel */
761 1.1 kardel struct peer *
762 1.1 kardel newpeer(
763 1.4 christos sockaddr_u * srcadr,
764 1.4 christos const char * hostname,
765 1.4 christos endpt * dstadr,
766 1.12 christos int ippeerlimit,
767 1.4 christos u_char hmode,
768 1.4 christos u_char version,
769 1.4 christos u_char minpoll,
770 1.4 christos u_char maxpoll,
771 1.4 christos u_int flags,
772 1.4 christos u_char cast_flags,
773 1.4 christos u_int32 ttl,
774 1.4 christos keyid_t key,
775 1.4 christos const char * ident
776 1.1 kardel )
777 1.1 kardel {
778 1.4 christos struct peer * peer;
779 1.4 christos u_int hash;
780 1.12 christos int ip_count = 0;
781 1.12 christos
782 1.1 kardel
783 1.8 christos DEBUG_REQUIRE(srcadr);
784 1.8 christos
785 1.4 christos #ifdef AUTOKEY
786 1.1 kardel /*
787 1.1 kardel * If Autokey is requested but not configured, complain loudly.
788 1.1 kardel */
789 1.1 kardel if (!crypto_flags) {
790 1.1 kardel if (key > NTP_MAXKEY) {
791 1.1 kardel return (NULL);
792 1.1 kardel
793 1.1 kardel } else if (flags & FLAG_SKEY) {
794 1.1 kardel msyslog(LOG_ERR, "Autokey not configured");
795 1.1 kardel return (NULL);
796 1.1 kardel }
797 1.1 kardel }
798 1.4 christos #endif /* AUTOKEY */
799 1.4 christos
800 1.4 christos /*
801 1.4 christos * For now only pool associations have a hostname.
802 1.4 christos */
803 1.8 christos INSIST(NULL == hostname || (MDF_POOL & cast_flags));
804 1.1 kardel
805 1.1 kardel /*
806 1.1 kardel * First search from the beginning for an association with given
807 1.1 kardel * remote address and mode. If an interface is given, search
808 1.1 kardel * from there to find the association which matches that
809 1.1 kardel * destination. If the given interface is "any", track down the
810 1.1 kardel * actual interface, because that's what gets put into the peer
811 1.1 kardel * structure.
812 1.1 kardel */
813 1.1 kardel if (dstadr != NULL) {
814 1.4 christos peer = findexistingpeer(srcadr, hostname, NULL, hmode,
815 1.12 christos cast_flags, &ip_count);
816 1.1 kardel while (peer != NULL) {
817 1.12 christos if ( peer->dstadr == dstadr
818 1.12 christos || ( (MDF_BCLNT & cast_flags)
819 1.12 christos && (MDF_BCLNT & peer->cast_flags)))
820 1.1 kardel break;
821 1.1 kardel
822 1.1 kardel if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) &&
823 1.1 kardel peer->dstadr == findinterface(srcadr))
824 1.1 kardel break;
825 1.1 kardel
826 1.4 christos peer = findexistingpeer(srcadr, hostname, peer,
827 1.12 christos hmode, cast_flags, &ip_count);
828 1.1 kardel }
829 1.3 kardel } else {
830 1.3 kardel /* no endpt address given */
831 1.4 christos peer = findexistingpeer(srcadr, hostname, NULL, hmode,
832 1.12 christos cast_flags, &ip_count);
833 1.1 kardel }
834 1.1 kardel
835 1.1 kardel /*
836 1.1 kardel * If a peer is found, this would be a duplicate and we don't
837 1.3 kardel * allow that. This avoids duplicate ephemeral (broadcast/
838 1.3 kardel * multicast) and preemptible (manycast and pool) client
839 1.1 kardel * associations.
840 1.1 kardel */
841 1.4 christos if (peer != NULL) {
842 1.4 christos DPRINTF(2, ("newpeer(%s) found existing association\n",
843 1.4 christos (hostname)
844 1.4 christos ? hostname
845 1.4 christos : stoa(srcadr)));
846 1.4 christos return NULL;
847 1.4 christos }
848 1.1 kardel
849 1.12 christos DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n",
850 1.12 christos (hostname)
851 1.12 christos ? hostname
852 1.12 christos : stoa(srcadr),
853 1.12 christos ip_count));
854 1.12 christos
855 1.12 christos /* Check ippeerlimit wrt ip_count */
856 1.12 christos if (ippeerlimit > -1) {
857 1.12 christos if (ip_count + 1 > ippeerlimit) {
858 1.12 christos DPRINTF(2, ("newpeer(%s) denied - ippeerlimit %d\n",
859 1.12 christos (hostname)
860 1.12 christos ? hostname
861 1.12 christos : stoa(srcadr),
862 1.12 christos ippeerlimit));
863 1.12 christos return NULL;
864 1.12 christos }
865 1.12 christos } else {
866 1.12 christos DPRINTF(1, ("newpeer(%s) - ippeerlimit %d ignored\n",
867 1.12 christos (hostname)
868 1.12 christos ? hostname
869 1.12 christos : stoa(srcadr),
870 1.12 christos ippeerlimit));
871 1.12 christos }
872 1.12 christos
873 1.1 kardel /*
874 1.1 kardel * Allocate a new peer structure. Some dirt here, since some of
875 1.1 kardel * the initialization requires knowlege of our system state.
876 1.1 kardel */
877 1.1 kardel if (peer_free_count == 0)
878 1.1 kardel getmorepeermem();
879 1.4 christos UNLINK_HEAD_SLIST(peer, peer_free, p_link);
880 1.8 christos INSIST(peer != NULL);
881 1.1 kardel peer_free_count--;
882 1.1 kardel peer_associations++;
883 1.4 christos if (FLAG_PREEMPT & flags)
884 1.1 kardel peer_preempt++;
885 1.1 kardel
886 1.1 kardel /*
887 1.1 kardel * Assign an association ID and increment the system variable.
888 1.1 kardel */
889 1.1 kardel peer->associd = current_association_ID;
890 1.1 kardel if (++current_association_ID == 0)
891 1.1 kardel ++current_association_ID;
892 1.1 kardel
893 1.1 kardel peer->srcadr = *srcadr;
894 1.4 christos if (hostname != NULL)
895 1.4 christos peer->hostname = estrdup(hostname);
896 1.4 christos peer->hmode = hmode;
897 1.4 christos peer->version = version;
898 1.1 kardel peer->flags = flags;
899 1.4 christos peer->cast_flags = cast_flags;
900 1.4 christos set_peerdstadr(peer,
901 1.4 christos select_peerinterface(peer, srcadr, dstadr));
902 1.1 kardel
903 1.1 kardel /*
904 1.1 kardel * It is an error to set minpoll less than NTP_MINPOLL or to
905 1.1 kardel * set maxpoll greater than NTP_MAXPOLL. However, minpoll is
906 1.1 kardel * clamped not greater than NTP_MAXPOLL and maxpoll is clamped
907 1.1 kardel * not less than NTP_MINPOLL without complaint. Finally,
908 1.1 kardel * minpoll is clamped not greater than maxpoll.
909 1.1 kardel */
910 1.1 kardel if (minpoll == 0)
911 1.1 kardel peer->minpoll = NTP_MINDPOLL;
912 1.1 kardel else
913 1.4 christos peer->minpoll = min(minpoll, NTP_MAXPOLL);
914 1.1 kardel if (maxpoll == 0)
915 1.1 kardel peer->maxpoll = NTP_MAXDPOLL;
916 1.1 kardel else
917 1.4 christos peer->maxpoll = max(maxpoll, NTP_MINPOLL);
918 1.1 kardel if (peer->minpoll > peer->maxpoll)
919 1.1 kardel peer->minpoll = peer->maxpoll;
920 1.1 kardel
921 1.4 christos if (peer->dstadr != NULL)
922 1.4 christos DPRINTF(3, ("newpeer(%s): using fd %d and our addr %s\n",
923 1.4 christos stoa(srcadr), peer->dstadr->fd,
924 1.4 christos stoa(&peer->dstadr->sin)));
925 1.1 kardel else
926 1.4 christos DPRINTF(3, ("newpeer(%s): local interface currently not bound\n",
927 1.4 christos stoa(srcadr)));
928 1.1 kardel
929 1.1 kardel /*
930 1.1 kardel * Broadcast needs the socket enabled for broadcast
931 1.1 kardel */
932 1.4 christos if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL)
933 1.1 kardel enable_broadcast(peer->dstadr, srcadr);
934 1.1 kardel
935 1.1 kardel /*
936 1.1 kardel * Multicast needs the socket interface enabled for multicast
937 1.1 kardel */
938 1.4 christos if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL)
939 1.1 kardel enable_multicast_if(peer->dstadr, srcadr);
940 1.1 kardel
941 1.4 christos #ifdef AUTOKEY
942 1.1 kardel if (key > NTP_MAXKEY)
943 1.1 kardel peer->flags |= FLAG_SKEY;
944 1.4 christos #endif /* AUTOKEY */
945 1.4 christos peer->ttl = ttl;
946 1.1 kardel peer->keyid = key;
947 1.4 christos if (ident != NULL)
948 1.4 christos peer->ident = estrdup(ident);
949 1.1 kardel peer->precision = sys_precision;
950 1.1 kardel peer->hpoll = peer->minpoll;
951 1.1 kardel if (cast_flags & MDF_ACAST)
952 1.1 kardel peer_clear(peer, "ACST");
953 1.4 christos else if (cast_flags & MDF_POOL)
954 1.4 christos peer_clear(peer, "POOL");
955 1.1 kardel else if (cast_flags & MDF_MCAST)
956 1.1 kardel peer_clear(peer, "MCST");
957 1.1 kardel else if (cast_flags & MDF_BCAST)
958 1.1 kardel peer_clear(peer, "BCST");
959 1.1 kardel else
960 1.1 kardel peer_clear(peer, "INIT");
961 1.1 kardel if (mode_ntpdate)
962 1.1 kardel peer_ntpdate++;
963 1.1 kardel
964 1.1 kardel /*
965 1.1 kardel * Note time on statistics timers.
966 1.1 kardel */
967 1.1 kardel peer->timereset = current_time;
968 1.1 kardel peer->timereachable = current_time;
969 1.1 kardel peer->timereceived = current_time;
970 1.1 kardel
971 1.4 christos if (ISREFCLOCKADR(&peer->srcadr)) {
972 1.1 kardel #ifdef REFCLOCK
973 1.1 kardel /*
974 1.1 kardel * We let the reference clock support do clock
975 1.1 kardel * dependent initialization. This includes setting
976 1.1 kardel * the peer timer, since the clock may have requirements
977 1.1 kardel * for this.
978 1.1 kardel */
979 1.1 kardel if (maxpoll == 0)
980 1.1 kardel peer->maxpoll = peer->minpoll;
981 1.1 kardel if (!refclock_newpeer(peer)) {
982 1.1 kardel /*
983 1.1 kardel * Dump it, something screwed up
984 1.1 kardel */
985 1.1 kardel set_peerdstadr(peer, NULL);
986 1.4 christos free_peer(peer, 0);
987 1.4 christos return NULL;
988 1.1 kardel }
989 1.4 christos #else /* REFCLOCK */
990 1.4 christos msyslog(LOG_ERR, "refclock %s isn't supported. ntpd was compiled without refclock support.",
991 1.4 christos stoa(&peer->srcadr));
992 1.4 christos set_peerdstadr(peer, NULL);
993 1.4 christos free_peer(peer, 0);
994 1.4 christos return NULL;
995 1.4 christos #endif /* REFCLOCK */
996 1.1 kardel }
997 1.1 kardel
998 1.1 kardel /*
999 1.1 kardel * Put the new peer in the hash tables.
1000 1.1 kardel */
1001 1.1 kardel hash = NTP_HASH_ADDR(&peer->srcadr);
1002 1.4 christos LINK_SLIST(peer_hash[hash], peer, adr_link);
1003 1.1 kardel peer_hash_count[hash]++;
1004 1.1 kardel hash = peer->associd & NTP_HASH_MASK;
1005 1.4 christos LINK_SLIST(assoc_hash[hash], peer, aid_link);
1006 1.1 kardel assoc_hash_count[hash]++;
1007 1.4 christos LINK_SLIST(peer_list, peer, p_link);
1008 1.4 christos
1009 1.4 christos restrict_source(&peer->srcadr, 0, 0);
1010 1.4 christos mprintf_event(PEVNT_MOBIL, peer, "assoc %d", peer->associd);
1011 1.4 christos DPRINTF(1, ("newpeer: %s->%s mode %u vers %u poll %u %u flags 0x%x 0x%x ttl %u key %08x\n",
1012 1.4 christos latoa(peer->dstadr), stoa(&peer->srcadr), peer->hmode,
1013 1.4 christos peer->version, peer->minpoll, peer->maxpoll, peer->flags,
1014 1.4 christos peer->cast_flags, peer->ttl, peer->keyid));
1015 1.4 christos return peer;
1016 1.1 kardel }
1017 1.1 kardel
1018 1.1 kardel
1019 1.1 kardel /*
1020 1.4 christos * peer_clr_stats - clear peer module statistics counters
1021 1.1 kardel */
1022 1.1 kardel void
1023 1.1 kardel peer_clr_stats(void)
1024 1.1 kardel {
1025 1.1 kardel findpeer_calls = 0;
1026 1.1 kardel assocpeer_calls = 0;
1027 1.1 kardel peer_allocations = 0;
1028 1.1 kardel peer_demobilizations = 0;
1029 1.1 kardel peer_timereset = current_time;
1030 1.1 kardel }
1031 1.1 kardel
1032 1.4 christos
1033 1.1 kardel /*
1034 1.1 kardel * peer_reset - reset statistics counters
1035 1.1 kardel */
1036 1.1 kardel void
1037 1.1 kardel peer_reset(
1038 1.1 kardel struct peer *peer
1039 1.1 kardel )
1040 1.1 kardel {
1041 1.1 kardel if (peer == NULL)
1042 1.3 kardel return;
1043 1.1 kardel
1044 1.1 kardel peer->timereset = current_time;
1045 1.1 kardel peer->sent = 0;
1046 1.1 kardel peer->received = 0;
1047 1.1 kardel peer->processed = 0;
1048 1.1 kardel peer->badauth = 0;
1049 1.1 kardel peer->bogusorg = 0;
1050 1.1 kardel peer->oldpkt = 0;
1051 1.1 kardel peer->seldisptoolarge = 0;
1052 1.1 kardel peer->selbroken = 0;
1053 1.1 kardel }
1054 1.1 kardel
1055 1.1 kardel
1056 1.1 kardel /*
1057 1.1 kardel * peer_all_reset - reset all peer statistics counters
1058 1.1 kardel */
1059 1.1 kardel void
1060 1.1 kardel peer_all_reset(void)
1061 1.1 kardel {
1062 1.1 kardel struct peer *peer;
1063 1.1 kardel
1064 1.4 christos for (peer = peer_list; peer != NULL; peer = peer->p_link)
1065 1.1 kardel peer_reset(peer);
1066 1.1 kardel }
1067 1.1 kardel
1068 1.1 kardel
1069 1.1 kardel /*
1070 1.4 christos * findmanycastpeer - find and return a manycastclient or pool
1071 1.4 christos * association matching a received response.
1072 1.1 kardel */
1073 1.1 kardel struct peer *
1074 1.1 kardel findmanycastpeer(
1075 1.1 kardel struct recvbuf *rbufp /* receive buffer pointer */
1076 1.1 kardel )
1077 1.1 kardel {
1078 1.4 christos struct peer *peer;
1079 1.1 kardel struct pkt *pkt;
1080 1.1 kardel l_fp p_org;
1081 1.1 kardel
1082 1.1 kardel /*
1083 1.4 christos * This routine is called upon arrival of a server-mode response
1084 1.4 christos * to a manycastclient multicast solicitation, or to a pool
1085 1.4 christos * server unicast solicitation. Search the peer list for a
1086 1.4 christos * manycastclient association where the last transmit timestamp
1087 1.4 christos * matches the response packet's originate timestamp. There can
1088 1.4 christos * be multiple manycastclient associations, or multiple pool
1089 1.4 christos * solicitation assocations, so this assumes the transmit
1090 1.4 christos * timestamps are unique for such.
1091 1.1 kardel */
1092 1.1 kardel pkt = &rbufp->recv_pkt;
1093 1.4 christos for (peer = peer_list; peer != NULL; peer = peer->p_link)
1094 1.4 christos if (MDF_SOLICIT_MASK & peer->cast_flags) {
1095 1.4 christos NTOHL_FP(&pkt->org, &p_org);
1096 1.4 christos if (L_ISEQU(&p_org, &peer->aorg))
1097 1.4 christos break;
1098 1.1 kardel }
1099 1.4 christos
1100 1.4 christos return peer;
1101 1.1 kardel }
1102 1.6 christos
1103 1.6 christos /* peer_cleanup - clean peer list prior to shutdown */
1104 1.6 christos void peer_cleanup(void)
1105 1.6 christos {
1106 1.6 christos struct peer *peer;
1107 1.6 christos associd_t assoc;
1108 1.6 christos
1109 1.6 christos for (assoc = initial_association_ID; assoc != current_association_ID; assoc++) {
1110 1.6 christos if (assoc != 0U) {
1111 1.6 christos peer = findpeerbyassoc(assoc);
1112 1.6 christos if (peer != NULL)
1113 1.6 christos unpeer(peer);
1114 1.6 christos }
1115 1.6 christos }
1116 1.6 christos peer = findpeerbyassoc(current_association_ID);
1117 1.6 christos if (peer != NULL)
1118 1.6 christos unpeer(peer);
1119 1.6 christos }
1120