Print this page
12306 XPG4v2 slave pty behaviour should generally be disabled
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Change-ID: I7ccd399c22866f34dd20c6bb9d28e77ba4e24c67
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/pts.c
+++ new/usr/src/uts/common/io/pts.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 26 /* All Rights Reserved */
27 27
28 +/*
29 + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
30 + */
28 31
29 -
30 32 /*
31 33 * Pseudo Terminal Slave Driver.
32 34 *
33 35 * The pseudo-tty subsystem simulates a terminal connection, where the master
34 36 * side represents the terminal and the slave represents the user process's
35 37 * special device end point. The master device is set up as a cloned device
36 38 * where its major device number is the major for the clone device and its minor
37 39 * device number is the major for the ptm driver. There are no nodes in the file
38 40 * system for master devices. The master pseudo driver is opened using the
39 41 * open(2) system call with /dev/ptmx as the device parameter. The clone open
40 42 * finds the next available minor device for the ptm major device.
41 43 *
42 44 * A master device is available only if it and its corresponding slave device
43 45 * are not already open. When the master device is opened, the corresponding
44 46 * slave device is automatically locked out. Only one open is allowed on a
45 47 * master device. Multiple opens are allowed on the slave device. After both
46 48 * the master and slave have been opened, the user has two file descriptors
47 49 * which are the end points of a full duplex connection composed of two streams
48 50 * which are automatically connected at the master and slave drivers. The user
49 51 * may then push modules onto either side of the stream pair.
50 52 *
51 53 * The master and slave drivers pass all messages to their adjacent queues.
52 54 * Only the M_FLUSH needs some processing. Because the read queue of one side
53 55 * is connected to the write queue of the other, the FLUSHR flag is changed to
54 56 * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP
55 57 * message is sent to the slave device which will render the device
56 58 * unusable. The process on the slave side gets the EIO when attempting to write
57 59 * on that stream but it will be able to read any data remaining on the stream
58 60 * head read queue. When all the data has been read, read() returns 0
59 61 * indicating that the stream can no longer be used. On the last close of the
60 62 * slave device, a 0-length message is sent to the master device. When the
61 63 * application on the master side issues a read() or getmsg() and 0 is returned,
62 64 * the user of the master device decides whether to issue a close() that
63 65 * dismantles the pseudo-terminal subsystem. If the master device is not closed,
64 66 * the pseudo-tty subsystem will be available to another user to open the slave
65 67 * device.
66 68 *
67 69 * Synchronization:
68 70 *
69 71 * All global data synchronization between ptm/pts is done via global
70 72 * ptms_lock mutex which is initialized at system boot time from
71 73 * ptms_initspace (called from space.c).
72 74 *
73 75 * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
74 76 * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
75 77 *
76 78 * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
77 79 * which allow reader locks to be reacquired by the same thread (usual
78 80 * reader/writer locks can't be used for that purpose since it is illegal for
79 81 * a thread to acquire a lock it already holds, even as a reader). The sole
80 82 * purpose of these macros is to guarantee that the peer queue will not
81 83 * disappear (due to closing peer) while it is used. It is safe to use
82 84 * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
83 85 * they are not real locks but reference counts).
84 86 *
85 87 * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
86 88 * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
87 89 * be set to appropriate queues *after* qprocson() is called during open (to
88 90 * prevent peer from accessing the queue with incomplete plumbing) and set to
89 91 * NULL before qprocsoff() is called during close.
90 92 *
91 93 * The pt_nullmsg field is only used in open/close routines and it is also
92 94 * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
93 95 * holds.
94 96 *
95 97 * Lock Ordering:
96 98 *
97 99 * If both ptms_lock and per-pty lock should be held, ptms_lock should always
98 100 * be entered first, followed by per-pty lock.
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
99 101 *
100 102 * See ptms.h, ptm.c and ptms_conf.c fore more information.
101 103 *
102 104 */
103 105
104 106 #include <sys/types.h>
105 107 #include <sys/param.h>
106 108 #include <sys/sysmacros.h>
107 109 #include <sys/stream.h>
108 110 #include <sys/stropts.h>
111 +#include <sys/strsubr.h>
109 112 #include <sys/stat.h>
110 113 #include <sys/errno.h>
111 114 #include <sys/debug.h>
112 115 #include <sys/cmn_err.h>
113 116 #include <sys/ptms.h>
114 117 #include <sys/systm.h>
115 118 #include <sys/modctl.h>
116 119 #include <sys/conf.h>
117 120 #include <sys/ddi.h>
118 121 #include <sys/sunddi.h>
119 122 #include <sys/cred.h>
120 123 #include <sys/zone.h>
121 124
122 125 #ifdef DEBUG
123 126 int pts_debug = 0;
124 127 #define DBG(a) if (pts_debug) cmn_err(CE_NOTE, a)
125 128 #else
126 129 #define DBG(a)
127 130 #endif
128 131
129 132 static int ptsopen(queue_t *, dev_t *, int, int, cred_t *);
130 133 static int ptsclose(queue_t *, int, cred_t *);
131 134 static int ptswput(queue_t *, mblk_t *);
132 135 static int ptsrsrv(queue_t *);
133 136 static int ptswsrv(queue_t *);
134 137
135 138 /*
136 139 * Slave Stream Pseudo Terminal Module: stream data structure definitions
137 140 */
138 141 static struct module_info pts_info = {
139 142 0xface,
140 143 "pts",
141 144 0,
142 145 _TTY_BUFSIZ,
143 146 _TTY_BUFSIZ,
144 147 128
145 148 };
146 149
147 150 static struct qinit ptsrint = {
148 151 NULL,
149 152 ptsrsrv,
150 153 ptsopen,
151 154 ptsclose,
152 155 NULL,
153 156 &pts_info,
154 157 NULL
155 158 };
156 159
157 160 static struct qinit ptswint = {
158 161 ptswput,
159 162 ptswsrv,
160 163 NULL,
161 164 NULL,
162 165 NULL,
163 166 &pts_info,
164 167 NULL
165 168 };
166 169
167 170 static struct streamtab ptsinfo = {
168 171 &ptsrint,
169 172 &ptswint,
170 173 NULL,
171 174 NULL
172 175 };
173 176
174 177 static int pts_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
175 178 static int pts_attach(dev_info_t *, ddi_attach_cmd_t);
176 179 static int pts_detach(dev_info_t *, ddi_detach_cmd_t);
177 180
178 181 #define PTS_CONF_FLAG (D_NEW | D_MP)
179 182
180 183 /*
181 184 * this will define (struct cb_ops cb_pts_ops) and (struct dev_ops pts_ops)
182 185 */
183 186 DDI_DEFINE_STREAM_OPS(pts_ops, nulldev, nulldev, \
184 187 pts_attach, pts_detach, nodev, \
185 188 pts_devinfo, PTS_CONF_FLAG, &ptsinfo, ddi_quiesce_not_supported);
186 189
187 190 /*
188 191 * Module linkage information for the kernel.
189 192 */
190 193
191 194 static struct modldrv modldrv = {
192 195 &mod_driverops, /* Type of module. This one is a pseudo driver */
193 196 "Slave Stream Pseudo Terminal driver 'pts'",
194 197 &pts_ops, /* driver ops */
195 198 };
196 199
197 200 static struct modlinkage modlinkage = {
198 201 MODREV_1,
199 202 &modldrv,
200 203 NULL
201 204 };
202 205
203 206 int
204 207 _init(void)
205 208 {
206 209 int rc;
207 210
208 211 if ((rc = mod_install(&modlinkage)) == 0)
209 212 ptms_init();
210 213 return (rc);
211 214 }
212 215
213 216
214 217 int
215 218 _fini(void)
216 219 {
217 220 return (mod_remove(&modlinkage));
218 221 }
219 222
220 223 int
221 224 _info(struct modinfo *modinfop)
222 225 {
223 226 return (mod_info(&modlinkage, modinfop));
224 227 }
225 228
226 229 static int
227 230 pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
228 231 {
229 232 if (cmd != DDI_ATTACH)
230 233 return (DDI_FAILURE);
231 234
232 235 mutex_enter(&ptms_lock);
233 236 pts_dip = devi;
234 237 mutex_exit(&ptms_lock);
235 238
236 239 return (DDI_SUCCESS);
237 240 }
238 241
239 242 /*ARGSUSED*/
240 243 static int
241 244 pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
242 245 {
243 246 if (cmd != DDI_DETACH)
244 247 return (DDI_FAILURE);
245 248
246 249 /*
247 250 * For now, pts cannot be detached.
248 251 */
249 252 return (DDI_FAILURE);
250 253 }
251 254
252 255 /*ARGSUSED*/
253 256 static int
254 257 pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
255 258 void **result)
256 259 {
257 260 int error;
258 261
259 262 switch (infocmd) {
260 263 case DDI_INFO_DEVT2DEVINFO:
261 264 if (pts_dip == NULL) {
262 265 error = DDI_FAILURE;
263 266 } else {
264 267 *result = (void *)pts_dip;
265 268 error = DDI_SUCCESS;
266 269 }
267 270 break;
268 271 case DDI_INFO_DEVT2INSTANCE:
269 272 *result = (void *)0;
270 273 error = DDI_SUCCESS;
271 274 break;
272 275 default:
273 276 error = DDI_FAILURE;
274 277 }
275 278 return (error);
276 279 }
277 280
278 281 /* ARGSUSED */
279 282 /*
280 283 * Open the slave device. Reject a clone open and do not allow the
281 284 * driver to be pushed. If the slave/master pair is locked or if
282 285 * the master is not open, return EACCESS.
283 286 * Upon success, store the write queue pointer in private data and
284 287 * set the PTSOPEN bit in the pt_state field.
285 288 */
286 289 static int
287 290 ptsopen(
288 291 queue_t *rqp, /* pointer to the read side queue */
289 292 dev_t *devp, /* pointer to stream tail's dev */
290 293 int oflag, /* the user open(2) supplied flags */
291 294 int sflag, /* open state flag */
292 295 cred_t *credp) /* credentials */
293 296 {
294 297 struct pt_ttys *ptsp;
295 298 mblk_t *mp;
296 299 mblk_t *mop; /* ptr to a setopts message block */
297 300 minor_t dminor = getminor(*devp);
298 301 struct stroptions *sop;
299 302
300 303 DDBG("entering ptsopen(%d)", dminor);
301 304
302 305 if (sflag != 0) {
303 306 return (EINVAL);
304 307 }
305 308
306 309 mutex_enter(&ptms_lock);
307 310 ptsp = ptms_minor2ptty(dminor);
308 311
309 312 if (ptsp == NULL) {
310 313 mutex_exit(&ptms_lock);
311 314 return (ENXIO);
312 315 }
313 316 mutex_enter(&ptsp->pt_lock);
314 317
315 318 /*
316 319 * Prevent opens from zones other than the one blessed by ptm. We
317 320 * can't even allow the global zone to open all pts's, as it would
318 321 * otherwise inproperly be able to claim pts's already opened by zones.
319 322 */
320 323 if (ptsp->pt_zoneid != getzoneid()) {
321 324 mutex_exit(&ptsp->pt_lock);
322 325 mutex_exit(&ptms_lock);
323 326 return (EPERM);
324 327 }
325 328
326 329 /*
327 330 * Allow reopen of this device.
328 331 */
329 332 if (rqp->q_ptr != NULL) {
↓ open down ↓ |
211 lines elided |
↑ open up ↑ |
330 333 ASSERT(rqp->q_ptr == ptsp);
331 334 ASSERT(ptsp->pts_rdq == rqp);
332 335 mutex_exit(&ptsp->pt_lock);
333 336 mutex_exit(&ptms_lock);
334 337 return (0);
335 338 }
336 339
337 340 DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp);
338 341 DDBG("ptsopen: state = %x\n", ptsp->pt_state);
339 342
340 -
341 343 ASSERT(ptsp->pt_minor == dminor);
342 344
343 345 if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) {
344 346 mutex_exit(&ptsp->pt_lock);
345 347 mutex_exit(&ptms_lock);
346 348 return (EAGAIN);
347 349 }
348 350
349 351 /*
350 - * if already, open simply return...
352 + * if already open, simply return...
351 353 */
352 354 if (ptsp->pt_state & PTSOPEN) {
353 355 ASSERT(rqp->q_ptr == ptsp);
354 356 ASSERT(ptsp->pts_rdq == rqp);
355 357 mutex_exit(&ptsp->pt_lock);
356 358 mutex_exit(&ptms_lock);
357 359 return (0);
358 360 }
359 361
360 362 /*
361 363 * Allocate message block for setting stream head options.
362 364 */
363 365 if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
364 366 mutex_exit(&ptsp->pt_lock);
365 367 mutex_exit(&ptms_lock);
366 368 return (ENOMEM);
367 369 }
368 370
369 371 /*
370 372 * Slave should send zero-length message to a master when it is
371 373 * closing. If memory is low at that time, master will not detect slave
372 374 * closes, this pty will not be deallocated. So, preallocate this
373 375 * zero-length message block early.
374 376 */
375 377 if ((mp = allocb(0, BPRI_MED)) == NULL) {
376 378 mutex_exit(&ptsp->pt_lock);
377 379 mutex_exit(&ptms_lock);
378 380 freemsg(mop);
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
379 381 return (ENOMEM);
380 382 }
381 383
382 384 ptsp->pt_state |= PTSOPEN;
383 385
384 386 WR(rqp)->q_ptr = rqp->q_ptr = ptsp;
385 387
386 388 mutex_exit(&ptsp->pt_lock);
387 389 mutex_exit(&ptms_lock);
388 390
391 + if (ptsp->pt_state & PTSTTY)
392 + STREAM(rqp)->sd_flag |= STRXPG4TTY;
393 +
389 394 qprocson(rqp);
390 395
391 396 /*
392 397 * After qprocson pts driver is fully plumbed into the stream and can
393 398 * send/receive messages. Setting pts_rdq will allow master side to send
394 399 * messages to the slave. This setting can't occur before qprocson() is
395 400 * finished because slave is not ready to process them.
396 401 */
397 402 PT_ENTER_WRITE(ptsp);
398 403 ptsp->pts_rdq = rqp;
399 404 ASSERT(ptsp->pt_nullmsg == NULL);
400 405 ptsp->pt_nullmsg = mp;
401 406 PT_EXIT_WRITE(ptsp);
402 407
403 408 /*
404 409 * set up hi/lo water marks on stream head read queue
405 410 * and add controlling tty if not set
406 411 */
407 412
408 413 mop->b_datap->db_type = M_SETOPTS;
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
409 414 mop->b_wptr += sizeof (struct stroptions);
410 415 sop = (struct stroptions *)mop->b_rptr;
411 416 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
412 417 sop->so_hiwat = _TTY_BUFSIZ;
413 418 sop->so_lowat = 256;
414 419 putnext(rqp, mop);
415 420
416 421 return (0);
417 422 }
418 423
419 -
420 -
421 424 /*
422 425 * Find the address to private data identifying the slave's write
423 426 * queue. Send a 0-length msg up the slave's read queue to designate
424 427 * the master is closing. Uattach the master from the slave by nulling
425 428 * out master's write queue field in private data.
426 429 */
427 430 /*ARGSUSED1*/
428 431 static int
429 432 ptsclose(queue_t *rqp, int flag, cred_t *credp)
430 433 {
431 434 struct pt_ttys *ptsp;
432 435 queue_t *wqp;
433 436 mblk_t *mp;
434 437 mblk_t *bp;
435 438
436 439 /*
437 440 * q_ptr should never be NULL in the close routine and it is checked in
438 441 * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to
439 442 * behave gracefully.
440 443 */
441 444 ASSERT(rqp->q_ptr != NULL);
442 445 if (rqp->q_ptr == NULL) {
443 446 qprocsoff(rqp);
444 447 return (0);
445 448 }
446 449
447 450 ptsp = (struct pt_ttys *)rqp->q_ptr;
448 451
449 452 /*
450 453 * Slave is going to close and doesn't want any new messages coming
451 454 * from the master side, so set pts_rdq to NULL. This should be done
452 455 * before call to qprocsoff() since slave can't process additional
453 456 * messages from the master after qprocsoff is called.
454 457 */
455 458 PT_ENTER_WRITE(ptsp);
456 459 mp = ptsp->pt_nullmsg;
457 460 ptsp->pt_nullmsg = NULL;
458 461 ptsp->pts_rdq = NULL;
459 462 PT_EXIT_WRITE(ptsp);
460 463
461 464 /*
462 465 * Drain the ouput
463 466 */
464 467 wqp = WR(rqp);
465 468 PT_ENTER_READ(ptsp);
466 469 while ((bp = getq(wqp)) != NULL) {
467 470 if (ptsp->ptm_rdq) {
468 471 putnext(ptsp->ptm_rdq, bp);
469 472 } else if (bp->b_datap->db_type == M_IOCTL) {
470 473 bp->b_datap->db_type = M_IOCNAK;
471 474 freemsg(bp->b_cont);
472 475 bp->b_cont = NULL;
473 476 qreply(wqp, bp);
474 477 } else {
475 478 freemsg(bp);
476 479 }
477 480 }
478 481 /*
479 482 * qenable master side write queue so that it can flush
480 483 * its messages as slaves's read queue is going away
481 484 */
482 485 if (ptsp->ptm_rdq) {
483 486 if (mp)
484 487 putnext(ptsp->ptm_rdq, mp);
485 488 else
486 489 qenable(WR(ptsp->ptm_rdq));
487 490 } else
488 491 freemsg(mp);
489 492 PT_EXIT_READ(ptsp);
490 493
491 494 qprocsoff(rqp);
492 495
493 496 rqp->q_ptr = NULL;
494 497 WR(rqp)->q_ptr = NULL;
495 498
496 499 ptms_close(ptsp, PTSOPEN | PTSTTY);
497 500
498 501 return (0);
499 502 }
500 503
501 504
502 505 /*
503 506 * The wput procedure will only handle flush messages.
504 507 * All other messages are queued and the write side
505 508 * service procedure sends them off to the master side.
506 509 */
507 510 static int
508 511 ptswput(queue_t *qp, mblk_t *mp)
509 512 {
510 513 struct pt_ttys *ptsp;
511 514 struct iocblk *iocp;
512 515 unsigned char type = mp->b_datap->db_type;
513 516
514 517 DBG(("entering ptswput\n"));
515 518 ASSERT(qp->q_ptr);
516 519
517 520 ptsp = (struct pt_ttys *)qp->q_ptr;
518 521 PT_ENTER_READ(ptsp);
519 522 if (ptsp->ptm_rdq == NULL) {
520 523 DBG(("in write put proc but no master\n"));
521 524 /*
522 525 * NAK ioctl as slave side read queue is gone.
523 526 * Or else free the message.
524 527 */
525 528 if (mp->b_datap->db_type == M_IOCTL) {
526 529 mp->b_datap->db_type = M_IOCNAK;
527 530 freemsg(mp->b_cont);
528 531 mp->b_cont = NULL;
529 532 qreply(qp, mp);
530 533 } else
531 534 freemsg(mp);
532 535 PT_EXIT_READ(ptsp);
533 536 return (0);
534 537 }
535 538
536 539 if (type >= QPCTL) {
537 540 switch (type) {
538 541
539 542 /*
540 543 * if write queue request, flush slave's write
541 544 * queue and send FLUSHR to ptm. If read queue
542 545 * request, send FLUSHR to ptm.
543 546 */
544 547 case M_FLUSH:
545 548 DBG(("pts got flush request\n"));
546 549 if (*mp->b_rptr & FLUSHW) {
547 550
548 551 DBG(("got FLUSHW, flush pts write Q\n"));
549 552 if (*mp->b_rptr & FLUSHBAND)
550 553 /*
551 554 * if it is a FLUSHBAND, do flushband.
552 555 */
553 556 flushband(qp, *(mp->b_rptr + 1), FLUSHDATA);
554 557 else
555 558 flushq(qp, FLUSHDATA);
556 559
557 560 *mp->b_rptr &= ~FLUSHW;
558 561 if ((*mp->b_rptr & FLUSHR) == 0) {
559 562 /*
560 563 * FLUSHW only. Change to FLUSHR and putnext
561 564 * to ptm, then we are done.
562 565 */
563 566 *mp->b_rptr |= FLUSHR;
564 567 if (ptsp->ptm_rdq)
565 568 putnext(ptsp->ptm_rdq, mp);
566 569 break;
567 570 } else {
568 571 mblk_t *nmp;
569 572
570 573 /* It is a FLUSHRW. Duplicate the mblk */
571 574 nmp = copyb(mp);
572 575 if (nmp) {
573 576 /*
574 577 * Change FLUSHW to FLUSHR before
575 578 * putnext to ptm.
576 579 */
577 580 DBG(("putnext nmp(FLUSHR) to ptm\n"));
578 581 *nmp->b_rptr |= FLUSHR;
579 582 if (ptsp->ptm_rdq)
580 583 putnext(ptsp->ptm_rdq, nmp);
581 584 }
582 585 }
583 586 }
584 587 /*
585 588 * Since the packet module will toss any
586 589 * M_FLUSHES sent to the master's stream head
587 590 * read queue, we simply turn it around here.
588 591 */
589 592 if (*mp->b_rptr & FLUSHR) {
590 593 ASSERT(RD(qp)->q_first == NULL);
591 594 DBG(("qreply(qp) turning FLUSHR around\n"));
592 595 qreply(qp, mp);
593 596 } else {
594 597 freemsg(mp);
595 598 }
596 599 break;
597 600
598 601 case M_READ:
599 602 /* Caused by ldterm - can not pass to master */
600 603 freemsg(mp);
601 604 break;
602 605
603 606 default:
604 607 if (ptsp->ptm_rdq)
605 608 putnext(ptsp->ptm_rdq, mp);
606 609 break;
607 610 }
608 611 PT_EXIT_READ(ptsp);
609 612 return (0);
610 613 }
611 614
612 615 switch (type) {
613 616
614 617 case M_IOCTL:
615 618 /*
616 619 * For case PTSSTTY set the flag PTSTTY and ACK
617 620 * the ioctl so that the user program can push
618 621 * the associated modules to get tty semantics.
619 622 * See bugid 4025044
620 623 */
621 624 iocp = (struct iocblk *)mp->b_rptr;
622 625 switch (iocp->ioc_cmd) {
623 626 default:
624 627 break;
625 628
626 629 case PTSSTTY:
627 630 if (ptsp->pt_state & PTSTTY) {
628 631 mp->b_datap->db_type = M_IOCNAK;
629 632 iocp->ioc_error = EEXIST;
630 633 } else {
631 634 mp->b_datap->db_type = M_IOCACK;
632 635 mutex_enter(&ptsp->pt_lock);
633 636 ptsp->pt_state |= PTSTTY;
634 637 mutex_exit(&ptsp->pt_lock);
635 638 iocp->ioc_error = 0;
636 639 }
637 640 iocp->ioc_count = 0;
638 641 qreply(qp, mp);
639 642 PT_EXIT_READ(ptsp);
640 643 return (0);
641 644 }
642 645 /* FALLTHROUGH */
643 646 default:
644 647 /*
645 648 * send other messages to the master
646 649 */
647 650 DBG(("put msg on slave's write queue\n"));
648 651 (void) putq(qp, mp);
649 652 break;
650 653 }
651 654
652 655 PT_EXIT_READ(ptsp);
653 656 DBG(("return from ptswput()\n"));
654 657 return (0);
655 658 }
656 659
657 660
658 661 /*
659 662 * enable the write side of the master. This triggers the
660 663 * master to send any messages queued on its write side to
661 664 * the read side of this slave.
662 665 */
663 666 static int
664 667 ptsrsrv(queue_t *qp)
665 668 {
666 669 struct pt_ttys *ptsp;
667 670
668 671 DBG(("entering ptsrsrv\n"));
669 672 ASSERT(qp->q_ptr);
670 673
671 674 ptsp = (struct pt_ttys *)qp->q_ptr;
672 675 PT_ENTER_READ(ptsp);
673 676 if (ptsp->ptm_rdq == NULL) {
674 677 DBG(("in read srv proc but no master\n"));
675 678 PT_EXIT_READ(ptsp);
676 679 return (0);
677 680 }
678 681 qenable(WR(ptsp->ptm_rdq));
679 682 PT_EXIT_READ(ptsp);
680 683 DBG(("leaving ptsrsrv\n"));
681 684 return (0);
682 685 }
683 686
684 687 /*
685 688 * If there are messages on this queue that can be sent to
686 689 * master, send them via putnext(). Else, if queued messages
687 690 * cannot be sent, leave them on this queue. If priority
688 691 * messages on this queue, send them to master no matter what.
689 692 */
690 693 static int
691 694 ptswsrv(queue_t *qp)
692 695 {
693 696 struct pt_ttys *ptsp;
694 697 queue_t *ptm_rdq;
695 698 mblk_t *mp;
696 699
697 700 DBG(("entering ptswsrv\n"));
698 701 ASSERT(qp->q_ptr);
699 702
700 703 ptsp = (struct pt_ttys *)qp->q_ptr;
701 704 PT_ENTER_READ(ptsp);
702 705 if (ptsp->ptm_rdq == NULL) {
703 706 DBG(("in write srv proc but no master\n"));
704 707 /*
705 708 * Free messages on the write queue and send
706 709 * NAK for any M_IOCTL type messages to wakeup
707 710 * the user process waiting for ACK/NAK from
708 711 * the ioctl invocation
709 712 */
710 713 while ((mp = getq(qp)) != NULL) {
711 714 if (mp->b_datap->db_type == M_IOCTL) {
712 715 mp->b_datap->db_type = M_IOCNAK;
713 716 freemsg(mp->b_cont);
714 717 mp->b_cont = NULL;
715 718 qreply(qp, mp);
716 719 } else
717 720 freemsg(mp);
718 721 }
719 722 PT_EXIT_READ(ptsp);
720 723 return (0);
721 724 } else {
722 725 ptm_rdq = ptsp->ptm_rdq;
723 726 }
724 727
725 728 /*
726 729 * while there are messages on this write queue...
727 730 */
728 731 while ((mp = getq(qp)) != NULL) {
729 732 /*
730 733 * if don't have control message and cannot put
731 734 * msg. on master's read queue, put it back on
732 735 * this queue.
733 736 */
734 737 if (mp->b_datap->db_type <= QPCTL &&
735 738 !bcanputnext(ptm_rdq, mp->b_band)) {
736 739 DBG(("put msg. back on Q\n"));
737 740 (void) putbq(qp, mp);
738 741 break;
739 742 }
740 743 /*
741 744 * else send the message up master's stream
742 745 */
743 746 DBG(("send message to master\n"));
744 747 putnext(ptm_rdq, mp);
745 748 }
746 749 DBG(("leaving ptswsrv\n"));
747 750 PT_EXIT_READ(ptsp);
748 751 return (0);
749 752 }
↓ open down ↓ |
319 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX