About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Documentation / connector / ucon.c


Based on kernel version 4.6.2. Page generated on 2016-06-08 13:01 EST.

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


About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog