Commit 897522ea1c20691b6a65f32f03ae4e77e508b31c
Committed by
David S. Miller
1 parent
94918ff68a
Exists in
master
and in
20 other branches
[CONNECTOR]: Add userspace example code into Documentation/connector/
I was asked several times to include userspace example code into Documentation, so if there is no policy against it, consider attached patch for 2.6.18. This program works with included Documentation/connector/cn_test.c connector module. Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 206 additions and 0 deletions Side-by-side Diff
Documentation/connector/ucon.c
1 | +/* | |
2 | + * ucon.c | |
3 | + * | |
4 | + * Copyright (c) 2004+ Evgeniy Polyakov <johnpol@2ka.mipt.ru> | |
5 | + * | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or modify | |
8 | + * it under the terms of the GNU General Public License as published by | |
9 | + * the Free Software Foundation; either version 2 of the License, or | |
10 | + * (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU General Public License | |
18 | + * along with this program; if not, write to the Free Software | |
19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | + */ | |
21 | + | |
22 | +#include <asm/types.h> | |
23 | + | |
24 | +#include <sys/types.h> | |
25 | +#include <sys/socket.h> | |
26 | +#include <sys/poll.h> | |
27 | + | |
28 | +#include <linux/netlink.h> | |
29 | +#include <linux/rtnetlink.h> | |
30 | + | |
31 | +#include <arpa/inet.h> | |
32 | + | |
33 | +#include <stdio.h> | |
34 | +#include <stdlib.h> | |
35 | +#include <unistd.h> | |
36 | +#include <string.h> | |
37 | +#include <errno.h> | |
38 | +#include <time.h> | |
39 | + | |
40 | +#include <linux/connector.h> | |
41 | + | |
42 | +#define DEBUG | |
43 | +#define NETLINK_CONNECTOR 11 | |
44 | + | |
45 | +#ifdef DEBUG | |
46 | +#define ulog(f, a...) fprintf(stdout, f, ##a) | |
47 | +#else | |
48 | +#define ulog(f, a...) do {} while (0) | |
49 | +#endif | |
50 | + | |
51 | +static int need_exit; | |
52 | +static __u32 seq; | |
53 | + | |
54 | +static int netlink_send(int s, struct cn_msg *msg) | |
55 | +{ | |
56 | + struct nlmsghdr *nlh; | |
57 | + unsigned int size; | |
58 | + int err; | |
59 | + char buf[128]; | |
60 | + struct cn_msg *m; | |
61 | + | |
62 | + size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len); | |
63 | + | |
64 | + nlh = (struct nlmsghdr *)buf; | |
65 | + nlh->nlmsg_seq = seq++; | |
66 | + nlh->nlmsg_pid = getpid(); | |
67 | + nlh->nlmsg_type = NLMSG_DONE; | |
68 | + nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh)); | |
69 | + nlh->nlmsg_flags = 0; | |
70 | + | |
71 | + m = NLMSG_DATA(nlh); | |
72 | +#if 0 | |
73 | + ulog("%s: [%08x.%08x] len=%u, seq=%u, ack=%u.\n", | |
74 | + __func__, msg->id.idx, msg->id.val, msg->len, msg->seq, msg->ack); | |
75 | +#endif | |
76 | + memcpy(m, msg, sizeof(*m) + msg->len); | |
77 | + | |
78 | + err = send(s, nlh, size, 0); | |
79 | + if (err == -1) | |
80 | + ulog("Failed to send: %s [%d].\n", | |
81 | + strerror(errno), errno); | |
82 | + | |
83 | + return err; | |
84 | +} | |
85 | + | |
86 | +int main(int argc, char *argv[]) | |
87 | +{ | |
88 | + int s; | |
89 | + char buf[1024]; | |
90 | + int len; | |
91 | + struct nlmsghdr *reply; | |
92 | + struct sockaddr_nl l_local; | |
93 | + struct cn_msg *data; | |
94 | + FILE *out; | |
95 | + time_t tm; | |
96 | + struct pollfd pfd; | |
97 | + | |
98 | + if (argc < 2) | |
99 | + out = stdout; | |
100 | + else { | |
101 | + out = fopen(argv[1], "a+"); | |
102 | + if (!out) { | |
103 | + ulog("Unable to open %s for writing: %s\n", | |
104 | + argv[1], strerror(errno)); | |
105 | + out = stdout; | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + memset(buf, 0, sizeof(buf)); | |
110 | + | |
111 | + s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | |
112 | + if (s == -1) { | |
113 | + perror("socket"); | |
114 | + return -1; | |
115 | + } | |
116 | + | |
117 | + l_local.nl_family = AF_NETLINK; | |
118 | + l_local.nl_groups = 0x123; /* bitmask of requested groups */ | |
119 | + l_local.nl_pid = 0; | |
120 | + | |
121 | + if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { | |
122 | + perror("bind"); | |
123 | + close(s); | |
124 | + return -1; | |
125 | + } | |
126 | + | |
127 | +#if 0 | |
128 | + { | |
129 | + int on = 0x57; /* Additional group number */ | |
130 | + setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on)); | |
131 | + } | |
132 | +#endif | |
133 | + if (0) { | |
134 | + int i, j; | |
135 | + | |
136 | + memset(buf, 0, sizeof(buf)); | |
137 | + | |
138 | + data = (struct cn_msg *)buf; | |
139 | + | |
140 | + data->id.idx = 0x123; | |
141 | + data->id.val = 0x456; | |
142 | + data->seq = seq++; | |
143 | + data->ack = 0; | |
144 | + data->len = 0; | |
145 | + | |
146 | + for (j=0; j<10; ++j) { | |
147 | + for (i=0; i<1000; ++i) { | |
148 | + len = netlink_send(s, data); | |
149 | + } | |
150 | + | |
151 | + ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val); | |
152 | + } | |
153 | + | |
154 | + return 0; | |
155 | + } | |
156 | + | |
157 | + | |
158 | + pfd.fd = s; | |
159 | + | |
160 | + while (!need_exit) { | |
161 | + pfd.events = POLLIN; | |
162 | + pfd.revents = 0; | |
163 | + switch (poll(&pfd, 1, -1)) { | |
164 | + case 0: | |
165 | + need_exit = 1; | |
166 | + break; | |
167 | + case -1: | |
168 | + if (errno != EINTR) { | |
169 | + need_exit = 1; | |
170 | + break; | |
171 | + } | |
172 | + continue; | |
173 | + } | |
174 | + if (need_exit) | |
175 | + break; | |
176 | + | |
177 | + memset(buf, 0, sizeof(buf)); | |
178 | + len = recv(s, buf, sizeof(buf), 0); | |
179 | + if (len == -1) { | |
180 | + perror("recv buf"); | |
181 | + close(s); | |
182 | + return -1; | |
183 | + } | |
184 | + reply = (struct nlmsghdr *)buf; | |
185 | + | |
186 | + switch (reply->nlmsg_type) { | |
187 | + case NLMSG_ERROR: | |
188 | + fprintf(out, "Error message received.\n"); | |
189 | + fflush(out); | |
190 | + break; | |
191 | + case NLMSG_DONE: | |
192 | + data = (struct cn_msg *)NLMSG_DATA(reply); | |
193 | + | |
194 | + time(&tm); | |
195 | + fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n", | |
196 | + ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack); | |
197 | + fflush(out); | |
198 | + break; | |
199 | + default: | |
200 | + break; | |
201 | + } | |
202 | + } | |
203 | + | |
204 | + close(s); | |
205 | + return 0; | |
206 | +} |