xref: /freebsd/sys/contrib/rdma/krping/krping_dev.c (revision 61e21613)
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 
33 SYSCTL_NODE(_dev, OID_AUTO, krping, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
34     "kernel rping module");
35 
36 int krping_debug = 0;
37 SYSCTL_INT(_dev_krping, OID_AUTO, debug, CTLFLAG_RW, &krping_debug, 0 , "");
38 
39 /* Function prototypes */
40 static d_open_t      krping_open;
41 static d_close_t     krping_close;
42 static d_read_t      krping_read;
43 static d_write_t     krping_write;
44 static d_purge_t     krping_purge;
45 
46 /* Character device entry points */
47 static 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 
57 typedef struct s_krping {
58 	char msg[BUFFERSIZE];
59 	int len;
60 } krping_t;
61 
62 struct stats_list_entry {
63 	STAILQ_ENTRY(stats_list_entry) link;
64 	struct krping_stats *stats;
65 };
66 STAILQ_HEAD(stats_list, stats_list_entry);
67 
68 /* vars */
69 static struct cdev *krping_dev;
70 
71 static int
72 krping_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 
94 static int
95 krping_open(struct cdev *dev, int oflags, int devtype, struct thread *p)
96 {
97 
98 	return (0);
99 }
100 
101 static int
102 krping_close(struct cdev *dev, int fflag, int devtype, struct thread *p)
103 {
104 
105 	return 0;
106 }
107 
108 static void
109 krping_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 
128 static int
129 krping_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 
168 static int
169 krping_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);
211 done:
212 	free(krpingmsg, M_DEVBUF);
213 	return(err);
214 }
215 
216 static void
217 krping_purge(struct cdev *dev __unused)
218 {
219 
220 	krping_cancel_all();
221 }
222 
223 int
224 krping_sigpending(void)
225 {
226 
227 	return (SIGPENDING(curthread));
228 }
229 
230 DEV_MODULE(krping, krping_loader, NULL);
231 MODULE_DEPEND(krping, ibcore, 1, 1, 1);
232