1    	/*
2    	 * Copyright (C) 2016-2025 Red Hat, Inc.  All rights reserved.
3    	 *
4    	 * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
5    	 *
6    	 * This software licensed under GPL-2.0+
7    	 */
8    	
9    	#include "config.h"
10   	
11   	#include <errno.h>
12   	#include <stdio.h>
13   	#include <stdlib.h>
14   	#include <string.h>
15   	#include <unistd.h>
16   	
17   	#include "libknet.h"
18   	
19   	#include "internals.h"
20   	#include "netutils.h"
21   	#include "test-common.h"
22   	
23   	static int private_data;
24   	
25   	static void sock_notify(void *pvt_data,
26   				int datafd,
27   				int8_t channel,
28   				uint8_t tx_rx,
29   				int error,
30   				int errorno)
31   	{
32   		return;
33   	}
34   	
35   	static int dhost_filter_ret = 0;
36   	
37   	static int dhost_filter(void *pvt_data,
38   				const unsigned char *outdata,
39   				ssize_t outdata_len,
40   				uint8_t tx_rx,
41   				knet_node_id_t this_host_id,
42   				knet_node_id_t src_host_id,
43   				int8_t *dst_channel,
44   				knet_node_id_t *dst_host_ids,
45   				size_t *dst_host_ids_entries)
46   	{
47   		dst_host_ids[0] = 0;
48   	
49   		/*
50   		 * fatal fault
51   		 */
52   		if (dhost_filter_ret < 0) {
53   			return -1;
54   		}
55   	
56   		/*
57   		 * trigger EINVAL
58   		 * no ids found
59   		 */
60   		if (dhost_filter_ret == 0) {
61   			*dst_host_ids_entries = 0;
62   			return 0;
63   		}
64   	
65   		/*
66   	 	 * send correct info back
67   	 	 */
68   	
69   		if (dhost_filter_ret == 1) {
70   			dst_host_ids[0] = 1;
71   			*dst_host_ids_entries = 1;
72   			return 0;
73   		}
74   	
75   		/*
76   		 * trigger E2BIG
77   		 * mcast destinations
78   		 */
79   		if (dhost_filter_ret == 2) {
80   			dst_host_ids[0] = 1;
81   			*dst_host_ids_entries = 2;
82   			return 0;
83   		}
84   	
85   		/*
86   		 * return mcast
87   		 */
88   		if (dhost_filter_ret == 3) {
89   			return 1;
90   		}
91   	
92   		return dhost_filter_ret;
93   	}
94   	
95   	static void test(void)
96   	{
97   		knet_handle_t knet_h1, knet_h[2];
98   		int logfds[2];
99   		int datafd = 0;
100  		int8_t channel = 0;
101  		char send_buff[KNET_MAX_PACKET_SIZE];
102  		struct sockaddr_storage lo;
103  		int res;
104  	
105  		memset(send_buff, 0, sizeof(send_buff));
106  	
107  		printf("Test knet_send_sync incorrect knet_h\n");
108  	
(1) Event cond_false: Condition "!knet_send_sync(NULL, send_buff, 65536, channel)", taking false branch.
(2) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
109  		if ((!knet_send_sync(NULL, send_buff, KNET_MAX_PACKET_SIZE, channel)) || (errno != EINVAL)) {
110  			printf("knet_send_sync accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
111  			exit(FAIL);
(3) Event if_end: End of if statement.
112  		}
113  	
114  		setup_logpipes(logfds);
115  	
116  		knet_h1 = knet_handle_start(logfds, KNET_LOG_DEBUG, knet_h);
117  	
118  		printf("Test knet_send_sync with no send_buff\n");
(4) Event cond_false: Condition "(res = knet_send_sync(knet_h1, NULL, 65536, channel)) == 0", taking false branch.
(5) Event cond_true: Condition "res == -1", taking true branch.
(6) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
(7) Event else_branch: Reached else branch.
119  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, NULL, KNET_MAX_PACKET_SIZE, channel), EINVAL);
120  	
121  		printf("Test knet_send_sync with invalid send_buff len (0)\n");
(8) Event cond_false: Condition "(res = knet_send_sync(knet_h1, send_buff, 0, channel)) == 0", taking false branch.
(9) Event cond_true: Condition "res == -1", taking true branch.
(10) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
(11) Event else_branch: Reached else branch.
122  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, send_buff, 0, channel), EINVAL);
123  	
124  		printf("Test knet_send_sync with invalid send_buff len (> KNET_MAX_PACKET_SIZE)\n");
(12) Event cond_false: Condition "(res = knet_send_sync(knet_h1, send_buff, 65537UL /* 65536 + 1 */, channel)) == 0", taking false branch.
(13) Event cond_true: Condition "res == -1", taking true branch.
(14) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
(15) Event else_branch: Reached else branch.
125  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE + 1, channel), EINVAL);
126  	
127  		printf("Test knet_send_sync with invalid channel (-1)\n");
128  		channel = -1;
(16) Event cond_false: Condition "(res = knet_send_sync(knet_h1, send_buff, 65536, channel)) == 0", taking false branch.
(17) Event cond_true: Condition "res == -1", taking true branch.
(18) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
(19) Event else_branch: Reached else branch.
129  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel), EINVAL);
130  	
131  		printf("Test knet_send_sync with invalid channel (KNET_DATAFD_MAX)\n");
132  		channel = KNET_DATAFD_MAX;
(20) Event cond_false: Condition "(res = knet_send_sync(knet_h1, send_buff, 65536, channel)) == 0", taking false branch.
(21) Event cond_true: Condition "res == -1", taking true branch.
(22) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
(23) Event else_branch: Reached else branch.
133  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel), EINVAL);
134  	
135  		printf("Test knet_send_sync with no filter configured\n");
136  		channel = 1;
(24) Event lock_acquire: Calling "knet_send_sync" acquires lock "knet_handle.tx_mutex". [details]
(25) Event cond_false: Condition "(res = knet_send_sync(knet_h1, send_buff, 65536, channel)) == 0", taking false branch.
(26) Event cond_true: Condition "res == -1", taking true branch.
(27) Event cond_false: Condition "*__errno_location() != 100", taking false branch.
(28) Event else_branch: Reached else branch.
Also see events: [lock_order][lock_acquire][example_lock_order][lock_acquire][example_lock_order][lock_acquire][example_lock_order]
137  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel), ENETDOWN);
(29) Event cond_false: Condition "(res = knet_handle_enable_filter(knet_h1, NULL, dhost_filter)) != 0", taking false branch.
(30) Event else_branch: Reached else branch.
138  		FAIL_ON_ERR(knet_handle_enable_filter(knet_h1, NULL, dhost_filter));
139  	
140  	
141  		printf("Test knet_send_sync with unconfigured channel\n");
142  		channel = 0;
(31) Event cond_false: Condition "(res = knet_send_sync(knet_h1, send_buff, 65536, channel)) == 0", taking false branch.
(32) Event cond_true: Condition "res == -1", taking true branch.
(33) Event cond_false: Condition "*__errno_location() != 22", taking false branch.
(34) Event else_branch: Reached else branch.
143  		FAIL_ON_SUCCESS(knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel), EINVAL);
144  	
145  		printf("Test knet_send_sync with data forwarding disabled\n");
(35) Event cond_false: Condition "(res = knet_handle_enable_sock_notify(knet_h1, &private_data, sock_notify)) != 0", taking false branch.
(36) Event else_branch: Reached else branch.
146  		FAIL_ON_ERR(knet_handle_enable_sock_notify(knet_h1, &private_data, sock_notify));
147  	
148  		datafd = 0;
149  		channel = -1;
150  	
(37) Event lock_order: Calling "knet_handle_add_datafd" acquires lock "knet_handle.global_rwlock" while holding lock "knet_handle.tx_mutex" (count: 1 / 4). [details]
Also see events: [lock_acquire][lock_acquire][example_lock_order][lock_acquire][example_lock_order][lock_acquire][example_lock_order]
151  		FAIL_ON_ERR(knet_handle_add_datafd(knet_h1, &datafd, &channel));
152  	
153  		if ((knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != ECANCELED)) {
154  			printf("knet_send_sync didn't detect datafwd disabled or returned incorrect error: %s\n", strerror(errno));
155  			CLEAN_EXIT(FAIL);
156  		}
157  	
158  		printf("Test knet_send_sync with broken dst_host_filter\n");
159  		FAIL_ON_ERR(knet_handle_setfwd(knet_h1, 1));
160  		dhost_filter_ret = -1;
161  		if ((knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != EFAULT)) {
162  			printf("knet_send_sync didn't detect fatal error from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
163  			CLEAN_EXIT(FAIL);
164  		}
165  	
166  		printf("Test knet_send_sync with dst_host_filter returning no host_ids_entries\n");
167  		dhost_filter_ret = 0;
168  		if ((knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != EINVAL)) {
169  			printf("knet_send_sync didn't detect 0 host_ids from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
170  			CLEAN_EXIT(FAIL);
171  		}
172  	
173  		printf("Test knet_send_sync with host down\n");
174  		dhost_filter_ret = 1;
175  		if ((knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != EHOSTDOWN)) {
176  			printf("knet_send_sync didn't detect hostdown or returned incorrect error: %s\n", strerror(errno));
177  			CLEAN_EXIT(FAIL);
178  		}
179  	
180  		printf("Test knet_send_sync with dst_host_filter returning too many host_ids_entries\n");
181  		FAIL_ON_ERR(knet_host_add(knet_h1, 1));
182  		FAIL_ON_ERR(_knet_link_set_config(knet_h1, 1, 0, KNET_TRANSPORT_UDP, 0, AF_INET, 0, &lo));
183  		FAIL_ON_ERR(knet_link_set_enable(knet_h1, 1, 0, 1));
184  		FAIL_ON_ERR(wait_for_host(knet_h1, 1, 10, logfds[0], stdout));
185  		dhost_filter_ret = 2;
186  		if ((knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != E2BIG)) {
187  			printf("knet_send_sync didn't detect 2+ host_ids from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
188  			CLEAN_EXIT(FAIL);
189  		}
190  	
191  		printf("Test knet_send_sync with dst_host_filter returning mcast packets\n");
192  		dhost_filter_ret = 3;
193  		if ((knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != E2BIG)) {
194  			printf("knet_send_sync didn't detect mcast packet from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
195  			CLEAN_EXIT(FAIL);
196  		}
197  	
198  	
199  		printf("Test knet_send_sync with valid data\n");
200  		dhost_filter_ret = 1;
201  		FAIL_ON_ERR(knet_send_sync(knet_h1, send_buff, KNET_MAX_PACKET_SIZE, channel));
202  	
203  		FAIL_ON_ERR(knet_handle_setfwd(knet_h1, 0));
204  	
205  		CLEAN_EXIT(CONTINUE);
206  	}
207  	
208  	int main(int argc, char *argv[])
209  	{
210  		test();
211  	
212  		return PASS;
213  	}
214