[CONNECTOR]: Add userspace example code into Documentation/connector/

I was asked several times to include userspace example code into
Documentation, so if there is no policy against it, consider attached patch
for 2.6.18. This program works with included Documentation/connector/cn_test.c
connector module.

Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Evgeniy Polyakov and committed by David S. Miller 897522ea 94918ff6

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