1/*
2 * This code lifted from:
3 * 	Simple `echo' pseudo-device KLD
4 * 	Murray Stokely
5 * 	Converted to 5.X by S��ren (Xride) Straarup
6 */
7
8/*
9 * /bin/echo "server,port=9999,addr=192.168.69.142,validate" > /dev/krping
10 * /bin/echo "client,port=9999,addr=192.168.69.142,validate" > /dev/krping
11 */
12
13#include <sys/cdefs.h>
14__FBSDID("$FreeBSD: releng/10.3/sys/contrib/rdma/krping/krping_dev.c 256829 2013-10-21 06:31:56Z np $");
15
16#include <sys/types.h>
17#include <sys/module.h>
18#include <sys/systm.h>  /* uprintf */
19#include <sys/errno.h>
20#include <sys/param.h>  /* defines used in kernel.h */
21#include <sys/kernel.h> /* types used in module initialization */
22#include <sys/conf.h>   /* cdevsw struct */
23#include <sys/uio.h>    /* uio struct */
24#include <sys/malloc.h>
25#include <sys/proc.h>
26#include <sys/sysctl.h>
27#include <machine/stdarg.h>
28
29#include "krping.h"
30
31#define BUFFERSIZE 512
32
33SYSCTL_NODE(_dev, OID_AUTO, krping, CTLFLAG_RW, 0, "kernel rping module");
34
35int krping_debug = 0;
36SYSCTL_INT(_dev_krping, OID_AUTO, debug, CTLFLAG_RW, &krping_debug, 0 , "");
37
38/* Function prototypes */
39static d_open_t      krping_open;
40static d_close_t     krping_close;
41static d_read_t      krping_read;
42static d_write_t     krping_write;
43
44/* Character device entry points */
45static struct cdevsw krping_cdevsw = {
46	.d_version = D_VERSION,
47	.d_open = krping_open,
48	.d_close = krping_close,
49	.d_read = krping_read,
50	.d_write = krping_write,
51	.d_name = "krping",
52};
53
54typedef struct s_krping {
55	char msg[BUFFERSIZE];
56	int len;
57} krping_t;
58
59struct stats_list_entry {
60	STAILQ_ENTRY(stats_list_entry) link;
61	struct krping_stats *stats;
62};
63STAILQ_HEAD(stats_list, stats_list_entry);
64
65/* vars */
66static struct cdev *krping_dev;
67
68static int
69krping_loader(struct module *m, int what, void *arg)
70{
71	int err = 0;
72
73	switch (what) {
74	case MOD_LOAD:                /* kldload */
75		krping_init();
76		krping_dev = make_dev(&krping_cdevsw, 0, UID_ROOT, GID_WHEEL,
77					0600, "krping");
78		printf("Krping device loaded.\n");
79		break;
80	case MOD_UNLOAD:
81		destroy_dev(krping_dev);
82		printf("Krping device unloaded.\n");
83		break;
84	default:
85		err = EOPNOTSUPP;
86		break;
87	}
88
89	return (err);
90}
91
92static int
93krping_open(struct cdev *dev, int oflags, int devtype, struct thread *p)
94{
95
96	return (0);
97}
98
99static int
100krping_close(struct cdev *dev, int fflag, int devtype, struct thread *p)
101{
102
103	return 0;
104}
105
106static void
107krping_copy_stats(struct krping_stats *stats, void *arg)
108{
109	struct stats_list_entry *s;
110	struct stats_list *list = arg;
111
112	s = malloc(sizeof(*s), M_DEVBUF, M_NOWAIT | M_ZERO);
113	if (s == NULL)
114		return;
115	if (stats != NULL) {
116		s->stats = malloc(sizeof(*stats), M_DEVBUF, M_NOWAIT | M_ZERO);
117		if (s->stats == NULL) {
118			free(s, M_DEVBUF);
119			return;
120		}
121		*s->stats = *stats;
122	}
123	STAILQ_INSERT_TAIL(list, s, link);
124}
125
126static int
127krping_read(struct cdev *dev, struct uio *uio, int ioflag)
128{
129	int num = 1;
130	struct stats_list list;
131	struct stats_list_entry *e;
132
133	STAILQ_INIT(&list);
134	krping_walk_cb_list(krping_copy_stats, &list);
135
136	if (STAILQ_EMPTY(&list))
137		return (0);
138
139	uprintf("krping: %4s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n",
140	    "num", "device", "snd bytes", "snd msgs", "rcv bytes", "rcv msgs",
141	    "wr bytes", "wr msgs", "rd bytes", "rd msgs");
142
143	while (!STAILQ_EMPTY(&list)) {
144		e = STAILQ_FIRST(&list);
145		STAILQ_REMOVE_HEAD(&list, link);
146		if (e->stats == NULL)
147			uprintf("krping: %d listen\n", num);
148		else {
149			struct krping_stats *stats = e->stats;
150
151			uprintf("krping: %4d %10s %10llu %10llu %10llu %10llu "
152			    "%10llu %10llu %10llu %10llu\n", num, stats->name,
153			    stats->send_bytes, stats->send_msgs,
154			    stats->recv_bytes, stats->recv_msgs,
155			    stats->write_bytes, stats->write_msgs,
156			    stats->read_bytes, stats->read_msgs);
157			free(stats, M_DEVBUF);
158		}
159		num++;
160		free(e, M_DEVBUF);
161	}
162
163	return (0);
164}
165
166static int
167krping_write(struct cdev *dev, struct uio *uio, int ioflag)
168{
169	int err = 0;
170	int amt;
171	int remain = BUFFERSIZE;
172	char *cp;
173	krping_t *krpingmsg;
174
175	krpingmsg = malloc(sizeof *krpingmsg, M_DEVBUF, M_WAITOK|M_ZERO);
176	if (!krpingmsg) {
177		uprintf("Could not malloc mem!\n");
178		return ENOMEM;
179	}
180
181	cp = krpingmsg->msg;
182	while (uio->uio_resid) {
183		amt = MIN(uio->uio_resid, remain);
184		if (amt == 0)
185			break;
186
187		/* Copy the string in from user memory to kernel memory */
188		err = uiomove(cp, amt, uio);
189		if (err) {
190			uprintf("Write failed: bad address!\n");
191			return err;
192		}
193		cp += amt;
194		remain -= amt;
195	}
196
197	if (uio->uio_resid != 0) {
198		uprintf("Message too big. max size is %d!\n", BUFFERSIZE);
199		return EMSGSIZE;
200	}
201
202	/* null terminate and remove the \n */
203	cp--;
204	*cp = 0;
205	krpingmsg->len = (unsigned long)(cp - krpingmsg->msg);
206	uprintf("krping: write string = |%s|\n", krpingmsg->msg);
207	err = krping_doit(krpingmsg->msg, curproc);
208	free(krpingmsg, M_DEVBUF);
209	return(err);
210}
211
212void
213krping_printf(void *cookie, const char *fmt, ...)
214{
215	va_list ap;
216
217	va_start(ap, fmt);
218	vtprintf(cookie, -1, fmt, ap);
219	va_end(ap);
220}
221
222int
223krping_sigpending(void)
224{
225
226	return (SIGPENDING(curthread));
227}
228
229DEV_MODULE(krping, krping_loader, NULL);
230MODULE_DEPEND(krping, ibcore, 1, 1, 1);
231