1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net>
10 #include <sys/types.h>
11 #include <sys/socket.h>
14 #include <linux/netlink.h>
15 #include <linux/rtnetlink.h>
17 #include <arpa/inet.h>
28 #include <linux/connector.h>
31 #define NETLINK_CONNECTOR 11
33 /* Hopefully your userspace connector.h matches this kernel */
34 #define CN_TEST_IDX CN_NETLINK_USERS + 3
35 #define CN_TEST_VAL 0x456
38 #define ulog(f, a...) fprintf(stdout, f, ##a)
40 #define ulog(f, a...) do {} while (0)
46 static int netlink_send(int s
, struct cn_msg
*msg
)
54 size
= NLMSG_SPACE(sizeof(struct cn_msg
) + msg
->len
);
56 nlh
= (struct nlmsghdr
*)buf
;
57 nlh
->nlmsg_seq
= seq
++;
58 nlh
->nlmsg_pid
= getpid();
59 nlh
->nlmsg_type
= NLMSG_DONE
;
60 nlh
->nlmsg_len
= size
;
65 ulog("%s: [%08x.%08x] len=%u, seq=%u, ack=%u.\n",
66 __func__
, msg
->id
.idx
, msg
->id
.val
, msg
->len
, msg
->seq
, msg
->ack
);
68 memcpy(m
, msg
, sizeof(*m
) + msg
->len
);
70 err
= send(s
, nlh
, size
, 0);
72 ulog("Failed to send: %s [%d].\n",
73 strerror(errno
), errno
);
78 static void usage(void)
81 "Usage: ucon [options] [output file]\n"
83 "\t-h\tthis help screen\n"
84 "\t-s\tsend buffers to the test module\n"
86 "The default behavior of ucon is to subscribe to the test module\n"
87 "and wait for state messages. Any ones received are dumped to the\n"
88 "specified output file (or stdout). The test module is assumed to\n"
89 "have an id of {%u.%u}\n"
91 "If you get no output, then verify the cn_test module id matches\n"
92 "the expected id above.\n"
93 , CN_TEST_IDX
, CN_TEST_VAL
97 int main(int argc
, char *argv
[])
102 struct nlmsghdr
*reply
;
103 struct sockaddr_nl l_local
;
108 bool send_msgs
= false;
110 while ((s
= getopt(argc
, argv
, "hs")) != -1) {
121 /* getopt() outputs an error for us */
127 if (argc
!= optind
) {
128 out
= fopen(argv
[optind
], "a+");
130 ulog("Unable to open %s for writing: %s\n",
131 argv
[1], strerror(errno
));
137 memset(buf
, 0, sizeof(buf
));
139 s
= socket(PF_NETLINK
, SOCK_DGRAM
, NETLINK_CONNECTOR
);
145 l_local
.nl_family
= AF_NETLINK
;
146 l_local
.nl_groups
= -1; /* bitmask of requested groups */
149 ulog("subscribing to %u.%u\n", CN_TEST_IDX
, CN_TEST_VAL
);
151 if (bind(s
, (struct sockaddr
*)&l_local
, sizeof(struct sockaddr_nl
)) == -1) {
159 int on
= 0x57; /* Additional group number */
160 setsockopt(s
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &on
, sizeof(on
));
166 memset(buf
, 0, sizeof(buf
));
168 data
= (struct cn_msg
*)buf
;
170 data
->id
.idx
= CN_TEST_IDX
;
171 data
->id
.val
= CN_TEST_VAL
;
176 for (j
=0; j
<10; ++j
) {
177 for (i
=0; i
<1000; ++i
) {
178 len
= netlink_send(s
, data
);
181 ulog("%d messages have been sent to %08x.%08x.\n", i
, data
->id
.idx
, data
->id
.val
);
193 switch (poll(&pfd
, 1, -1)) {
198 if (errno
!= EINTR
) {
207 memset(buf
, 0, sizeof(buf
));
208 len
= recv(s
, buf
, sizeof(buf
), 0);
214 reply
= (struct nlmsghdr
*)buf
;
216 switch (reply
->nlmsg_type
) {
218 fprintf(out
, "Error message received.\n");
222 data
= (struct cn_msg
*)NLMSG_DATA(reply
);
225 fprintf(out
, "%.24s : [%x.%x] [%08u.%08u].\n",
226 ctime(&tm
), data
->id
.idx
, data
->id
.val
, data
->seq
, data
->ack
);