1    	/*
2    	 * Copyright (C) 2012-2025 Red Hat, Inc.  All rights reserved.
3    	 *
4    	 * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
5    	 *          Federico Simoncelli <fsimon@kronosnet.org>
6    	 *
7    	 * This software licensed under LGPL-2.0+
8    	 */
9    	
10   	#include "config.h"
11   	
12   	#include <errno.h>
13   	#include <netdb.h>
14   	#include <string.h>
15   	#include <pthread.h>
16   	
17   	#include "netutils.h"
18   	#include "internals.h"
19   	#include "logging.h"
20   	#include "links.h"
21   	#include "transports.h"
22   	#include "host.h"
23   	#include "threads_common.h"
24   	#include "links_acl.h"
25   	#include <ifaddrs.h>
26   	#include <net/if.h>
27   	
28   	static int find_ifindex(struct sockaddr_storage *addr)
29   	{
30   		struct ifaddrs *ifrs, *ifa;
31   	
32   		if (getifaddrs(&ifrs) == 0) {
33   			for (ifa = ifrs; ifa != NULL; ifa = ifa->ifa_next) {
34   				if (ifa->ifa_addr && cmpaddr(addr, (struct sockaddr_storage *)ifa->ifa_addr) == 0) {
35   					int ifindex = if_nametoindex(ifa->ifa_name);
36   					freeifaddrs(ifrs);
37   					return ifindex;
38   				}
39   			}
40   			freeifaddrs(ifrs);
41   		}
42   		return -1;
43   	}
44   	
45   	int _link_updown(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
46   			 unsigned int enabled, unsigned int connected, unsigned int lock_stats)
47   	{
48   		struct knet_host *host = knet_h->host_index[host_id];
49   		struct knet_link *link = &host->link[link_id];
50   		int savederrno = 0;
51   	
52   		if ((link->status.enabled == enabled) &&
53   		    (link->status.connected == connected))
54   			return 0;
55   	
56   		link->status.enabled = enabled;
57   		link->status.connected = connected;
58   	
59   		_host_dstcache_update_async(knet_h, knet_h->host_index[host_id]);
60   	
61   		if ((link->status.dynconnected) &&
62   		    (!link->status.connected)) {
63   			link->status.dynconnected = 0;
64   		}
65   	
66   		if (!connected) {
67   			transport_link_is_down(knet_h, link);
68   		} else {
69   			/* Reset MTU in case new link can't use full line MTU */
70   			log_info(knet_h, KNET_SUB_LINK, "Resetting MTU for link %u because host %u joined", link_id, host_id);
71   			force_pmtud_run(knet_h, KNET_SUB_LINK, 1, 1);
72   		}
73   	
74   		if (lock_stats) {
75   			savederrno = pthread_mutex_lock(&link->link_stats_mutex);
76   			if (savederrno) {
77   				log_err(knet_h, KNET_SUB_LINK, "Unable to get stats mutex lock for host %u link %u: %s",
78   					host_id, link_id, strerror(savederrno));
79   				errno = savederrno;
80   				return -1;
81   			}
82   		}
83   	
84   		if (connected) {
85   			time(&link->status.stats.last_up_times[link->status.stats.last_up_time_index]);
86   			link->status.stats.up_count++;
87   			if (++link->status.stats.last_up_time_index >= MAX_LINK_EVENTS) {
88   				link->status.stats.last_up_time_index = 0;
89   			}
90   			knet_h->knet_transport_fd_tracker[link->outsock].ifindex = find_ifindex(&link->src_addr);
91   		} else {
92   			time(&link->status.stats.last_down_times[link->status.stats.last_down_time_index]);
93   			link->status.stats.down_count++;
94   			if (++link->status.stats.last_down_time_index >= MAX_LINK_EVENTS) {
95   				link->status.stats.last_down_time_index = 0;
96   			}
97   		}
98   	
99   		if (lock_stats) {
100  			pthread_mutex_unlock(&link->link_stats_mutex);
101  		}
102  		return 0;
103  	}
104  	
105  	void _link_clear_stats(knet_handle_t knet_h)
106  	{
107  		struct knet_host *host;
108  		struct knet_link *link;
109  		uint32_t host_id;
110  		uint8_t link_id;
111  	
112  		for (host_id = 0; host_id < KNET_MAX_HOST; host_id++) {
113  			host = knet_h->host_index[host_id];
114  			if (!host) {
115  				continue;
116  			}
117  			for (link_id = 0; link_id < KNET_MAX_LINK; link_id++) {
118  				link = &host->link[link_id];
119  				memset(&link->status.stats, 0, sizeof(struct knet_link_stats));
120  			}
121  		}
122  	}
123  	
124  	int knet_link_set_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
125  				 uint8_t transport,
126  				 struct sockaddr_storage *src_addr,
127  				 struct sockaddr_storage *dst_addr,
128  				 uint64_t flags)
129  	{
130  		int savederrno = 0, err = 0, i, wipelink = 0, link_idx;
131  		struct knet_host *host, *tmp_host;
132  		struct knet_link *link = NULL;
133  	
134  		if (!_is_valid_handle(knet_h)) {
135  			return -1;
136  		}
137  	
138  		if (link_id >= KNET_MAX_LINK) {
139  			errno = EINVAL;
140  			return -1;
141  		}
142  	
143  		if (!src_addr) {
144  			errno = EINVAL;
145  			return -1;
146  		}
147  	
148  		if (dst_addr && (src_addr->ss_family != dst_addr->ss_family)) {
149  			log_err(knet_h, KNET_SUB_LINK, "Source address family does not match destination address family");
150  			errno = EINVAL;
151  			return -1;
152  		}
153  	
154  		if (transport >= KNET_MAX_TRANSPORTS) {
155  			errno = EINVAL;
156  			return -1;
157  		}
158  	
159  		savederrno = get_global_wrlock(knet_h);
160  		if (savederrno) {
161  			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
162  				strerror(savederrno));
163  			errno = savederrno;
164  			return -1;
165  		}
166  	
167  		if (transport == KNET_TRANSPORT_LOOPBACK && knet_h->host_id != host_id) {
168  			log_err(knet_h, KNET_SUB_LINK, "Cannot create loopback link to remote node");
169  			err = -1;
170  			savederrno = EINVAL;
171  			goto exit_unlock;
172  		}
173  	
174  		if (knet_h->host_id == host_id && knet_h->has_loop_link) {
175  			log_err(knet_h, KNET_SUB_LINK, "Cannot create more than 1 link when loopback is active");
176  			err = -1;
177  			savederrno = EINVAL;
178  			goto exit_unlock;
179  		}
180  	
181  		host = knet_h->host_index[host_id];
182  		if (!host) {
183  			err = -1;
184  			savederrno = EINVAL;
185  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
186  				host_id, strerror(savederrno));
187  			goto exit_unlock;
188  		}
189  	
190  		if (transport == KNET_TRANSPORT_LOOPBACK && knet_h->host_id == host_id) {
191  			for (i=0; i<KNET_MAX_LINK; i++) {
192  				if (host->link[i].configured) {
193  					log_err(knet_h, KNET_SUB_LINK, "Cannot add loopback link when other links are already configured.");
194  					err = -1;
195  					savederrno = EINVAL;
196  					goto exit_unlock;
197  				}
198  			}
199  		}
200  	
201  		link = &host->link[link_id];
202  	
203  		if (link->configured != 0) {
204  			err =-1;
205  			savederrno = EBUSY;
206  			log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently configured: %s",
207  				host_id, link_id, strerror(savederrno));
208  			goto exit_unlock;
209  		}
210  	
211  		if (link->status.enabled != 0) {
212  			err =-1;
213  			savederrno = EBUSY;
214  			log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s",
215  				host_id, link_id, strerror(savederrno));
216  			goto exit_unlock;
217  		}
218  	
219  		/*
220  		 * errors happening after this point should trigger
221  		 * a memset of the link
222  		 */
223  		wipelink = 1;
224  	
225  		copy_sockaddr(&link->src_addr, src_addr);
226  	
227  		err = knet_addrtostr(src_addr, sizeof(struct sockaddr_storage),
228  				     link->status.src_ipaddr, KNET_MAX_HOST_LEN,
229  				     link->status.src_port, KNET_MAX_PORT_LEN);
230  		if (err) {
231  			if (err == EAI_SYSTEM) {
232  				savederrno = errno;
233  				log_warn(knet_h, KNET_SUB_LINK,
234  					 "Unable to resolve host: %u link: %u source addr/port: %s",
235  					 host_id, link_id, strerror(savederrno));
236  			} else {
237  				savederrno = EINVAL;
238  				log_warn(knet_h, KNET_SUB_LINK,
239  					 "Unable to resolve host: %u link: %u source addr/port: %s",
240  					 host_id, link_id, gai_strerror(err));
241  			}
242  			err = -1;
243  			goto exit_unlock;
244  		}
245  	
246  		if (!dst_addr) {
247  			link->dynamic = KNET_LINK_DYNIP;
248  		} else {
249  	
250  			link->dynamic = KNET_LINK_STATIC;
251  	
252  			copy_sockaddr(&link->dst_addr, dst_addr);
253  			err = knet_addrtostr(dst_addr, sizeof(struct sockaddr_storage),
254  					     link->status.dst_ipaddr, KNET_MAX_HOST_LEN,
255  					     link->status.dst_port, KNET_MAX_PORT_LEN);
256  			if (err) {
257  				if (err == EAI_SYSTEM) {
258  					savederrno = errno;
259  					log_warn(knet_h, KNET_SUB_LINK,
260  						 "Unable to resolve host: %u link: %u destination addr/port: %s",
261  						 host_id, link_id, strerror(savederrno));
262  				} else {
263  					savederrno = EINVAL;
264  					log_warn(knet_h, KNET_SUB_LINK,
265  						 "Unable to resolve host: %u link: %u destination addr/port: %s",
266  						 host_id, link_id, gai_strerror(err));
267  				}
268  				err = -1;
269  				goto exit_unlock;
270  			}
271  		}
272  	
273  		link->pmtud_crypto_timeout_multiplier = KNET_LINK_PMTUD_CRYPTO_TIMEOUT_MULTIPLIER_MIN;
274  		link->pong_count = KNET_LINK_DEFAULT_PONG_COUNT;
275  		link->has_valid_mtu = 0;
276  		link->ping_interval = KNET_LINK_DEFAULT_PING_INTERVAL * 1000; /* microseconds */
277  		link->pong_timeout = KNET_LINK_DEFAULT_PING_TIMEOUT * 1000; /* microseconds */
278  		link->pong_timeout_backoff = KNET_LINK_PONG_TIMEOUT_BACKOFF;
279  		link->pong_timeout_adj = link->pong_timeout * link->pong_timeout_backoff; /* microseconds */
280  		link->latency_max_samples = KNET_LINK_DEFAULT_PING_PRECISION;
281  		link->latency_cur_samples = 0;
282  		link->flags = flags;
283  	
284  		/*
285  		 * check for DYNIP vs STATIC collisions.
286  		 * example: link0 is static, user attempts to configure link1 as dynamic with the same source
287  		 * address/port.
288  		 * This configuration is invalid and would cause ACL collisions.
289  		 */
(22) Event example_checked: Example 3: "knet_h->host_head" has its value checked in "tmp_host != NULL".
Also see events: [null_field][example_checked][example_checked][example_checked][example_checked][dereference]
290  		for (tmp_host = knet_h->host_head; tmp_host != NULL; tmp_host = tmp_host->next) {
291  			for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
292  				if (&tmp_host->link[link_idx] == link)
293  					continue;
294  	
295  				if ((!memcmp(&tmp_host->link[link_idx].src_addr, &link->src_addr, sizeof(struct sockaddr_storage))) &&
296  				    (tmp_host->link[link_idx].dynamic != link->dynamic)) {
297  					savederrno = EINVAL;
298  					err = -1;
299  					log_err(knet_h, KNET_SUB_LINK, "Failed to configure host %u link %u dyn %u. Conflicts with host %u link %u dyn %u: %s",
300  						host_id, link_id, link->dynamic, tmp_host->host_id, link_idx, tmp_host->link[link_idx].dynamic, strerror(savederrno));
301  					goto exit_unlock;
302  				}
303  			}
304  		}
305  	
306  		savederrno = pthread_mutex_init(&link->link_stats_mutex, NULL);
307  		if (savederrno) {
308  			log_err(knet_h, KNET_SUB_LINK, "Unable to initialize link stats mutex: %s", strerror(savederrno));
309  			err = -1;
310  			goto exit_unlock;
311  		}
312  	
313  		if (transport_link_set_config(knet_h, link, transport) < 0) {
314  			savederrno = errno;
315  			err = -1;
316  			goto exit_transport_err;
317  		}
318  	
319  		/*
320  		 * we can only configure default access lists if we know both endpoints
321  		 * and the protocol uses GENERIC_ACL, otherwise the protocol has
322  		 * to setup their own access lists above in transport_link_set_config.
323  		 */
324  		if ((transport_get_acl_type(knet_h, transport) == USE_GENERIC_ACL) &&
325  		    (link->dynamic == KNET_LINK_STATIC)) {
326  			log_debug(knet_h, KNET_SUB_LINK, "Configuring default access lists for host: %u link: %u socket: %d",
327  				  host_id, link_id, link->outsock);
328  			if ((check_add(knet_h, link, -1,
329  				       &link->dst_addr, &link->dst_addr,
330  				       CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != EEXIST)) {
331  				log_warn(knet_h, KNET_SUB_LINK, "Failed to configure default access lists for host: %u link: %u", host_id, link_id);
332  				savederrno = errno;
333  				err = -1;
334  				goto exit_acl_error;
335  			}
336  		}
337  	
338  		/*
339  		 * no errors should happen after link is configured
340  		 */
341  		link->configured = 1;
342  		log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is configured",
343  			  host_id, link_id);
344  	
345  		if (transport == KNET_TRANSPORT_LOOPBACK) {
346  			knet_h->has_loop_link = 1;
347  			knet_h->loop_link = link_id;
348  			host->status.reachable = 1;
349  			link->status.mtu = KNET_PMTUD_SIZE_V6;
350  		} else {
351  			/*
352  			 * calculate the minimum MTU that is safe to use,
353  			 * based on RFCs and that each network device should
354  			 * be able to support without any troubles
355  			 */
356  			if (link->dynamic == KNET_LINK_STATIC) {
357  				/*
358  				 * with static link we can be more precise than using
359  				 * the generic calc_min_mtu()
360  				 */
361  				switch (link->dst_addr.ss_family) {
362  					case AF_INET6:
363  						link->status.mtu =  calc_max_data_outlen(knet_h, KNET_PMTUD_MIN_MTU_V6 - (KNET_PMTUD_OVERHEAD_V6 + link->proto_overhead));
364  						break;
365  					case AF_INET:
366  						link->status.mtu =  calc_max_data_outlen(knet_h, KNET_PMTUD_MIN_MTU_V4 - (KNET_PMTUD_OVERHEAD_V4 + link->proto_overhead));
367  						break;
368  				}
369  			} else {
370  				/*
371  				 * for dynamic links we start with the minimum MTU
372  				 * possible and PMTUd will kick in immediately
373  				 * after connection status is 1
374  				 */
375  				link->status.mtu =  calc_min_mtu(knet_h);
376  			}
377  			link->has_valid_mtu = 1;
378  		}
379  	
380  	exit_acl_error:
381  		/*
382  		 * if creating access lists has error, we only need to clean
383  		 * the transport and the stuff below.
384  		 */
385  		if (err < 0) {
386  			if ((transport_link_clear_config(knet_h, link) < 0)  &&
387  			    (errno != EBUSY)) {
388  				log_warn(knet_h, KNET_SUB_LINK, "Failed to deconfigure transport for host %u link %u: %s", host_id, link_id, strerror(errno));
389  			}
390  		}
391  	exit_transport_err:
392  		/*
393  		 * if transport has errors, transport will clean after itself
394  		 * and we only need to clean the mutex
395  		 */
396  		if (err < 0) {
397  			pthread_mutex_destroy(&link->link_stats_mutex);
398  		}
399  	exit_unlock:
400  		/*
401  		 * re-init the link on error
402  		 */
403  		if ((err < 0) && (wipelink)) {
404  			memset(link, 0, sizeof(struct knet_link));
405  			link->link_id = link_id;
406  		}
407  		pthread_rwlock_unlock(&knet_h->global_rwlock);
408  		errno = err ? savederrno : 0;
409  		return err;
410  	}
411  	
412  	int knet_link_get_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
413  				 uint8_t *transport,
414  				 struct sockaddr_storage *src_addr,
415  				 struct sockaddr_storage *dst_addr,
416  				 uint8_t *dynamic,
417  				 uint64_t *flags)
418  	{
419  		int savederrno = 0, err = 0;
420  		struct knet_host *host;
421  		struct knet_link *link;
422  	
423  		if (!_is_valid_handle(knet_h)) {
424  			return -1;
425  		}
426  	
427  		if (link_id >= KNET_MAX_LINK) {
428  			errno = EINVAL;
429  			return -1;
430  		}
431  	
432  		if (!src_addr) {
433  			errno = EINVAL;
434  			return -1;
435  		}
436  	
437  		if (!dynamic) {
438  			errno = EINVAL;
439  			return -1;
440  		}
441  	
442  		if (!transport) {
443  			errno = EINVAL;
444  			return -1;
445  		}
446  	
447  		if (!flags) {
448  			errno = EINVAL;
449  			return -1;
450  		}
451  	
452  		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
453  		if (savederrno) {
454  			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
455  				strerror(savederrno));
456  			errno = savederrno;
457  			return -1;
458  		}
459  	
460  		host = knet_h->host_index[host_id];
461  		if (!host) {
462  			err = -1;
463  			savederrno = EINVAL;
464  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
465  				host_id, strerror(savederrno));
466  			goto exit_unlock;
467  		}
468  	
469  		link = &host->link[link_id];
470  	
471  		if (!link->configured) {
472  			err = -1;
473  			savederrno = EINVAL;
474  			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
475  				host_id, link_id, strerror(savederrno));
476  			goto exit_unlock;
477  		}
478  	
479  		if ((link->dynamic == KNET_LINK_STATIC) && (!dst_addr)) {
480  			savederrno = EINVAL;
481  			err = -1;
482  			goto exit_unlock;
483  		}
484  	
485  		memmove(src_addr, &link->src_addr, sizeof(struct sockaddr_storage));
486  	
487  		*transport = link->transport;
488  		*flags = link->flags;
489  	
490  		if (link->dynamic == KNET_LINK_STATIC) {
491  			*dynamic = 0;
492  			memmove(dst_addr, &link->dst_addr, sizeof(struct sockaddr_storage));
493  		} else {
494  			*dynamic = 1;
495  		}
496  	
497  	exit_unlock:
498  		pthread_rwlock_unlock(&knet_h->global_rwlock);
499  		errno = err ? savederrno : 0;
500  		return err;
501  	}
502  	
503  	int knet_link_clear_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id)
504  	{
505  		int savederrno = 0, err = 0;
506  		struct knet_host *host;
507  		struct knet_link *link;
508  		int sock;
509  		uint8_t transport;
510  	
511  		if (!_is_valid_handle(knet_h)) {
512  			return -1;
513  		}
514  	
515  		if (link_id >= KNET_MAX_LINK) {
516  			errno = EINVAL;
517  			return -1;
518  		}
519  	
520  		savederrno = get_global_wrlock(knet_h);
521  		if (savederrno) {
522  			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
523  				strerror(savederrno));
524  			errno = savederrno;
525  			return -1;
526  		}
527  	
528  		host = knet_h->host_index[host_id];
529  		if (!host) {
530  			err = -1;
531  			savederrno = EINVAL;
532  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
533  				host_id, strerror(savederrno));
534  			goto exit_unlock;
535  		}
536  	
537  		link = &host->link[link_id];
538  	
539  		if (link->configured != 1) {
540  			err = -1;
541  			savederrno = EINVAL;
542  			log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is not configured: %s",
543  				host_id, link_id, strerror(savederrno));
544  			goto exit_unlock;
545  		}
546  	
547  		if (link->status.enabled != 0) {
548  			err = -1;
549  			savederrno = EBUSY;
550  			log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s",
551  				host_id, link_id, strerror(savederrno));
552  			goto exit_unlock;
553  		}
554  	
555  		/*
556  		 * remove well known access lists here.
557  		 * After the transport has done clearing the config,
558  		 * then we can remove any leftover access lists if the link
559  		 * is no longer in use.
560  		 */
561  		if ((transport_get_acl_type(knet_h, link->transport) == USE_GENERIC_ACL) &&
562  		    (link->dynamic == KNET_LINK_STATIC)) {
563  			if ((check_rm(knet_h, link,
564  				      &link->dst_addr, &link->dst_addr,
565  				      CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != ENOENT)) {
566  				err = -1;
567  				savederrno = errno;
568  				log_err(knet_h, KNET_SUB_LINK, "Host %u link %u: unable to remove default access list",
569  					host_id, link_id);
570  				goto exit_unlock;
571  			}
572  		}
573  	
574  		/*
575  		 * cache it for later as we don't know if the transport
576  		 * will clear link info during clear_config.
577  		 */
578  		sock = link->outsock;
579  		transport = link->transport;
580  	
581  		if ((transport_link_clear_config(knet_h, link) < 0)  &&
582  		    (errno != EBUSY)) {
583  			savederrno = errno;
584  			err = -1;
585  			goto exit_unlock;
586  		}
587  	
588  		/*
589  		 * remove any other access lists when the socket is no
590  		 * longer in use by the transport.
591  		 */
592  		if ((transport_get_acl_type(knet_h, transport) == USE_GENERIC_ACL) &&
593  		    (knet_h->knet_transport_fd_tracker[sock].transport == KNET_MAX_TRANSPORTS)) {
594  			check_rmall(knet_h, link);
595  		}
596  	
597  		pthread_mutex_destroy(&link->link_stats_mutex);
598  	
599  		memset(link, 0, sizeof(struct knet_link));
600  		link->link_id = link_id;
601  	
602  		if (knet_h->has_loop_link && host_id == knet_h->host_id && link_id == knet_h->loop_link) {
603  			knet_h->has_loop_link = 0;
604  			if (host->active_link_entries == 0) {
605  				host->status.reachable = 0;
606  			}
607  		}
608  	
609  		log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u config has been wiped",
610  			  host_id, link_id);
611  	
612  	exit_unlock:
613  		pthread_rwlock_unlock(&knet_h->global_rwlock);
614  		errno = err ? savederrno : 0;
615  		return err;
616  	}
617  	
618  	int knet_link_set_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
619  				 unsigned int enabled)
620  	{
621  		int savederrno = 0, err = 0;
622  		struct knet_host *host;
623  		struct knet_link *link;
624  	
625  		if (!_is_valid_handle(knet_h)) {
626  			return -1;
627  		}
628  	
629  		if (link_id >= KNET_MAX_LINK) {
630  			errno = EINVAL;
631  			return -1;
632  		}
633  	
634  		if (enabled > 1) {
635  			errno = EINVAL;
636  			return -1;
637  		}
638  	
639  		savederrno = get_global_wrlock(knet_h);
640  		if (savederrno) {
641  			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
642  				strerror(savederrno));
643  			errno = savederrno;
644  			return -1;
645  		}
646  	
647  		host = knet_h->host_index[host_id];
648  		if (!host) {
649  			err = -1;
650  			savederrno = EINVAL;
651  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
652  				host_id, strerror(savederrno));
653  			goto exit_unlock;
654  		}
655  	
656  		link = &host->link[link_id];
657  	
658  		if (!link->configured) {
659  			err = -1;
660  			savederrno = EINVAL;
661  			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
662  				host_id, link_id, strerror(savederrno));
663  			goto exit_unlock;
664  		}
665  	
666  		if (link->status.enabled == enabled) {
667  			err = 0;
668  			goto exit_unlock;
669  		}
670  	
671  		err = _link_updown(knet_h, host_id, link_id, enabled, link->status.connected, 0);
672  		savederrno = errno;
673  	
674  		if (enabled) {
675  			goto exit_unlock;
676  		}
677  	
678  		log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is disabled",
679  			  host_id, link_id);
680  	
681  	exit_unlock:
682  		pthread_rwlock_unlock(&knet_h->global_rwlock);
683  		errno = err ? savederrno : 0;
684  		return err;
685  	}
686  	
687  	int knet_link_get_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
688  				 unsigned int *enabled)
689  	{
690  		int savederrno = 0, err = 0;
691  		struct knet_host *host;
692  		struct knet_link *link;
693  	
694  		if (!_is_valid_handle(knet_h)) {
695  			return -1;
696  		}
697  	
698  		if (link_id >= KNET_MAX_LINK) {
699  			errno = EINVAL;
700  			return -1;
701  		}
702  	
703  		if (!enabled) {
704  			errno = EINVAL;
705  			return -1;
706  		}
707  	
708  		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
709  		if (savederrno) {
710  			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
711  				strerror(savederrno));
712  			errno = savederrno;
713  			return -1;
714  		}
715  	
716  		host = knet_h->host_index[host_id];
717  		if (!host) {
718  			err = -1;
719  			savederrno = EINVAL;
720  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
721  				host_id, strerror(savederrno));
722  			goto exit_unlock;
723  		}
724  	
725  		link = &host->link[link_id];
726  	
727  		if (!link->configured) {
728  			err = -1;
729  			savederrno = EINVAL;
730  			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
731  				host_id, link_id, strerror(savederrno));
732  			goto exit_unlock;
733  		}
734  	
735  		*enabled = link->status.enabled;
736  	
737  	exit_unlock:
738  		pthread_rwlock_unlock(&knet_h->global_rwlock);
739  		errno = err ? savederrno : 0;
740  		return err;
741  	}
742  	
743  	int knet_link_set_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
744  				     uint8_t pong_count)
745  	{
746  		int savederrno = 0, err = 0;
747  		struct knet_host *host;
748  		struct knet_link *link;
749  	
750  		if (!_is_valid_handle(knet_h)) {
751  			return -1;
752  		}
753  	
754  		if (link_id >= KNET_MAX_LINK) {
755  			errno = EINVAL;
756  			return -1;
757  		}
758  	
759  		if (pong_count < 1) {
760  			errno = EINVAL;
761  			return -1;
762  		}
763  	
764  		savederrno = get_global_wrlock(knet_h);
765  		if (savederrno) {
766  			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
767  				strerror(savederrno));
768  			errno = savederrno;
769  			return -1;
770  		}
771  	
772  		host = knet_h->host_index[host_id];
773  		if (!host) {
774  			err = -1;
775  			savederrno = EINVAL;
776  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
777  				host_id, strerror(savederrno));
778  			goto exit_unlock;
779  		}
780  	
781  		link = &host->link[link_id];
782  	
783  		if (!link->configured) {
784  			err = -1;
785  			savederrno = EINVAL;
786  			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
787  				host_id, link_id, strerror(savederrno));
788  			goto exit_unlock;
789  		}
790  	
791  		link->pong_count = pong_count;
792  	
793  		log_debug(knet_h, KNET_SUB_LINK,
794  			  "host: %u link: %u pong count update: %u",
795  			  host_id, link_id, link->pong_count);
796  	
797  	exit_unlock:
798  		pthread_rwlock_unlock(&knet_h->global_rwlock);
799  		errno = err ? savederrno : 0;
800  		return err;
801  	}
802  	
803  	int knet_link_get_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
804  				     uint8_t *pong_count)
805  	{
806  		int savederrno = 0, err = 0;
807  		struct knet_host *host;
808  		struct knet_link *link;
809  	
810  		if (!_is_valid_handle(knet_h)) {
811  			return -1;
812  		}
813  	
814  		if (link_id >= KNET_MAX_LINK) {
815  			errno = EINVAL;
816  			return -1;
817  		}
818  	
819  		if (!pong_count) {
820  			errno = EINVAL;
821  			return -1;
822  		}
823  	
824  		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
825  		if (savederrno) {
826  			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
827  				strerror(savederrno));
828  			errno = savederrno;
829  			return -1;
830  		}
831  	
832  		host = knet_h->host_index[host_id];
833  		if (!host) {
834  			err = -1;
835  			savederrno = EINVAL;
836  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
837  				host_id, strerror(savederrno));
838  			goto exit_unlock;
839  		}
840  	
841  		link = &host->link[link_id];
842  	
843  		if (!link->configured) {
844  			err = -1;
845  			savederrno = EINVAL;
846  			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
847  				host_id, link_id, strerror(savederrno));
848  			goto exit_unlock;
849  		}
850  	
851  		*pong_count = link->pong_count;
852  	
853  	exit_unlock:
854  		pthread_rwlock_unlock(&knet_h->global_rwlock);
855  		errno = err ? savederrno : 0;
856  		return err;
857  	}
858  	
859  	int knet_link_set_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
860  				      time_t interval, time_t timeout, unsigned int precision)
861  	{
862  		int savederrno = 0, err = 0;
863  		struct knet_host *host;
864  		struct knet_link *link;
865  		unsigned long long ping_interval, pong_timeout;
866  	
867  		if (!_is_valid_handle(knet_h)) {
868  			return -1;
869  		}
870  	
871  		if (link_id >= KNET_MAX_LINK) {
872  			errno = EINVAL;
873  			return -1;
874  		}
875  	
876  		if (interval <= 0) {
877  			errno = EINVAL;
878  			return -1;
879  		}
880  	
881  		if (timeout <= 0) {
882  			errno = ENOSYS;
883  			return -1;
884  		}
885  	
886  		if (!precision) {
887  			errno = EINVAL;
888  			return -1;
889  		}
890  	
891  		savederrno = get_global_wrlock(knet_h);
892  		if (savederrno) {
893  			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
894  				strerror(savederrno));
895  			errno = savederrno;
896  			return -1;
897  		}
898  	
899  		host = knet_h->host_index[host_id];
900  		if (!host) {
901  			err = -1;
902  			savederrno = EINVAL;
903  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
904  				host_id, strerror(savederrno));
905  			goto exit_unlock;
906  		}
907  	
908  		link = &host->link[link_id];
909  	
910  		if (!link->configured) {
911  			err = -1;
912  			savederrno = EINVAL;
913  			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
914  				host_id, link_id, strerror(savederrno));
915  			goto exit_unlock;
916  		}
917  	
918  		ping_interval = (unsigned long long)interval * 1000; /* microseconds */
919  		if (ping_interval < KNET_THREADS_TIMERES) {
920  			log_warn(knet_h, KNET_SUB_LINK,
921  				 "host: %u link: %u interval: %llu too small (%s). interval lower than thread_timer_res (%u ms) has no effect",
922  				 host_id, link_id, (unsigned long long)interval, strerror(savederrno), (KNET_THREADS_TIMERES / 1000));
923  		}
924  	
925  		pong_timeout = (unsigned long long)timeout * 1000; /* microseconds */
926  		if (pong_timeout < KNET_THREADS_TIMERES) {
927  			err = -1;
928  			savederrno = EINVAL;
929  			log_err(knet_h, KNET_SUB_LINK,
930  				"host: %u link: %u pong timeout: %llu too small (%s). timeout cannot be less than thread_timer_res (%u ms)",
931  				host_id, link_id, (unsigned long long)timeout, strerror(savederrno), (KNET_THREADS_TIMERES / 1000));
932  			goto exit_unlock;
933  		}
934  	
935  		link->ping_interval = ping_interval;
936  		link->pong_timeout = pong_timeout;
937  		link->latency_max_samples = precision;
938  	
939  		log_debug(knet_h, KNET_SUB_LINK,
940  			  "host: %u link: %u timeout update - interval: %llu timeout: %llu precision: %u",
941  			  host_id, link_id, link->ping_interval, link->pong_timeout, precision);
942  	
943  	exit_unlock:
944  		pthread_rwlock_unlock(&knet_h->global_rwlock);
945  		errno = err ? savederrno : 0;
946  		return err;
947  	}
948  	
949  	int knet_link_get_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
950  				      time_t *interval, time_t *timeout, unsigned int *precision)
951  	{
952  		int savederrno = 0, err = 0;
953  		struct knet_host *host;
954  		struct knet_link *link;
955  	
956  		if (!_is_valid_handle(knet_h)) {
957  			return -1;
958  		}
959  	
960  		if (link_id >= KNET_MAX_LINK) {
961  			errno = EINVAL;
962  			return -1;
963  		}
964  	
965  		if (!interval) {
966  			errno = EINVAL;
967  			return -1;
968  		}
969  	
970  		if (!timeout) {
971  			errno = EINVAL;
972  			return -1;
973  		}
974  	
975  		if (!precision) {
976  			errno = EINVAL;
977  			return -1;
978  		}
979  	
980  		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
981  		if (savederrno) {
982  			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
983  				strerror(savederrno));
984  			errno = savederrno;
985  			return -1;
986  		}
987  	
988  		host = knet_h->host_index[host_id];
989  		if (!host) {
990  			err = -1;
991  			savederrno = EINVAL;
992  			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
993  				host_id, strerror(savederrno));
994  			goto exit_unlock;
995  		}
996  	
997  		link = &host->link[link_id];
998  	
999  		if (!link->configured) {
1000 			err = -1;
1001 			savederrno = EINVAL;
1002 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1003 				host_id, link_id, strerror(savederrno));
1004 			goto exit_unlock;
1005 		}
1006 	
1007 		*interval = link->ping_interval / 1000; /* microseconds */
1008 		*timeout = link->pong_timeout / 1000;
1009 		*precision = link->latency_max_samples;
1010 	
1011 	exit_unlock:
1012 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1013 		errno = err ? savederrno : 0;
1014 		return err;
1015 	}
1016 	
1017 	int knet_link_set_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1018 				   uint8_t priority)
1019 	{
1020 		int savederrno = 0, err = 0;
1021 		struct knet_host *host;
1022 		struct knet_link *link;
1023 		uint8_t old_priority;
1024 	
1025 		if (!_is_valid_handle(knet_h)) {
1026 			return -1;
1027 		}
1028 	
1029 		if (link_id >= KNET_MAX_LINK) {
1030 			errno = EINVAL;
1031 			return -1;
1032 		}
1033 	
1034 		savederrno = get_global_wrlock(knet_h);
1035 		if (savederrno) {
1036 			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1037 				strerror(savederrno));
1038 			errno = savederrno;
1039 			return -1;
1040 		}
1041 	
1042 		host = knet_h->host_index[host_id];
1043 		if (!host) {
1044 			err = -1;
1045 			savederrno = EINVAL;
1046 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1047 				host_id, strerror(savederrno));
1048 			goto exit_unlock;
1049 		}
1050 	
1051 		link = &host->link[link_id];
1052 	
1053 		if (!link->configured) {
1054 			err = -1;
1055 			savederrno = EINVAL;
1056 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1057 				host_id, link_id, strerror(savederrno));
1058 			goto exit_unlock;
1059 		}
1060 	
1061 		old_priority = link->priority;
1062 	
1063 		if (link->priority == priority) {
1064 			err = 0;
1065 			goto exit_unlock;
1066 		}
1067 	
1068 		link->priority = priority;
1069 	
1070 		if (_host_dstcache_update_sync(knet_h, host)) {
1071 			savederrno = errno;
1072 			log_debug(knet_h, KNET_SUB_LINK,
1073 				  "Unable to update link priority (host: %u link: %u priority: %u): %s",
1074 				  host_id, link_id, link->priority, strerror(savederrno));
1075 			link->priority = old_priority;
1076 			err = -1;
1077 			goto exit_unlock;
1078 		}
1079 	
1080 		log_debug(knet_h, KNET_SUB_LINK,
1081 			  "host: %u link: %u priority set to: %u",
1082 			  host_id, link_id, link->priority);
1083 	
1084 	exit_unlock:
1085 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1086 		errno = err ? savederrno : 0;
1087 		return err;
1088 	}
1089 	
1090 	int knet_link_get_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1091 				   uint8_t *priority)
1092 	{
1093 		int savederrno = 0, err = 0;
1094 		struct knet_host *host;
1095 		struct knet_link *link;
1096 	
1097 		if (!_is_valid_handle(knet_h)) {
1098 			return -1;
1099 		}
1100 	
1101 		if (link_id >= KNET_MAX_LINK) {
1102 			errno = EINVAL;
1103 			return -1;
1104 		}
1105 	
1106 		if (!priority) {
1107 			errno = EINVAL;
1108 			return -1;
1109 		}
1110 	
1111 		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
1112 		if (savederrno) {
1113 			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
1114 				strerror(savederrno));
1115 			errno = savederrno;
1116 			return -1;
1117 		}
1118 	
1119 		host = knet_h->host_index[host_id];
1120 		if (!host) {
1121 			err = -1;
1122 			savederrno = EINVAL;
1123 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1124 				host_id, strerror(savederrno));
1125 			goto exit_unlock;
1126 		}
1127 	
1128 		link = &host->link[link_id];
1129 	
1130 		if (!link->configured) {
1131 			err = -1;
1132 			savederrno = EINVAL;
1133 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1134 				host_id, link_id, strerror(savederrno));
1135 			goto exit_unlock;
1136 		}
1137 	
1138 		*priority = link->priority;
1139 	
1140 	exit_unlock:
1141 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1142 		errno = err ? savederrno : 0;
1143 		return err;
1144 	}
1145 	
1146 	int knet_link_get_link_list(knet_handle_t knet_h, knet_node_id_t host_id,
1147 				    uint8_t *link_ids, size_t *link_ids_entries)
1148 	{
1149 		int savederrno = 0, err = 0, i, count = 0;
1150 		struct knet_host *host;
1151 		struct knet_link *link;
1152 	
1153 		if (!_is_valid_handle(knet_h)) {
1154 			return -1;
1155 		}
1156 	
1157 		if (!link_ids) {
1158 			errno = EINVAL;
1159 			return -1;
1160 		}
1161 	
1162 		if (!link_ids_entries) {
1163 			errno = EINVAL;
1164 			return -1;
1165 		}
1166 	
1167 		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
1168 		if (savederrno) {
1169 			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
1170 				strerror(savederrno));
1171 			errno = savederrno;
1172 			return -1;
1173 		}
1174 	
1175 		host = knet_h->host_index[host_id];
1176 		if (!host) {
1177 			err = -1;
1178 			savederrno = EINVAL;
1179 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1180 				host_id, strerror(savederrno));
1181 			goto exit_unlock;
1182 		}
1183 	
1184 		for (i = 0; i < KNET_MAX_LINK; i++) {
1185 			link = &host->link[i];
1186 			if (!link->configured) {
1187 				continue;
1188 			}
1189 			link_ids[count] = i;
1190 			count++;
1191 		}
1192 	
1193 		*link_ids_entries = count;
1194 	
1195 	exit_unlock:
1196 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1197 		errno = err ? savederrno : 0;
1198 		return err;
1199 	}
1200 	
1201 	int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1202 				 struct knet_link_status *status, size_t struct_size)
1203 	{
1204 		int savederrno = 0, err = 0;
1205 		struct knet_host *host;
1206 		struct knet_link *link;
1207 	
1208 		if (!_is_valid_handle(knet_h)) {
1209 			return -1;
1210 		}
1211 	
1212 		if (link_id >= KNET_MAX_LINK) {
1213 			errno = EINVAL;
1214 			return -1;
1215 		}
1216 	
1217 		if (!status) {
1218 			errno = EINVAL;
1219 			return -1;
1220 		}
1221 	
1222 		savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
1223 		if (savederrno) {
1224 			log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
1225 				strerror(savederrno));
1226 			errno = savederrno;
1227 			return -1;
1228 		}
1229 	
1230 		host = knet_h->host_index[host_id];
1231 		if (!host) {
1232 			err = -1;
1233 			savederrno = EINVAL;
1234 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1235 				host_id, strerror(savederrno));
1236 			goto exit_unlock;
1237 		}
1238 	
1239 		link = &host->link[link_id];
1240 	
1241 		if (!link->configured) {
1242 			err = -1;
1243 			savederrno = EINVAL;
1244 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1245 				host_id, link_id, strerror(savederrno));
1246 			goto exit_unlock;
1247 		}
1248 	
1249 		savederrno = pthread_mutex_lock(&link->link_stats_mutex);
1250 		if (savederrno) {
1251 			log_err(knet_h, KNET_SUB_LINK, "Unable to get stats mutex lock for host %u link %u: %s",
1252 				host_id, link_id, strerror(savederrno));
1253 			err = -1;
1254 			goto exit_unlock;
1255 		}
1256 	
1257 		memmove(status, &link->status, struct_size);
1258 	
1259 		pthread_mutex_unlock(&link->link_stats_mutex);
1260 	
1261 		/* Calculate totals - no point in doing this on-the-fly */
1262 		status->stats.rx_total_packets =
1263 			status->stats.rx_data_packets +
1264 			status->stats.rx_ping_packets +
1265 			status->stats.rx_pong_packets +
1266 			status->stats.rx_pmtu_packets;
1267 		status->stats.tx_total_packets =
1268 			status->stats.tx_data_packets +
1269 			status->stats.tx_ping_packets +
1270 			status->stats.tx_pong_packets +
1271 			status->stats.tx_pmtu_packets;
1272 		status->stats.rx_total_bytes =
1273 			status->stats.rx_data_bytes +
1274 			status->stats.rx_ping_bytes +
1275 			status->stats.rx_pong_bytes +
1276 			status->stats.rx_pmtu_bytes;
1277 		status->stats.tx_total_bytes =
1278 			status->stats.tx_data_bytes +
1279 			status->stats.tx_ping_bytes +
1280 			status->stats.tx_pong_bytes +
1281 			status->stats.tx_pmtu_bytes;
1282 		status->stats.tx_total_errors =
1283 			status->stats.tx_data_errors +
1284 			status->stats.tx_ping_errors +
1285 			status->stats.tx_pong_errors +
1286 			status->stats.tx_pmtu_errors;
1287 		status->stats.tx_total_retries =
1288 			status->stats.tx_data_retries +
1289 			status->stats.tx_ping_retries +
1290 			status->stats.tx_pong_retries +
1291 			status->stats.tx_pmtu_retries;
1292 	
1293 		/* Tell the caller our full size in case they have an old version */
1294 		status->size = sizeof(struct knet_link_status);
1295 	
1296 	exit_unlock:
1297 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1298 		errno = err ? savederrno : 0;
1299 		return err;
1300 	}
1301 	
1302 	int knet_link_insert_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1303 				 int index,
1304 				 struct sockaddr_storage *ss1,
1305 				 struct sockaddr_storage *ss2,
1306 				 check_type_t type, check_acceptreject_t acceptreject)
1307 	{
1308 		int savederrno = 0, err = 0;
1309 		struct knet_host *host;
1310 		struct knet_link *link;
1311 	
1312 		if (!_is_valid_handle(knet_h)) {
1313 			return -1;
1314 		}
1315 	
1316 		if (!ss1) {
1317 			errno = EINVAL;
1318 			return -1;
1319 		}
1320 	
1321 		if ((type != CHECK_TYPE_ADDRESS) &&
1322 		    (type != CHECK_TYPE_MASK) &&
1323 		    (type != CHECK_TYPE_RANGE)) {
1324 			errno = EINVAL;
1325 			return -1;
1326 		}
1327 	
1328 		if ((acceptreject != CHECK_ACCEPT) &&
1329 		    (acceptreject != CHECK_REJECT)) {
1330 			errno = EINVAL;
1331 			return -1;
1332 		}
1333 	
1334 		if ((type != CHECK_TYPE_ADDRESS) && (!ss2)) {
1335 			errno = EINVAL;
1336 			return -1;
1337 		}
1338 	
1339 		if ((type == CHECK_TYPE_RANGE) &&
1340 		    (ss1->ss_family != ss2->ss_family)) {
1341 				errno = EINVAL;
1342 				return -1;
1343 		}
1344 	
1345 		if (link_id >= KNET_MAX_LINK) {
1346 			errno = EINVAL;
1347 			return -1;
1348 		}
1349 	
1350 		savederrno = get_global_wrlock(knet_h);
1351 		if (savederrno) {
1352 			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1353 				strerror(savederrno));
1354 			errno = savederrno;
1355 			return -1;
1356 		}
1357 	
1358 		host = knet_h->host_index[host_id];
1359 		if (!host) {
1360 			err = -1;
1361 			savederrno = EINVAL;
1362 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1363 				host_id, strerror(savederrno));
1364 			goto exit_unlock;
1365 		}
1366 	
1367 		link = &host->link[link_id];
1368 	
1369 		if (!link->configured) {
1370 			err = -1;
1371 			savederrno = EINVAL;
1372 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1373 				host_id, link_id, strerror(savederrno));
1374 			goto exit_unlock;
1375 		}
1376 	
1377 		if (link->dynamic != KNET_LINK_DYNIP) {
1378 			err = -1;
1379 			savederrno = EINVAL;
1380 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is a point to point connection: %s",
1381 				host_id, link_id, strerror(savederrno));
1382 			goto exit_unlock;
1383 		}
1384 	
1385 		err = check_add(knet_h, link, index,
1386 				ss1, ss2, type, acceptreject);
1387 		savederrno = errno;
1388 	
1389 	exit_unlock:
1390 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1391 	
1392 		errno = savederrno;
1393 		return err;
1394 	}
1395 	
1396 	int knet_link_add_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1397 			      struct sockaddr_storage *ss1,
1398 			      struct sockaddr_storage *ss2,
1399 			      check_type_t type, check_acceptreject_t acceptreject)
1400 	{
1401 		return knet_link_insert_acl(knet_h, host_id, link_id, -1, ss1, ss2, type, acceptreject);
1402 	}
1403 	
1404 	
1405 	int knet_link_rm_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
1406 			     struct sockaddr_storage *ss1,
1407 			     struct sockaddr_storage *ss2,
1408 			     check_type_t type, check_acceptreject_t acceptreject)
1409 	{
1410 		int savederrno = 0, err = 0;
1411 		struct knet_host *host;
1412 		struct knet_link *link;
1413 	
1414 		if (!_is_valid_handle(knet_h)) {
1415 			return -1;
1416 		}
1417 	
1418 		if (!ss1) {
1419 			errno = EINVAL;
1420 			return -1;
1421 		}
1422 	
1423 		if ((type != CHECK_TYPE_ADDRESS) &&
1424 		    (type != CHECK_TYPE_MASK) &&
1425 		    (type != CHECK_TYPE_RANGE)) {
1426 			errno = EINVAL;
1427 			return -1;
1428 		}
1429 	
1430 		if ((acceptreject != CHECK_ACCEPT) &&
1431 		    (acceptreject != CHECK_REJECT)) {
1432 			errno = EINVAL;
1433 			return -1;
1434 		}
1435 	
1436 		if ((type != CHECK_TYPE_ADDRESS) && (!ss2)) {
1437 			errno = EINVAL;
1438 			return -1;
1439 		}
1440 	
1441 		if ((type == CHECK_TYPE_RANGE) &&
1442 		    (ss1->ss_family != ss2->ss_family)) {
1443 				errno = EINVAL;
1444 				return -1;
1445 		}
1446 	
1447 		if (link_id >= KNET_MAX_LINK) {
1448 			errno = EINVAL;
1449 			return -1;
1450 		}
1451 	
1452 		savederrno = get_global_wrlock(knet_h);
1453 		if (savederrno) {
1454 			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1455 				strerror(savederrno));
1456 			errno = savederrno;
1457 			return -1;
1458 		}
1459 	
1460 		host = knet_h->host_index[host_id];
1461 		if (!host) {
1462 			err = -1;
1463 			savederrno = EINVAL;
1464 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1465 				host_id, strerror(savederrno));
1466 			goto exit_unlock;
1467 		}
1468 	
1469 		link = &host->link[link_id];
1470 	
1471 		if (!link->configured) {
1472 			err = -1;
1473 			savederrno = EINVAL;
1474 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1475 				host_id, link_id, strerror(savederrno));
1476 			goto exit_unlock;
1477 		}
1478 	
1479 		if (link->dynamic != KNET_LINK_DYNIP) {
1480 			err = -1;
1481 			savederrno = EINVAL;
1482 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is a point to point connection: %s",
1483 				host_id, link_id, strerror(savederrno));
1484 			goto exit_unlock;
1485 		}
1486 	
1487 		err = check_rm(knet_h, link,
1488 			       ss1, ss2, type, acceptreject);
1489 		savederrno = errno;
1490 	
1491 	exit_unlock:
1492 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1493 	
1494 		errno = savederrno;
1495 		return err;
1496 	}
1497 	
1498 	int knet_link_clear_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id)
1499 	{
1500 		int savederrno = 0, err = 0;
1501 		struct knet_host *host;
1502 		struct knet_link *link;
1503 	
1504 		if (!_is_valid_handle(knet_h)) {
1505 			return -1;
1506 		}
1507 	
1508 		if (link_id >= KNET_MAX_LINK) {
1509 			errno = EINVAL;
1510 			return -1;
1511 		}
1512 	
1513 		savederrno = get_global_wrlock(knet_h);
1514 		if (savederrno) {
1515 			log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
1516 				strerror(savederrno));
1517 			errno = savederrno;
1518 			return -1;
1519 		}
1520 	
1521 		host = knet_h->host_index[host_id];
1522 		if (!host) {
1523 			err = -1;
1524 			savederrno = EINVAL;
1525 			log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
1526 				host_id, strerror(savederrno));
1527 			goto exit_unlock;
1528 		}
1529 	
1530 		link = &host->link[link_id];
1531 	
1532 		if (!link->configured) {
1533 			err = -1;
1534 			savederrno = EINVAL;
1535 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
1536 				host_id, link_id, strerror(savederrno));
1537 			goto exit_unlock;
1538 		}
1539 	
1540 		if (link->dynamic != KNET_LINK_DYNIP) {
1541 			err = -1;
1542 			savederrno = EINVAL;
1543 			log_err(knet_h, KNET_SUB_LINK, "host %u link %u is a point to point connection: %s",
1544 				host_id, link_id, strerror(savederrno));
1545 			goto exit_unlock;
1546 		}
1547 	
1548 		check_rmall(knet_h, link);
1549 	
1550 	exit_unlock:
1551 		pthread_rwlock_unlock(&knet_h->global_rwlock);
1552 	
1553 		errno = savederrno;
1554 		return err;
1555 	}
1556