• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/Documentation/connector/
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
57static int need_exit;
58static __u32 seq;
59
60static 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 = NLMSG_LENGTH(size - sizeof(*nlh));
75	nlh->nlmsg_flags = 0;
76
77	m = NLMSG_DATA(nlh);
78	memcpy(m, msg, sizeof(*m) + msg->len);
79
80	err = send(s, nlh, size, 0);
81	if (err == -1)
82		ulog("Failed to send: %s [%d].\n",
83			strerror(errno), errno);
84
85	return err;
86}
87
88static void usage(void)
89{
90	printf(
91		"Usage: ucon [options] [output file]\n"
92		"\n"
93		"\t-h\tthis help screen\n"
94		"\t-s\tsend buffers to the test module\n"
95		"\n"
96		"The default behavior of ucon is to subscribe to the test module\n"
97		"and wait for state messages.  Any ones received are dumped to the\n"
98		"specified output file (or stdout).  The test module is assumed to\n"
99		"have an id of {%u.%u}\n"
100		"\n"
101		"If you get no output, then verify the cn_test module id matches\n"
102		"the expected id above.\n"
103		, CN_TEST_IDX, CN_TEST_VAL
104	);
105}
106
107int main(int argc, char *argv[])
108{
109	int s;
110	char buf[1024];
111	int len;
112	struct nlmsghdr *reply;
113	struct sockaddr_nl l_local;
114	struct cn_msg *data;
115	FILE *out;
116	time_t tm;
117	struct pollfd pfd;
118	bool send_msgs = false;
119
120	while ((s = getopt(argc, argv, "hs")) != -1) {
121		switch (s) {
122		case 's':
123			send_msgs = true;
124			break;
125
126		case 'h':
127			usage();
128			return 0;
129
130		default:
131			/* getopt() outputs an error for us */
132			usage();
133			return 1;
134		}
135	}
136
137	if (argc != optind) {
138		out = fopen(argv[optind], "a+");
139		if (!out) {
140			ulog("Unable to open %s for writing: %s\n",
141				argv[1], strerror(errno));
142			out = stdout;
143		}
144	} else
145		out = stdout;
146
147	memset(buf, 0, sizeof(buf));
148
149	s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
150	if (s == -1) {
151		perror("socket");
152		return -1;
153	}
154
155	l_local.nl_family = AF_NETLINK;
156	l_local.nl_groups = -1; /* bitmask of requested groups */
157	l_local.nl_pid = 0;
158
159	ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
160
161	if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
162		perror("bind");
163		close(s);
164		return -1;
165	}
166
167	if (send_msgs) {
168		int i, j;
169
170		memset(buf, 0, sizeof(buf));
171
172		data = (struct cn_msg *)buf;
173
174		data->id.idx = CN_TEST_IDX;
175		data->id.val = CN_TEST_VAL;
176		data->seq = seq++;
177		data->ack = 0;
178		data->len = 0;
179
180		for (j=0; j<10; ++j) {
181			for (i=0; i<1000; ++i) {
182				len = netlink_send(s, data);
183			}
184
185			ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val);
186		}
187
188		return 0;
189	}
190
191
192	pfd.fd = s;
193
194	while (!need_exit) {
195		pfd.events = POLLIN;
196		pfd.revents = 0;
197		switch (poll(&pfd, 1, -1)) {
198			case 0:
199				need_exit = 1;
200				break;
201			case -1:
202				if (errno != EINTR) {
203					need_exit = 1;
204					break;
205				}
206				continue;
207		}
208		if (need_exit)
209			break;
210
211		memset(buf, 0, sizeof(buf));
212		len = recv(s, buf, sizeof(buf), 0);
213		if (len == -1) {
214			perror("recv buf");
215			close(s);
216			return -1;
217		}
218		reply = (struct nlmsghdr *)buf;
219
220		switch (reply->nlmsg_type) {
221		case NLMSG_ERROR:
222			fprintf(out, "Error message received.\n");
223			fflush(out);
224			break;
225		case NLMSG_DONE:
226			data = (struct cn_msg *)NLMSG_DATA(reply);
227
228			time(&tm);
229			fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n",
230				ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack);
231			fflush(out);
232			break;
233		default:
234			break;
235		}
236	}
237
238	close(s);
239	return 0;
240}
241