8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27
28
29
30 /*
31 * Pseudo Terminal Slave Driver.
32 *
33 * The pseudo-tty subsystem simulates a terminal connection, where the master
34 * side represents the terminal and the slave represents the user process's
35 * special device end point. The master device is set up as a cloned device
36 * where its major device number is the major for the clone device and its minor
37 * device number is the major for the ptm driver. There are no nodes in the file
38 * system for master devices. The master pseudo driver is opened using the
39 * open(2) system call with /dev/ptmx as the device parameter. The clone open
40 * finds the next available minor device for the ptm major device.
41 *
42 * A master device is available only if it and its corresponding slave device
43 * are not already open. When the master device is opened, the corresponding
44 * slave device is automatically locked out. Only one open is allowed on a
45 * master device. Multiple opens are allowed on the slave device. After both
46 * the master and slave have been opened, the user has two file descriptors
47 * which are the end points of a full duplex connection composed of two streams
48 * which are automatically connected at the master and slave drivers. The user
49 * may then push modules onto either side of the stream pair.
89 * NULL before qprocsoff() is called during close.
90 *
91 * The pt_nullmsg field is only used in open/close routines and it is also
92 * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
93 * holds.
94 *
95 * Lock Ordering:
96 *
97 * If both ptms_lock and per-pty lock should be held, ptms_lock should always
98 * be entered first, followed by per-pty lock.
99 *
100 * See ptms.h, ptm.c and ptms_conf.c fore more information.
101 *
102 */
103
104 #include <sys/types.h>
105 #include <sys/param.h>
106 #include <sys/sysmacros.h>
107 #include <sys/stream.h>
108 #include <sys/stropts.h>
109 #include <sys/stat.h>
110 #include <sys/errno.h>
111 #include <sys/debug.h>
112 #include <sys/cmn_err.h>
113 #include <sys/ptms.h>
114 #include <sys/systm.h>
115 #include <sys/modctl.h>
116 #include <sys/conf.h>
117 #include <sys/ddi.h>
118 #include <sys/sunddi.h>
119 #include <sys/cred.h>
120 #include <sys/zone.h>
121
122 #ifdef DEBUG
123 int pts_debug = 0;
124 #define DBG(a) if (pts_debug) cmn_err(CE_NOTE, a)
125 #else
126 #define DBG(a)
127 #endif
128
320 if (ptsp->pt_zoneid != getzoneid()) {
321 mutex_exit(&ptsp->pt_lock);
322 mutex_exit(&ptms_lock);
323 return (EPERM);
324 }
325
326 /*
327 * Allow reopen of this device.
328 */
329 if (rqp->q_ptr != NULL) {
330 ASSERT(rqp->q_ptr == ptsp);
331 ASSERT(ptsp->pts_rdq == rqp);
332 mutex_exit(&ptsp->pt_lock);
333 mutex_exit(&ptms_lock);
334 return (0);
335 }
336
337 DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp);
338 DDBG("ptsopen: state = %x\n", ptsp->pt_state);
339
340
341 ASSERT(ptsp->pt_minor == dminor);
342
343 if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) {
344 mutex_exit(&ptsp->pt_lock);
345 mutex_exit(&ptms_lock);
346 return (EAGAIN);
347 }
348
349 /*
350 * if already, open simply return...
351 */
352 if (ptsp->pt_state & PTSOPEN) {
353 ASSERT(rqp->q_ptr == ptsp);
354 ASSERT(ptsp->pts_rdq == rqp);
355 mutex_exit(&ptsp->pt_lock);
356 mutex_exit(&ptms_lock);
357 return (0);
358 }
359
360 /*
361 * Allocate message block for setting stream head options.
362 */
363 if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
364 mutex_exit(&ptsp->pt_lock);
365 mutex_exit(&ptms_lock);
366 return (ENOMEM);
367 }
368
369 /*
370 * Slave should send zero-length message to a master when it is
371 * closing. If memory is low at that time, master will not detect slave
372 * closes, this pty will not be deallocated. So, preallocate this
373 * zero-length message block early.
374 */
375 if ((mp = allocb(0, BPRI_MED)) == NULL) {
376 mutex_exit(&ptsp->pt_lock);
377 mutex_exit(&ptms_lock);
378 freemsg(mop);
379 return (ENOMEM);
380 }
381
382 ptsp->pt_state |= PTSOPEN;
383
384 WR(rqp)->q_ptr = rqp->q_ptr = ptsp;
385
386 mutex_exit(&ptsp->pt_lock);
387 mutex_exit(&ptms_lock);
388
389 qprocson(rqp);
390
391 /*
392 * After qprocson pts driver is fully plumbed into the stream and can
393 * send/receive messages. Setting pts_rdq will allow master side to send
394 * messages to the slave. This setting can't occur before qprocson() is
395 * finished because slave is not ready to process them.
396 */
397 PT_ENTER_WRITE(ptsp);
398 ptsp->pts_rdq = rqp;
399 ASSERT(ptsp->pt_nullmsg == NULL);
400 ptsp->pt_nullmsg = mp;
401 PT_EXIT_WRITE(ptsp);
402
403 /*
404 * set up hi/lo water marks on stream head read queue
405 * and add controlling tty if not set
406 */
407
408 mop->b_datap->db_type = M_SETOPTS;
409 mop->b_wptr += sizeof (struct stroptions);
410 sop = (struct stroptions *)mop->b_rptr;
411 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
412 sop->so_hiwat = _TTY_BUFSIZ;
413 sop->so_lowat = 256;
414 putnext(rqp, mop);
415
416 return (0);
417 }
418
419
420
421 /*
422 * Find the address to private data identifying the slave's write
423 * queue. Send a 0-length msg up the slave's read queue to designate
424 * the master is closing. Uattach the master from the slave by nulling
425 * out master's write queue field in private data.
426 */
427 /*ARGSUSED1*/
428 static int
429 ptsclose(queue_t *rqp, int flag, cred_t *credp)
430 {
431 struct pt_ttys *ptsp;
432 queue_t *wqp;
433 mblk_t *mp;
434 mblk_t *bp;
435
436 /*
437 * q_ptr should never be NULL in the close routine and it is checked in
438 * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to
439 * behave gracefully.
440 */
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27
28 /*
29 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
30 */
31
32 /*
33 * Pseudo Terminal Slave Driver.
34 *
35 * The pseudo-tty subsystem simulates a terminal connection, where the master
36 * side represents the terminal and the slave represents the user process's
37 * special device end point. The master device is set up as a cloned device
38 * where its major device number is the major for the clone device and its minor
39 * device number is the major for the ptm driver. There are no nodes in the file
40 * system for master devices. The master pseudo driver is opened using the
41 * open(2) system call with /dev/ptmx as the device parameter. The clone open
42 * finds the next available minor device for the ptm major device.
43 *
44 * A master device is available only if it and its corresponding slave device
45 * are not already open. When the master device is opened, the corresponding
46 * slave device is automatically locked out. Only one open is allowed on a
47 * master device. Multiple opens are allowed on the slave device. After both
48 * the master and slave have been opened, the user has two file descriptors
49 * which are the end points of a full duplex connection composed of two streams
50 * which are automatically connected at the master and slave drivers. The user
51 * may then push modules onto either side of the stream pair.
91 * NULL before qprocsoff() is called during close.
92 *
93 * The pt_nullmsg field is only used in open/close routines and it is also
94 * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
95 * holds.
96 *
97 * Lock Ordering:
98 *
99 * If both ptms_lock and per-pty lock should be held, ptms_lock should always
100 * be entered first, followed by per-pty lock.
101 *
102 * See ptms.h, ptm.c and ptms_conf.c fore more information.
103 *
104 */
105
106 #include <sys/types.h>
107 #include <sys/param.h>
108 #include <sys/sysmacros.h>
109 #include <sys/stream.h>
110 #include <sys/stropts.h>
111 #include <sys/strsubr.h>
112 #include <sys/stat.h>
113 #include <sys/errno.h>
114 #include <sys/debug.h>
115 #include <sys/cmn_err.h>
116 #include <sys/ptms.h>
117 #include <sys/systm.h>
118 #include <sys/modctl.h>
119 #include <sys/conf.h>
120 #include <sys/ddi.h>
121 #include <sys/sunddi.h>
122 #include <sys/cred.h>
123 #include <sys/zone.h>
124
125 #ifdef DEBUG
126 int pts_debug = 0;
127 #define DBG(a) if (pts_debug) cmn_err(CE_NOTE, a)
128 #else
129 #define DBG(a)
130 #endif
131
323 if (ptsp->pt_zoneid != getzoneid()) {
324 mutex_exit(&ptsp->pt_lock);
325 mutex_exit(&ptms_lock);
326 return (EPERM);
327 }
328
329 /*
330 * Allow reopen of this device.
331 */
332 if (rqp->q_ptr != NULL) {
333 ASSERT(rqp->q_ptr == ptsp);
334 ASSERT(ptsp->pts_rdq == rqp);
335 mutex_exit(&ptsp->pt_lock);
336 mutex_exit(&ptms_lock);
337 return (0);
338 }
339
340 DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp);
341 DDBG("ptsopen: state = %x\n", ptsp->pt_state);
342
343 ASSERT(ptsp->pt_minor == dminor);
344
345 if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) {
346 mutex_exit(&ptsp->pt_lock);
347 mutex_exit(&ptms_lock);
348 return (EAGAIN);
349 }
350
351 /*
352 * if already open, simply return...
353 */
354 if (ptsp->pt_state & PTSOPEN) {
355 ASSERT(rqp->q_ptr == ptsp);
356 ASSERT(ptsp->pts_rdq == rqp);
357 mutex_exit(&ptsp->pt_lock);
358 mutex_exit(&ptms_lock);
359 return (0);
360 }
361
362 /*
363 * Allocate message block for setting stream head options.
364 */
365 if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
366 mutex_exit(&ptsp->pt_lock);
367 mutex_exit(&ptms_lock);
368 return (ENOMEM);
369 }
370
371 /*
372 * Slave should send zero-length message to a master when it is
373 * closing. If memory is low at that time, master will not detect slave
374 * closes, this pty will not be deallocated. So, preallocate this
375 * zero-length message block early.
376 */
377 if ((mp = allocb(0, BPRI_MED)) == NULL) {
378 mutex_exit(&ptsp->pt_lock);
379 mutex_exit(&ptms_lock);
380 freemsg(mop);
381 return (ENOMEM);
382 }
383
384 ptsp->pt_state |= PTSOPEN;
385
386 WR(rqp)->q_ptr = rqp->q_ptr = ptsp;
387
388 mutex_exit(&ptsp->pt_lock);
389 mutex_exit(&ptms_lock);
390
391 if (ptsp->pt_state & PTSTTY)
392 STREAM(rqp)->sd_flag |= STRXPG4TTY;
393
394 qprocson(rqp);
395
396 /*
397 * After qprocson pts driver is fully plumbed into the stream and can
398 * send/receive messages. Setting pts_rdq will allow master side to send
399 * messages to the slave. This setting can't occur before qprocson() is
400 * finished because slave is not ready to process them.
401 */
402 PT_ENTER_WRITE(ptsp);
403 ptsp->pts_rdq = rqp;
404 ASSERT(ptsp->pt_nullmsg == NULL);
405 ptsp->pt_nullmsg = mp;
406 PT_EXIT_WRITE(ptsp);
407
408 /*
409 * set up hi/lo water marks on stream head read queue
410 * and add controlling tty if not set
411 */
412
413 mop->b_datap->db_type = M_SETOPTS;
414 mop->b_wptr += sizeof (struct stroptions);
415 sop = (struct stroptions *)mop->b_rptr;
416 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
417 sop->so_hiwat = _TTY_BUFSIZ;
418 sop->so_lowat = 256;
419 putnext(rqp, mop);
420
421 return (0);
422 }
423
424 /*
425 * Find the address to private data identifying the slave's write
426 * queue. Send a 0-length msg up the slave's read queue to designate
427 * the master is closing. Uattach the master from the slave by nulling
428 * out master's write queue field in private data.
429 */
430 /*ARGSUSED1*/
431 static int
432 ptsclose(queue_t *rqp, int flag, cred_t *credp)
433 {
434 struct pt_ttys *ptsp;
435 queue_t *wqp;
436 mblk_t *mp;
437 mblk_t *bp;
438
439 /*
440 * q_ptr should never be NULL in the close routine and it is checked in
441 * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to
442 * behave gracefully.
443 */
|