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