root/samples/connector/ucon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. netlink_send
  2. usage
  3. main

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

/* [<][>][^][v][top][bottom][index][help] */