blob: fa17f864200eb0055e43bb14fcdd6fdc698a8b7f [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Evgeniy Polyakov897522e2006-08-25 00:52:06 -07002/*
3 * ucon.c
4 *
Evgeniy Polyakovacb9c1b2009-07-21 12:43:51 -07005 * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net>
Evgeniy Polyakov897522e2006-08-25 00:52:06 -07006 */
7
8#include <asm/types.h>
9
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <sys/poll.h>
13
14#include <linux/netlink.h>
15#include <linux/rtnetlink.h>
16
17#include <arpa/inet.h>
18
Mike Frysinger37cf2b82009-07-17 10:14:26 -070019#include <stdbool.h>
Evgeniy Polyakov897522e2006-08-25 00:52:06 -070020#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <string.h>
24#include <errno.h>
25#include <time.h>
Mike Frysinger37cf2b82009-07-17 10:14:26 -070026#include <getopt.h>
Evgeniy Polyakov897522e2006-08-25 00:52:06 -070027
28#include <linux/connector.h>
29
30#define DEBUG
31#define NETLINK_CONNECTOR 11
32
Mike Frysinger37cf2b82009-07-17 10:14:26 -070033/* Hopefully your userspace connector.h matches this kernel */
34#define CN_TEST_IDX CN_NETLINK_USERS + 3
35#define CN_TEST_VAL 0x456
36
Evgeniy Polyakov897522e2006-08-25 00:52:06 -070037#ifdef DEBUG
38#define ulog(f, a...) fprintf(stdout, f, ##a)
39#else
40#define ulog(f, a...) do {} while (0)
41#endif
42
43static int need_exit;
44static __u32 seq;
45
46static int netlink_send(int s, struct cn_msg *msg)
47{
48 struct nlmsghdr *nlh;
49 unsigned int size;
50 int err;
51 char buf[128];
52 struct cn_msg *m;
53
54 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
55
56 nlh = (struct nlmsghdr *)buf;
57 nlh->nlmsg_seq = seq++;
58 nlh->nlmsg_pid = getpid();
59 nlh->nlmsg_type = NLMSG_DONE;
Mathias Krause05742fa2013-09-30 22:03:09 +020060 nlh->nlmsg_len = size;
Evgeniy Polyakov897522e2006-08-25 00:52:06 -070061 nlh->nlmsg_flags = 0;
62
63 m = NLMSG_DATA(nlh);
64#if 0
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);
67#endif
68 memcpy(m, msg, sizeof(*m) + msg->len);
69
70 err = send(s, nlh, size, 0);
71 if (err == -1)
72 ulog("Failed to send: %s [%d].\n",
73 strerror(errno), errno);
74
75 return err;
76}
77
Mike Frysinger37cf2b82009-07-17 10:14:26 -070078static void usage(void)
79{
80 printf(
81 "Usage: ucon [options] [output file]\n"
82 "\n"
83 "\t-h\tthis help screen\n"
84 "\t-s\tsend buffers to the test module\n"
85 "\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"
90 "\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
94 );
95}
96
Evgeniy Polyakov897522e2006-08-25 00:52:06 -070097int main(int argc, char *argv[])
98{
99 int s;
100 char buf[1024];
101 int len;
102 struct nlmsghdr *reply;
103 struct sockaddr_nl l_local;
104 struct cn_msg *data;
105 FILE *out;
106 time_t tm;
107 struct pollfd pfd;
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700108 bool send_msgs = false;
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700109
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700110 while ((s = getopt(argc, argv, "hs")) != -1) {
111 switch (s) {
112 case 's':
113 send_msgs = true;
114 break;
115
116 case 'h':
117 usage();
118 return 0;
119
120 default:
121 /* getopt() outputs an error for us */
122 usage();
123 return 1;
124 }
125 }
126
127 if (argc != optind) {
128 out = fopen(argv[optind], "a+");
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700129 if (!out) {
130 ulog("Unable to open %s for writing: %s\n",
131 argv[1], strerror(errno));
132 out = stdout;
133 }
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700134 } else
135 out = stdout;
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700136
137 memset(buf, 0, sizeof(buf));
138
139 s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
140 if (s == -1) {
141 perror("socket");
142 return -1;
143 }
144
145 l_local.nl_family = AF_NETLINK;
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700146 l_local.nl_groups = -1; /* bitmask of requested groups */
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700147 l_local.nl_pid = 0;
148
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700149 ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
150
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700151 if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
152 perror("bind");
153 close(s);
154 return -1;
155 }
156
157#if 0
158 {
159 int on = 0x57; /* Additional group number */
160 setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
161 }
162#endif
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700163 if (send_msgs) {
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700164 int i, j;
165
166 memset(buf, 0, sizeof(buf));
167
168 data = (struct cn_msg *)buf;
169
Mike Frysinger37cf2b82009-07-17 10:14:26 -0700170 data->id.idx = CN_TEST_IDX;
171 data->id.val = CN_TEST_VAL;
Evgeniy Polyakov897522e2006-08-25 00:52:06 -0700172 data->seq = seq++;
173 data->ack = 0;
174 data->len = 0;
175
176 for (j=0; j<10; ++j) {
177 for (i=0; i<1000; ++i) {
178 len = netlink_send(s, data);
179 }
180
181 ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val);
182 }
183
184 return 0;
185 }
186
187
188 pfd.fd = s;
189
190 while (!need_exit) {
191 pfd.events = POLLIN;
192 pfd.revents = 0;
193 switch (poll(&pfd, 1, -1)) {
194 case 0:
195 need_exit = 1;
196 break;
197 case -1:
198 if (errno != EINTR) {
199 need_exit = 1;
200 break;
201 }
202 continue;
203 }
204 if (need_exit)
205 break;
206
207 memset(buf, 0, sizeof(buf));
208 len = recv(s, buf, sizeof(buf), 0);
209 if (len == -1) {
210 perror("recv buf");
211 close(s);
212 return -1;
213 }
214 reply = (struct nlmsghdr *)buf;
215
216 switch (reply->nlmsg_type) {
217 case NLMSG_ERROR:
218 fprintf(out, "Error message received.\n");
219 fflush(out);
220 break;
221 case NLMSG_DONE:
222 data = (struct cn_msg *)NLMSG_DATA(reply);
223
224 time(&tm);
225 fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n",
226 ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack);
227 fflush(out);
228 break;
229 default:
230 break;
231 }
232 }
233
234 close(s);
235 return 0;
236}