xref: /original-bsd/sys/vax/datakit/dk.c (revision 410efcb1)
1 /*
2  * Datakit driver
3  *	SCCSID[] = "@(#)dk.c	2.1 DKHOST 84/07/03"
4  */
5 
6 #include "datakit.h"
7 #if NDATAKIT>0
8 
9 #include "../include/pte.h"
10 #include "sys/param.h"
11 #include "sys/signal.h"
12 #include "sys/errno.h"
13 #include "sys/conf.h"
14 #include "sys/user.h"
15 #include "sys/ioctl.h"
16 #include "sys/tty.h"
17 #include "sys/vnode.h"
18 #include "sys/file.h"
19 #include "sys/systm.h"
20 #include "sys/proc.h"
21 #include "sys/mbuf.h"
22 #include "sys/buf.h"
23 #include "sys/uio.h"
24 #include "sys/kernel.h"
25 #include "sys/dkit.h"
26 #include "sys/dkcmc.h"
27 #include "sys/dk.h"
28 #include "sys/dkdev.h"
29 #include "sys/syslog.h"
30 
31 extern int dkdebug ;
32 
33 #define DKBUFUSE	5	/* max buffers /channel */
34 
35 
36 int	dk_nchan	= NDATAKIT;
37 struct	dkdev		dkdev[NDATAKIT];
38 struct	dksetupreq	*dkreq[NDATAKIT];
39 
40 
41 
42 
43 #ifdef	MONITOR
44 int dummy ;
45 int *DKP2 = &dummy ;
46 #define	M_ON(a)		*DKP2 |= (a)
47 #define	M_OFF(a)	*DKP2 &= ~(a)
48 
49 #define	Mread	0400
50 #define Mrslp	01000
51 #define	Mrcpy	02000
52 #define	Mwrite	04000
53 #define	Mwcpy	010000
54 
55 #else
56 #define	M_ON(a)
57 #define	M_OFF(a)
58 #endif
59 
60 
61 
62 /*ARGSUSED*/
63 dkioctl(dev, cmd, data, flag)
64 register caddr_t data;
65 {
66 	register struct	dkdev	*tp;
67 	register chanstat ;
68 	int	chan, sp_chan;
69 	int	s, error = 0;
70 	register short	*pp ;
71 	struct dkdev *tsp;
72 	extern dkidone() ;
73 	struct diocdial dialreq;
74 	extern int commchan;
75 
76 	chan = dev = minor(dev);
77 	tp = &dkdev[chan];
78 	pp = (short *) data;
79 	switch(cmd) {
80 	case DIOCEXCL:
81 		tp->d_state |= DKXCLUDE ;
82 		break ;
83 	case DIOCNXCL:
84 		tp->d_state &= ~DKXCLUDE ;
85 		break ;
86 	case DIOCSETK:
87 		dkdebug = pp[0] ;
88 		break;
89 	case DIOCQQABO:
90 		pp[0] = tp->d_rresid;
91 		pp[1] = tp->d_rdone;
92 		pp[2] = tp->d_rctl;
93 		break ;
94 	case DIOCRMODE:
95 		if (pp[0] & DKR_TIME)
96 			tp->d_rmode = (DKR_TIME | DKR_BLOCK);
97 		else tp->d_rmode = pp[0] ;
98 		break ;
99 	case DIOCXCTL:
100 		tp->d_xctl = pp[0] ;
101 		break ;
102 	case DIOCFLUSH:
103 		dk_cmd(chan, DKC_XINIT|DKC_FLUSH);
104 		break;
105 	case KIOCINIT:
106 		dk_cmd(chan, DKC_XINIT);
107 		break;
108 	case DIOCXWIN:
109 		return dk_winsize(chan, (struct diocxwin *)data);
110 	case DIOCRESET:
111 		if (chan != 1 && chan != pp[0]) return EACCES;
112 		if (pp[0] > 1 && pp[0] < commchan) return EINVAL;
113 		if (pp[0] < 0 || pp[0] >= dk_nchan) return EINVAL;
114 		if (pp[0] == 0) return -dk_close(0);
115 		else dk_reset(pp[0]);
116 		break;
117 	case DIOCCTYPE:
118 		if (tp->d_ctype == NULL) {
119 			struct mbuf *m;
120 
121 			MGET(m, M_WAIT, DKMT_CTYPE);
122 			if (m == NULL)
123 				return ENOBUFS;
124 			tp->d_ctype = mtod(m, struct diocctype *);
125 		}
126 		return bcopy(data, (caddr_t) tp->d_ctype, sizeof (struct diocctype));
127 	case DIOCINFO:
128 		((struct diocinfo *)data)->dioc_nchan = dk_nchan;
129 		((struct diocinfo *)data)->dioc_channum = chan;
130 		((struct diocinfo *)data)->dioc_commchan = commchan;
131 		break;
132 	case DIOCSTAT:
133 		if (*((int *)data) < 0 || *((int *)data) >= dk_nchan)
134 			return EINVAL;
135 		*((int *)data) = dk_status(*((int *)data));
136 		break;
137 	case FIONBIO:
138 		if (*(int *)data)
139 			tp->dc_state |= DK_NDELAY;
140 		else
141 			tp->dc_state &= ~DK_NDELAY;
142 		break;
143 	case FIOASYNC:
144 		if (*(int *)data)
145 			tp->dc_state |= DK_ASYNC;
146 		else
147 			tp->dc_state &= ~DK_ASYNC;
148 		break;
149 	case TIOCGPGRP:
150 		*(int *)data = tp->d_pgrp;
151 		break;
152 	case TIOCSPGRP:
153 		tp->d_pgrp = *(int *)data;
154 		break;
155 
156 	/* splice chan to file descriptor */
157 	case DKIOCSPL:
158 		error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param,
159 		    3*sizeof (short));
160 		if (error) return error;
161 		if ((error = dkgetdev(tp->d_param[0], &sp_chan)) <= 0)
162 			return error ;
163 		if (sp_chan == chan)
164 			return EINVAL ;
165 		tsp = &dkdev[sp_chan] ;
166 		tp->dc_state |= DKSETUP ;
167 		tsp->dc_state |= DKSETUP ;
168 		if (dk_splice(chan, sp_chan, dkidone, (caddr_t) tp,
169 			(caddr_t) tsp)) {
170 			tp->dc_state &= ~DKSETUP ;
171 			tsp->dc_state &= ~DKSETUP ;
172 			return EIO ;
173 		}
174 		s = spl5() ;
175 		error = 0;
176 		while (error == 0 && tp->dc_state & DKSETUP)
177 			error = tsleep((caddr_t)tp, TTOPRI, ttopen, 0);
178 		while (error == 0 && tsp->dc_state & DKSETUP)
179 			error = tsleep((caddr_t)tsp, TTOPRI, ttopen, 0);
180 		splx(s) ;
181 		if (error)
182 			return (error);
183 		if ((dk_status(chan) & DK_RESET) || (dk_status(sp_chan) & DK_RESET))
184 			return EIO ;
185 		if (tp->d_error || tsp->d_error)
186 			return EIO ;
187 		error = copyout((caddr_t) tp->d_param, *(caddr_t *)data,
188 		    3*sizeof (short));
189 		if (error) return error;
190 		break ;
191 
192 	case DIOCSWAIT:
193 		error = dksplwait(chan);
194 		break ;
195 
196 	default:
197 		if ((cmd & DKIOCMASK) != DKIOCVAL) {
198 			return ENOTTY ;
199 		}
200 		if (cmd == DKIODIAL) {
201 			error = copyin(*(caddr_t *)data, (caddr_t) &dialreq,
202 			    sizeof (struct diocdial));
203 			if (error) return error;
204 			if (error = dkiodial(chan, dialreq.dialstring))
205 				return error;
206 			tp->dc_state |= DKSETUP ;
207 			chanstat = dk_setup(minor(dev), (int) DKIOCREQ, 0,
208 			0, 0, (int) u.u_uid, dkidone, (caddr_t)tp) ;
209 		}
210 		else {
211 			error = copyin(*(caddr_t *)data, (caddr_t) tp->d_param,
212 			    3*sizeof (short));
213 			if (error) return error;
214 			tp->dc_state |= DKSETUP ;
215 			chanstat = dk_setup(minor(dev), cmd, 0, 0, 0,
216 				(int) u.u_uid, dkidone, (caddr_t)tp) ;
217 		}
218 		if (chanstat) {
219 			tp->dc_state &= ~DKSETUP ;
220 			return (chanstat < 0 ? ECONNREFUSED : chanstat);
221 		}
222 		s = spl5() ;
223 		error = 0;
224 		while (error == 0 && tp->dc_state & DKSETUP)
225 			error = tsleep((caddr_t)(tp), TTOPRI, ttyout, 0) ;
226 		splx(s) ;
227 		if (error)
228 			return error;
229 		error = copyout((caddr_t) tp->d_param, *(caddr_t *)data,
230 		    3*sizeof (short));
231 		if (error) return error;
232 		if (dk_status(minor(dev)) & DK_RESET)
233 			return ENETRESET ;
234 		if (tp->d_error)
235 			return EIO ;
236 		break ;
237 	}
238 	return error;
239 }
240 
241 #define DS_SIZE 64
242 static
243 dkiodial(chan, user_ds)
244 register char *user_ds;
245 {
246 	register caddr_t ds;
247 	register n;
248 	register struct mbuf *mb;
249 	int u_count;
250 
251 	mb = m_get(M_WAIT, DKMT_DATA);
252 	if (mb == NULL) return ENOBUFS;
253 	ds = mtod(mb, caddr_t);
254 	for (u_count = 0; u_count < MLEN - 6; u_count++) {
255 		*ds = *user_ds;
256 		if (*ds == '\n' || *ds == '\0') break;
257 		ds++;
258 		user_ds++;
259 	}
260 	*ds = '\n';
261 	u_count++;
262 
263 	/* add uid in char decimal */
264 
265 	ds++;
266 	u_count++;
267 	for (n = u.u_uid; n /= 10; ds++) u_count++;
268 	for (n = u.u_uid;; ds--) {
269 		*ds = n % 10 + '0';
270 		if ((n /= 10) == 0) break;
271 	}
272 
273 	mb->m_len = u_count;
274 	if (dk_xmit(chan, mb, 1, 0, (int (*)()) 0, (caddr_t) 0) == 0) {
275 		return(EIO);
276 	}
277 	else return(0);
278 }
279 /*
280  * End action for ioctl completion
281  */
282 /*ARGSUSED*/
283 dkidone(tp, chan, err, p0, p1, p2)
284 register struct dkdev *tp ;
285 short chan, p0, p1, p2 ;
286 {
287 	tp->d_error = err ;
288 	tp->d_param[0] = p0 ;
289 	tp->d_param[1] = p1 ;
290 	tp->d_param[2] = p2 ;
291 	tp->dc_state &= ~DKSETUP ;
292 	wakeup((caddr_t)tp) ;
293 }
294 
295 
296 
297 
298 /*ARGSUSED*/
299 dkopen(dev, flag)
300 {
301 	USES_VOP_LOCK;
302 	USES_VOP_UNLOCK;
303 	register struct	dkdev	*tp;
304 	register chan;
305 	register struct nameidata *ndp = &u.u_nd;	/* XXX */
306 	struct proc *p = u.u_procp;			/* XXX */
307 	struct vnode *vp;
308 	struct	file *fp;
309 	int	 m, error;
310 
311 #ifdef lint
312 	(void) dk_xint(0, 0);
313 #endif
314 	dev = minor(dev);
315 	if (dev == 1) {
316 		return 0;	/* Maintenance channel */
317 	}
318 
319 	chan = dev;
320 	if (chan >= dk_nchan) {
321 /* debug */	log(LOG_ERR, "dkopen bad: chan>=NDKCHANS : %d\n",chan);
322 		return ENXIO;
323 	}
324 
325 	tp = &dkdev[chan];
326 	if ((tp->d_state & DKOPEN) == 0)
327 		tp->dc_state = 0 ;
328 	if (tp->d_state&DKXCLUDE && u.u_procp->p_ruid!=0) {
329 		return EBUSY;
330 	}
331 
332 	if ((m = dk_open(chan, (int (*)()) NULL)) < 0)
333 		return -m;
334 
335 
336 	/*
337 	 * Channel 0 is reserved for maintenance.
338 	 * An open on channel 0 is interpreted as a request
339 	 * for an unused channel.
340 	 */
341 	if (chan==0) {
342 		char dname[30];
343 
344 		chan = m ;
345 		tp = &dkdev[chan] ;
346 		tp->dc_state = 0 ;
347 		/*
348 		 * throw away vnode for dk0. (/dev/dk/dial)
349 		 * Build standard name of new one, and ask namei for it.
350 		 */
351 		fp = u.u_ofile[-1 - p->p_dupfd];
352 
353 		dksnamer(dname, chan);
354 		/* log(LOG_ERR, "dname=%s chan=%d\n", dname, chan); */
355 		ndp->ni_nameiop = FOLLOW | LOOKUP | LOCKLEAF;
356 		ndp->ni_segflg = UIO_SYSSPACE;
357 		ndp->ni_dirp = dname;
358 		if (error = namei(ndp)) {
359 			(void) dk_close(chan) ;
360 			return (error);
361 		}
362 
363 		/* Give back old one */
364 		vp = (struct vnode *) fp->f_data;
365 		VOP_LOCK(vp);
366 		vput(vp);
367 
368 		vp = ndp->ni_vp;
369 		fp->f_data = (caddr_t) vp;
370 		VOP_UNLOCK(vp);
371 	}
372 	if ((tp->d_state & DKOPEN) == 0) {
373 		tp->d_state |= DKOPEN ;
374 		tp->dc_state = 0;
375 		tp->d_rmode = 0 ;
376 		tp->d_xctl = 0 ;
377 		tp->d_pgrp = 0;
378 	}
379 	tp->d_prot |= DpURP;
380 	return 0;
381 }
382 
383 /* Policy decision here -- standard name of dk file known to this routine */
384 dksnamer(s, n) register char *s;
385 {
386 	register char *p = "/dev/dk/dk";
387 
388 	while (*s++ = *p++)
389 		;
390 	s--;
391 	*s++ = '0' + (n/100); n %= 100;
392 	*s++ = '0' + (n/10); n %= 10;
393 	*s++ = '0' + n;
394 	*s = '\0';
395 }
396 
397 /*
398  * Close a channel:
399  */
400 
401 /*ARGSUSED*/
402 dkclose(dev, flag)
403 dev_t dev;
404 int flag;
405 {
406 	register struct	dkdev	*tp;
407 	extern wakeup() ;
408 	extern brelse() ;
409 	short	s, chan ;
410 	int i, cl = 0;
411 
412 	chan = minor(dev);
413 	tp = &dkdev[chan];
414 	if (chan == 1) {
415 		return 0;	/* Maintenance channel */
416 	}
417 	s = spl5() ;
418 	if (u.u_signal[SIGKILL] != SIG_IGN) {	  /* detect close from exit() */
419 		while (tp->d_bufct) {
420 			tp->d_state |= DKWAIT ;
421 			if (tsleep((caddr_t)(&tp->d_state), TTOPRI, ttyout, 0))
422 				break;
423 		}
424 	}
425 	else if (tp->d_bufct)
426 		/* Hmm -- buffers queued.  Let's wait 15 seconds max */
427 		for (i = 0; tp->d_bufct && i < 15; i++) {
428 			tp->d_state |= DKWAIT ;
429 			if (tsleep((caddr_t)(&tp->d_state), TTOPRI, ttyout, hz))
430 				break;
431 		}
432 	splx(s) ;
433 	tp->dc_state = 0;
434 	tp->d_rmode = 0;
435 	tp->d_prot &= ~DpURP;
436 	if(!tp->d_prot){
437 		cl = dk_close(chan);
438 		(void) dk_takedown(chan);
439 		tp->d_state = 0;
440 	}
441 	return -cl;
442 }
443 
444 dkread(dev, uio)
445 dev_t dev ;
446 struct uio *uio;
447 {
448 register struct dkdev *tp ;
449 int err;
450 
451 	M_ON(Mread) ;
452 	tp = &dkdev[minor(dev)] ;
453 	err = dkuread(minor(dev), uio) ;
454 	tp->d_rresid = uio->uio_resid ;
455 	M_OFF(Mread) ;
456 	return err;
457 }
458 
459 
460 dkwrite(dev, uio)
461 struct uio *uio;
462 dev_t dev ;
463 {
464 	int err;
465 
466 	M_ON(Mwrite) ;
467 	err = dkuwrite(minor(dev), uio) ;
468 	M_OFF(Mwrite) ;
469 	return err;
470 }
471 
472 #endif
473