Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/samples/connector/ucon.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* ucon.c
4
*
5
* Copyright (c) 2004+ Evgeniy Polyakov <[email protected]>
6
*/
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
19
#include <stdbool.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <unistd.h>
23
#include <string.h>
24
#include <errno.h>
25
#include <time.h>
26
#include <getopt.h>
27
28
#include <linux/connector.h>
29
30
#define DEBUG
31
#define NETLINK_CONNECTOR 11
32
33
/* Hopefully your userspace connector.h matches this kernel */
34
#define CN_TEST_IDX CN_NETLINK_USERS + 3
35
#define CN_TEST_VAL 0x456
36
37
#ifdef DEBUG
38
#define ulog(f, a...) fprintf(stdout, f, ##a)
39
#else
40
#define ulog(f, a...) do {} while (0)
41
#endif
42
43
static int need_exit;
44
static __u32 seq;
45
46
static 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;
60
nlh->nlmsg_len = size;
61
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
78
static 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
97
int 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;
108
bool send_msgs = false;
109
110
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+");
129
if (!out) {
130
ulog("Unable to open %s for writing: %s\n",
131
argv[1], strerror(errno));
132
out = stdout;
133
}
134
} else
135
out = stdout;
136
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;
146
l_local.nl_groups = -1; /* bitmask of requested groups */
147
l_local.nl_pid = 0;
148
149
ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
150
151
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
163
if (send_msgs) {
164
int i, j;
165
166
memset(buf, 0, sizeof(buf));
167
168
data = (struct cn_msg *)buf;
169
170
data->id.idx = CN_TEST_IDX;
171
data->id.val = CN_TEST_VAL;
172
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
}
237
238