Linux Audio

Check our new training course

Loading...
v6.2
  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
 43static int need_exit;
 44static __u32 seq;
 45
 46static 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
 78static 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
 97int 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}
v4.17
 
  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 = size;
 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
 92static 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"
107		, CN_TEST_IDX, CN_TEST_VAL
108	);
109}
110
111int 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
153	s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
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}