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
51static int need_exit;
52static __u32 seq;
53
54static 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	memcpy(m, msg, sizeof(*m) + msg->len);
73
74	err = send(s, nlh, size, 0);
75	if (err == -1)
76		ulog("Failed to send: %s [%d].\n",
77			strerror(errno), errno);
78
79	return err;
80}
81
82int main(int argc, char *argv[])
83{
84	int s;
85	char buf[1024];
86	int len;
87	struct nlmsghdr *reply;
88	struct sockaddr_nl l_local;
89	struct cn_msg *data;
90	FILE *out;
91	time_t tm;
92	struct pollfd pfd;
93
94	if (argc < 2)
95		out = stdout;
96	else {
97		out = fopen(argv[1], "a+");
98		if (!out) {
99			ulog("Unable to open %s for writing: %s\n",
100				argv[1], strerror(errno));
101			out = stdout;
102		}
103	}
104
105	memset(buf, 0, sizeof(buf));
106
107	s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
108	if (s == -1) {
109		perror("socket");
110		return -1;
111	}
112
113	l_local.nl_family = AF_NETLINK;
114	l_local.nl_groups = 0x123; /* bitmask of requested groups */
115	l_local.nl_pid = 0;
116
117	if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
118		perror("bind");
119		close(s);
120		return -1;
121	}
122
123	if (0) {
124		int i, j;
125
126		memset(buf, 0, sizeof(buf));
127
128		data = (struct cn_msg *)buf;
129
130		data->id.idx = 0x123;
131		data->id.val = 0x456;
132		data->seq = seq++;
133		data->ack = 0;
134		data->len = 0;
135
136		for (j=0; j<10; ++j) {
137			for (i=0; i<1000; ++i) {
138				len = netlink_send(s, data);
139			}
140
141			ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val);
142		}
143
144		return 0;
145	}
146
147
148	pfd.fd = s;
149
150	while (!need_exit) {
151		pfd.events = POLLIN;
152		pfd.revents = 0;
153		switch (poll(&pfd, 1, -1)) {
154			case 0:
155				need_exit = 1;
156				break;
157			case -1:
158				if (errno != EINTR) {
159					need_exit = 1;
160					break;
161				}
162				continue;
163		}
164		if (need_exit)
165			break;
166
167		memset(buf, 0, sizeof(buf));
168		len = recv(s, buf, sizeof(buf), 0);
169		if (len == -1) {
170			perror("recv buf");
171			close(s);
172			return -1;
173		}
174		reply = (struct nlmsghdr *)buf;
175
176		switch (reply->nlmsg_type) {
177		case NLMSG_ERROR:
178			fprintf(out, "Error message received.\n");
179			fflush(out);
180			break;
181		case NLMSG_DONE:
182			data = (struct cn_msg *)NLMSG_DATA(reply);
183
184			time(&tm);
185			fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n",
186				ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack);
187			fflush(out);
188			break;
189		default:
190			break;
191		}
192	}
193
194	close(s);
195	return 0;
196}
197