Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ucon.c
Go to the documentation of this file.
1 /*
2  * ucon.c
3  *
4  * Copyright (c) 2004+ Evgeniy Polyakov <[email protected]>
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 = NLMSG_LENGTH(size - sizeof(*nlh));
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"
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 
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 }