xref: /original-bsd/sys/vax/datakit/dk.c (revision a91856c6)
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 	register struct	dkdev	*tp;
302 	register chan;
303 	register struct nameidata *ndp = &u.u_nd;	/* XXX */
304 	struct proc *p = u.u_procp;			/* XXX */
305 	struct vnode *vp;
306 	struct	file *fp;
307 	int	 m, error;
308 
309 #ifdef lint
310 	(void) dk_xint(0, 0);
311 #endif
312 	dev = minor(dev);
313 	if (dev == 1) {
314 		return 0;	/* Maintenance channel */
315 	}
316 
317 	chan = dev;
318 	if (chan >= dk_nchan) {
319 /* debug */	log(LOG_ERR, "dkopen bad: chan>=NDKCHANS : %d\n",chan);
320 		return ENXIO;
321 	}
322 
323 	tp = &dkdev[chan];
324 	if ((tp->d_state & DKOPEN) == 0)
325 		tp->dc_state = 0 ;
326 	if (tp->d_state&DKXCLUDE && u.u_procp->p_ruid!=0) {
327 		return EBUSY;
328 	}
329 
330 	if ((m = dk_open(chan, (int (*)()) NULL)) < 0)
331 		return -m;
332 
333 
334 	/*
335 	 * Channel 0 is reserved for maintenance.
336 	 * An open on channel 0 is interpreted as a request
337 	 * for an unused channel.
338 	 */
339 	if (chan==0) {
340 		char dname[30];
341 
342 		chan = m ;
343 		tp = &dkdev[chan] ;
344 		tp->dc_state = 0 ;
345 		/*
346 		 * throw away vnode for dk0. (/dev/dk/dial)
347 		 * Build standard name of new one, and ask namei for it.
348 		 */
349 		fp = u.u_ofile[-1 - p->p_dupfd];
350 
351 		dksnamer(dname, chan);
352 		/* log(LOG_ERR, "dname=%s chan=%d\n", dname, chan); */
353 		ndp->ni_nameiop = FOLLOW | LOOKUP | LOCKLEAF;
354 		ndp->ni_segflg = UIO_SYSSPACE;
355 		ndp->ni_dirp = dname;
356 		if (error = namei(ndp)) {
357 			(void) dk_close(chan) ;
358 			return (error);
359 		}
360 
361 		/* Give back old one */
362 		vp = (struct vnode *) fp->f_data;
363 		VOP_LOCK(vp);
364 		vput(vp);
365 
366 		vp = ndp->ni_vp;
367 		fp->f_data = (caddr_t) vp;
368 		VOP_UNLOCK(vp);
369 	}
370 	if ((tp->d_state & DKOPEN) == 0) {
371 		tp->d_state |= DKOPEN ;
372 		tp->dc_state = 0;
373 		tp->d_rmode = 0 ;
374 		tp->d_xctl = 0 ;
375 		tp->d_pgrp = 0;
376 	}
377 	tp->d_prot |= DpURP;
378 	return 0;
379 }
380 
381 /* Policy decision here -- standard name of dk file known to this routine */
382 dksnamer(s, n) register char *s;
383 {
384 	register char *p = "/dev/dk/dk";
385 
386 	while (*s++ = *p++)
387 		;
388 	s--;
389 	*s++ = '0' + (n/100); n %= 100;
390 	*s++ = '0' + (n/10); n %= 10;
391 	*s++ = '0' + n;
392 	*s = '\0';
393 }
394 
395 /*
396  * Close a channel:
397  */
398 
399 /*ARGSUSED*/
400 dkclose(dev, flag)
401 dev_t dev;
402 int flag;
403 {
404 	register struct	dkdev	*tp;
405 	extern wakeup() ;
406 	extern brelse() ;
407 	short	s, chan ;
408 	int i, cl = 0;
409 
410 	chan = minor(dev);
411 	tp = &dkdev[chan];
412 	if (chan == 1) {
413 		return 0;	/* Maintenance channel */
414 	}
415 	s = spl5() ;
416 	if (u.u_signal[SIGKILL] != SIG_IGN) {	  /* detect close from exit() */
417 		while (tp->d_bufct) {
418 			tp->d_state |= DKWAIT ;
419 			if (tsleep((caddr_t)(&tp->d_state), TTOPRI, ttyout, 0))
420 				break;
421 		}
422 	}
423 	else if (tp->d_bufct)
424 		/* Hmm -- buffers queued.  Let's wait 15 seconds max */
425 		for (i = 0; tp->d_bufct && i < 15; i++) {
426 			tp->d_state |= DKWAIT ;
427 			if (tsleep((caddr_t)(&tp->d_state), TTOPRI, ttyout, hz))
428 				break;
429 		}
430 	splx(s) ;
431 	tp->dc_state = 0;
432 	tp->d_rmode = 0;
433 	tp->d_prot &= ~DpURP;
434 	if(!tp->d_prot){
435 		cl = dk_close(chan);
436 		(void) dk_takedown(chan);
437 		tp->d_state = 0;
438 	}
439 	return -cl;
440 }
441 
442 dkread(dev, uio)
443 dev_t dev ;
444 struct uio *uio;
445 {
446 register struct dkdev *tp ;
447 int err;
448 
449 	M_ON(Mread) ;
450 	tp = &dkdev[minor(dev)] ;
451 	err = dkuread(minor(dev), uio) ;
452 	tp->d_rresid = uio->uio_resid ;
453 	M_OFF(Mread) ;
454 	return err;
455 }
456 
457 
458 dkwrite(dev, uio)
459 struct uio *uio;
460 dev_t dev ;
461 {
462 	int err;
463 
464 	M_ON(Mwrite) ;
465 	err = dkuwrite(minor(dev), uio) ;
466 	M_OFF(Mwrite) ;
467 	return err;
468 }
469 
470 #endif
471