1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * ucon.c 3 * ucon.c 4 * 4 * 5 * Copyright (c) 2004+ Evgeniy Polyakov <zbr@i 5 * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net> 6 */ 6 */ 7 7 8 #include <asm/types.h> 8 #include <asm/types.h> 9 9 10 #include <sys/types.h> 10 #include <sys/types.h> 11 #include <sys/socket.h> 11 #include <sys/socket.h> 12 #include <sys/poll.h> 12 #include <sys/poll.h> 13 13 14 #include <linux/netlink.h> 14 #include <linux/netlink.h> 15 #include <linux/rtnetlink.h> 15 #include <linux/rtnetlink.h> 16 16 17 #include <arpa/inet.h> 17 #include <arpa/inet.h> 18 18 19 #include <stdbool.h> 19 #include <stdbool.h> 20 #include <stdio.h> 20 #include <stdio.h> 21 #include <stdlib.h> 21 #include <stdlib.h> 22 #include <unistd.h> 22 #include <unistd.h> 23 #include <string.h> 23 #include <string.h> 24 #include <errno.h> 24 #include <errno.h> 25 #include <time.h> 25 #include <time.h> 26 #include <getopt.h> 26 #include <getopt.h> 27 27 28 #include <linux/connector.h> 28 #include <linux/connector.h> 29 29 30 #define DEBUG 30 #define DEBUG 31 #define NETLINK_CONNECTOR 11 31 #define NETLINK_CONNECTOR 11 32 32 33 /* Hopefully your userspace connector.h matche 33 /* Hopefully your userspace connector.h matches this kernel */ 34 #define CN_TEST_IDX CN_NETLINK_USE 34 #define CN_TEST_IDX CN_NETLINK_USERS + 3 35 #define CN_TEST_VAL 0x456 35 #define CN_TEST_VAL 0x456 36 36 37 #ifdef DEBUG 37 #ifdef DEBUG 38 #define ulog(f, a...) fprintf(stdout, f, ##a) 38 #define ulog(f, a...) fprintf(stdout, f, ##a) 39 #else 39 #else 40 #define ulog(f, a...) do {} while (0) 40 #define ulog(f, a...) do {} while (0) 41 #endif 41 #endif 42 42 43 static int need_exit; 43 static int need_exit; 44 static __u32 seq; 44 static __u32 seq; 45 45 46 static int netlink_send(int s, struct cn_msg * 46 static int netlink_send(int s, struct cn_msg *msg) 47 { 47 { 48 struct nlmsghdr *nlh; 48 struct nlmsghdr *nlh; 49 unsigned int size; 49 unsigned int size; 50 int err; 50 int err; 51 char buf[128]; 51 char buf[128]; 52 struct cn_msg *m; 52 struct cn_msg *m; 53 53 54 size = NLMSG_SPACE(sizeof(struct cn_ms 54 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len); 55 55 56 nlh = (struct nlmsghdr *)buf; 56 nlh = (struct nlmsghdr *)buf; 57 nlh->nlmsg_seq = seq++; 57 nlh->nlmsg_seq = seq++; 58 nlh->nlmsg_pid = getpid(); 58 nlh->nlmsg_pid = getpid(); 59 nlh->nlmsg_type = NLMSG_DONE; 59 nlh->nlmsg_type = NLMSG_DONE; 60 nlh->nlmsg_len = size; 60 nlh->nlmsg_len = size; 61 nlh->nlmsg_flags = 0; 61 nlh->nlmsg_flags = 0; 62 62 63 m = NLMSG_DATA(nlh); 63 m = NLMSG_DATA(nlh); 64 #if 0 64 #if 0 65 ulog("%s: [%08x.%08x] len=%u, seq=%u, 65 ulog("%s: [%08x.%08x] len=%u, seq=%u, ack=%u.\n", 66 __func__, msg->id.idx, msg->id. 66 __func__, msg->id.idx, msg->id.val, msg->len, msg->seq, msg->ack); 67 #endif 67 #endif 68 memcpy(m, msg, sizeof(*m) + msg->len); 68 memcpy(m, msg, sizeof(*m) + msg->len); 69 69 70 err = send(s, nlh, size, 0); 70 err = send(s, nlh, size, 0); 71 if (err == -1) 71 if (err == -1) 72 ulog("Failed to send: %s [%d]. 72 ulog("Failed to send: %s [%d].\n", 73 strerror(errno), errno 73 strerror(errno), errno); 74 74 75 return err; 75 return err; 76 } 76 } 77 77 78 static void usage(void) 78 static void usage(void) 79 { 79 { 80 printf( 80 printf( 81 "Usage: ucon [options] [output 81 "Usage: ucon [options] [output file]\n" 82 "\n" 82 "\n" 83 "\t-h\tthis help screen\n" 83 "\t-h\tthis help screen\n" 84 "\t-s\tsend buffers to the tes 84 "\t-s\tsend buffers to the test module\n" 85 "\n" 85 "\n" 86 "The default behavior of ucon 86 "The default behavior of ucon is to subscribe to the test module\n" 87 "and wait for state messages. 87 "and wait for state messages. Any ones received are dumped to the\n" 88 "specified output file (or std 88 "specified output file (or stdout). The test module is assumed to\n" 89 "have an id of {%u.%u}\n" 89 "have an id of {%u.%u}\n" 90 "\n" 90 "\n" 91 "If you get no output, then ve 91 "If you get no output, then verify the cn_test module id matches\n" 92 "the expected id above.\n" 92 "the expected id above.\n" 93 , CN_TEST_IDX, CN_TEST_VAL 93 , CN_TEST_IDX, CN_TEST_VAL 94 ); 94 ); 95 } 95 } 96 96 97 int main(int argc, char *argv[]) 97 int main(int argc, char *argv[]) 98 { 98 { 99 int s; 99 int s; 100 char buf[1024]; 100 char buf[1024]; 101 int len; 101 int len; 102 struct nlmsghdr *reply; 102 struct nlmsghdr *reply; 103 struct sockaddr_nl l_local; 103 struct sockaddr_nl l_local; 104 struct cn_msg *data; 104 struct cn_msg *data; 105 FILE *out; 105 FILE *out; 106 time_t tm; 106 time_t tm; 107 struct pollfd pfd; 107 struct pollfd pfd; 108 bool send_msgs = false; 108 bool send_msgs = false; 109 109 110 while ((s = getopt(argc, argv, "hs")) 110 while ((s = getopt(argc, argv, "hs")) != -1) { 111 switch (s) { 111 switch (s) { 112 case 's': 112 case 's': 113 send_msgs = true; 113 send_msgs = true; 114 break; 114 break; 115 115 116 case 'h': 116 case 'h': 117 usage(); 117 usage(); 118 return 0; 118 return 0; 119 119 120 default: 120 default: 121 /* getopt() outputs an 121 /* getopt() outputs an error for us */ 122 usage(); 122 usage(); 123 return 1; 123 return 1; 124 } 124 } 125 } 125 } 126 126 127 if (argc != optind) { 127 if (argc != optind) { 128 out = fopen(argv[optind], "a+" 128 out = fopen(argv[optind], "a+"); 129 if (!out) { 129 if (!out) { 130 ulog("Unable to open % 130 ulog("Unable to open %s for writing: %s\n", 131 argv[1], strer 131 argv[1], strerror(errno)); 132 out = stdout; 132 out = stdout; 133 } 133 } 134 } else 134 } else 135 out = stdout; 135 out = stdout; 136 136 137 memset(buf, 0, sizeof(buf)); 137 memset(buf, 0, sizeof(buf)); 138 138 139 s = socket(PF_NETLINK, SOCK_DGRAM, NET 139 s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 140 if (s == -1) { 140 if (s == -1) { 141 perror("socket"); 141 perror("socket"); 142 return -1; 142 return -1; 143 } 143 } 144 144 145 l_local.nl_family = AF_NETLINK; 145 l_local.nl_family = AF_NETLINK; 146 l_local.nl_groups = -1; /* bitmask of 146 l_local.nl_groups = -1; /* bitmask of requested groups */ 147 l_local.nl_pid = 0; 147 l_local.nl_pid = 0; 148 148 149 ulog("subscribing to %u.%u\n", CN_TEST 149 ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL); 150 150 151 if (bind(s, (struct sockaddr *)&l_loca 151 if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { 152 perror("bind"); 152 perror("bind"); 153 close(s); 153 close(s); 154 return -1; 154 return -1; 155 } 155 } 156 156 157 #if 0 157 #if 0 158 { 158 { 159 int on = 0x57; /* Additional g 159 int on = 0x57; /* Additional group number */ 160 setsockopt(s, SOL_NETLINK, NET 160 setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on)); 161 } 161 } 162 #endif 162 #endif 163 if (send_msgs) { 163 if (send_msgs) { 164 int i, j; 164 int i, j; 165 165 166 memset(buf, 0, sizeof(buf)); 166 memset(buf, 0, sizeof(buf)); 167 167 168 data = (struct cn_msg *)buf; 168 data = (struct cn_msg *)buf; 169 169 170 data->id.idx = CN_TEST_IDX; 170 data->id.idx = CN_TEST_IDX; 171 data->id.val = CN_TEST_VAL; 171 data->id.val = CN_TEST_VAL; 172 data->seq = seq++; 172 data->seq = seq++; 173 data->ack = 0; 173 data->ack = 0; 174 data->len = 0; 174 data->len = 0; 175 175 176 for (j=0; j<10; ++j) { 176 for (j=0; j<10; ++j) { 177 for (i=0; i<1000; ++i) 177 for (i=0; i<1000; ++i) { 178 len = netlink_ 178 len = netlink_send(s, data); 179 } 179 } 180 180 181 ulog("%d messages have 181 ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val); 182 } 182 } 183 183 184 return 0; 184 return 0; 185 } 185 } 186 186 187 187 188 pfd.fd = s; 188 pfd.fd = s; 189 189 190 while (!need_exit) { 190 while (!need_exit) { 191 pfd.events = POLLIN; 191 pfd.events = POLLIN; 192 pfd.revents = 0; 192 pfd.revents = 0; 193 switch (poll(&pfd, 1, -1)) { 193 switch (poll(&pfd, 1, -1)) { 194 case 0: 194 case 0: 195 need_exit = 1; 195 need_exit = 1; 196 break; 196 break; 197 case -1: 197 case -1: 198 if (errno != E 198 if (errno != EINTR) { 199 need_e 199 need_exit = 1; 200 break; 200 break; 201 } 201 } 202 continue; 202 continue; 203 } 203 } 204 if (need_exit) 204 if (need_exit) 205 break; 205 break; 206 206 207 memset(buf, 0, sizeof(buf)); 207 memset(buf, 0, sizeof(buf)); 208 len = recv(s, buf, sizeof(buf) 208 len = recv(s, buf, sizeof(buf), 0); 209 if (len == -1) { 209 if (len == -1) { 210 perror("recv buf"); 210 perror("recv buf"); 211 close(s); 211 close(s); 212 return -1; 212 return -1; 213 } 213 } 214 reply = (struct nlmsghdr *)buf 214 reply = (struct nlmsghdr *)buf; 215 215 216 switch (reply->nlmsg_type) { 216 switch (reply->nlmsg_type) { 217 case NLMSG_ERROR: 217 case NLMSG_ERROR: 218 fprintf(out, "Error me 218 fprintf(out, "Error message received.\n"); 219 fflush(out); 219 fflush(out); 220 break; 220 break; 221 case NLMSG_DONE: 221 case NLMSG_DONE: 222 data = (struct cn_msg 222 data = (struct cn_msg *)NLMSG_DATA(reply); 223 223 224 time(&tm); 224 time(&tm); 225 fprintf(out, "%.24s : 225 fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n", 226 ctime(&tm), da 226 ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack); 227 fflush(out); 227 fflush(out); 228 break; 228 break; 229 default: 229 default: 230 break; 230 break; 231 } 231 } 232 } 232 } 233 233 234 close(s); 234 close(s); 235 return 0; 235 return 0; 236 } 236 } 237 237
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.