Print this page
9042 multiples of tty streams modules cause weirdness
Reviewed by: Randy Fishel <randyf@sibernet.com>
Reviewed by: Carlos Neira <cneirabustos@gmail.com>
Approved by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/ptem.c
+++ new/usr/src/uts/common/io/ptem.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, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 23 /* All Rights Reserved */
24 24
25 25
26 26 /*
27 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 28 * Use is subject to license terms.
29 + * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
29 30 */
30 31
31 32 /*
32 33 * Description:
33 34 *
34 35 * The PTEM streams module is used as a pseudo driver emulator. Its purpose
35 36 * is to emulate the ioctl() functions of a terminal device driver.
36 37 */
37 38
38 39 #include <sys/types.h>
39 40 #include <sys/param.h>
40 41 #include <sys/stream.h>
41 42 #include <sys/stropts.h>
42 43 #include <sys/strsun.h>
43 44 #include <sys/termio.h>
44 45 #include <sys/pcb.h>
45 46 #include <sys/signal.h>
46 47 #include <sys/cred.h>
47 48 #include <sys/strtty.h>
48 49 #include <sys/errno.h>
49 50 #include <sys/cmn_err.h>
50 51 #include <sys/jioctl.h>
51 52 #include <sys/ptem.h>
52 53 #include <sys/ptms.h>
53 54 #include <sys/debug.h>
54 55 #include <sys/kmem.h>
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
55 56 #include <sys/ddi.h>
56 57 #include <sys/sunddi.h>
57 58 #include <sys/conf.h>
58 59 #include <sys/modctl.h>
59 60
60 61 extern struct streamtab pteminfo;
61 62
62 63 static struct fmodsw fsw = {
63 64 "ptem",
64 65 &pteminfo,
65 - D_MTQPAIR | D_MP
66 + D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
66 67 };
67 68
68 69 static struct modlstrmod modlstrmod = {
69 70 &mod_strmodops, "pty hardware emulator", &fsw
70 71 };
71 72
72 73 static struct modlinkage modlinkage = {
73 74 MODREV_1, &modlstrmod, NULL
74 75 };
75 76
76 77 int
77 78 _init()
78 79 {
79 80 return (mod_install(&modlinkage));
80 81 }
81 82
82 83 int
83 84 _fini()
84 85 {
85 86 return (mod_remove(&modlinkage));
86 87 }
87 88
88 89 int
89 90 _info(struct modinfo *modinfop)
90 91 {
91 92 return (mod_info(&modlinkage, modinfop));
92 93 }
93 94
94 95 /*
95 96 * stream data structure definitions
96 97 */
97 98 static int ptemopen(queue_t *, dev_t *, int, int, cred_t *);
98 99 static int ptemclose(queue_t *, int, cred_t *);
99 100 static void ptemrput(queue_t *, mblk_t *);
100 101 static void ptemwput(queue_t *, mblk_t *);
101 102 static void ptemwsrv(queue_t *);
102 103
103 104 static struct module_info ptem_info = {
104 105 0xabcd,
105 106 "ptem",
106 107 0,
107 108 _TTY_BUFSIZ,
108 109 _TTY_BUFSIZ,
109 110 128
110 111 };
111 112
112 113 static struct qinit ptemrinit = {
113 114 (int (*)()) ptemrput,
114 115 NULL,
115 116 ptemopen,
116 117 ptemclose,
117 118 NULL,
118 119 &ptem_info,
119 120 NULL
120 121 };
121 122
122 123 static struct qinit ptemwinit = {
123 124 (int (*)()) ptemwput,
124 125 (int (*)()) ptemwsrv,
125 126 ptemopen,
126 127 ptemclose,
127 128 nulldev,
128 129 &ptem_info,
129 130 NULL
130 131 };
131 132
132 133 struct streamtab pteminfo = {
133 134 &ptemrinit,
134 135 &ptemwinit,
135 136 NULL,
136 137 NULL
137 138 };
138 139
139 140 static void ptioc(queue_t *, mblk_t *, int);
140 141 static int ptemwmsg(queue_t *, mblk_t *);
141 142
142 143 /*
143 144 * ptemopen - open routine gets called when the module gets pushed onto the
144 145 * stream.
145 146 */
146 147 /* ARGSUSED */
147 148 static int
148 149 ptemopen(
149 150 queue_t *q, /* pointer to the read side queue */
150 151 dev_t *devp, /* pointer to stream tail's dev */
151 152 int oflag, /* the user open(2) supplied flags */
152 153 int sflag, /* open state flag */
153 154 cred_t *credp) /* credentials */
154 155 {
155 156 struct ptem *ntp; /* ptem entry for this PTEM module */
156 157 mblk_t *mop; /* an setopts mblk */
157 158 struct stroptions *sop;
158 159 struct termios *termiosp;
159 160 int len;
160 161
161 162 if (sflag != MODOPEN)
162 163 return (EINVAL);
163 164
164 165 if (q->q_ptr != NULL) {
165 166 /* It's already attached. */
166 167 return (0);
167 168 }
168 169
169 170 /*
170 171 * Allocate state structure.
171 172 */
172 173 ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP);
173 174
174 175 /*
175 176 * Allocate a message block, used to pass the zero length message for
176 177 * "stty 0".
177 178 *
178 179 * NOTE: it's better to find out if such a message block can be
179 180 * allocated before it's needed than to not be able to
180 181 * deliver (for possible lack of buffers) when a hang-up
181 182 * occurs.
182 183 */
183 184 if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) {
184 185 kmem_free(ntp, sizeof (*ntp));
185 186 return (EAGAIN);
186 187 }
187 188
188 189 /*
189 190 * Initialize an M_SETOPTS message to set up hi/lo water marks on
190 191 * stream head read queue and add controlling tty if not set.
191 192 */
192 193 mop = allocb(sizeof (struct stroptions), BPRI_MED);
193 194 if (mop == NULL) {
194 195 freemsg(ntp->dack_ptr);
195 196 kmem_free(ntp, sizeof (*ntp));
196 197 return (EAGAIN);
197 198 }
198 199 mop->b_datap->db_type = M_SETOPTS;
199 200 mop->b_wptr += sizeof (struct stroptions);
200 201 sop = (struct stroptions *)mop->b_rptr;
201 202 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
202 203 sop->so_hiwat = _TTY_BUFSIZ;
203 204 sop->so_lowat = 256;
204 205
205 206 /*
206 207 * Cross-link.
207 208 */
208 209 ntp->q_ptr = q;
209 210 q->q_ptr = ntp;
210 211 WR(q)->q_ptr = ntp;
211 212
212 213 /*
213 214 * Get termios defaults. These are stored as
214 215 * a property in the "options" node.
215 216 */
216 217 if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
217 218 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
218 219 len == sizeof (struct termios)) {
219 220
220 221 ntp->cflags = termiosp->c_cflag;
221 222 kmem_free(termiosp, len);
222 223 } else {
223 224 /*
224 225 * Gack! Whine about it.
225 226 */
226 227 cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!");
227 228 }
228 229 ntp->wsz.ws_row = 0;
229 230 ntp->wsz.ws_col = 0;
230 231 ntp->wsz.ws_xpixel = 0;
231 232 ntp->wsz.ws_ypixel = 0;
232 233
233 234 ntp->state = 0;
234 235
235 236 /*
236 237 * Commit to the open and send the M_SETOPTS off to the stream head.
237 238 */
238 239 qprocson(q);
239 240 putnext(q, mop);
240 241
241 242 return (0);
242 243 }
243 244
244 245
245 246 /*
246 247 * ptemclose - This routine gets called when the module gets popped off of the
247 248 * stream.
248 249 */
249 250 /* ARGSUSED */
250 251 static int
251 252 ptemclose(queue_t *q, int flag, cred_t *credp)
252 253 {
253 254 struct ptem *ntp; /* ptem entry for this PTEM module */
254 255
255 256 qprocsoff(q);
256 257 ntp = (struct ptem *)q->q_ptr;
257 258 freemsg(ntp->dack_ptr);
258 259 kmem_free(ntp, sizeof (*ntp));
259 260 q->q_ptr = WR(q)->q_ptr = NULL;
260 261 return (0);
261 262 }
262 263
263 264
264 265 /*
265 266 * ptemrput - Module read queue put procedure.
266 267 *
267 268 * This is called from the module or driver downstream.
268 269 */
269 270 static void
270 271 ptemrput(queue_t *q, mblk_t *mp)
271 272 {
272 273 struct iocblk *iocp; /* M_IOCTL data */
273 274 struct copyresp *resp; /* transparent ioctl response struct */
274 275 int error;
275 276
276 277 switch (mp->b_datap->db_type) {
277 278 case M_DELAY:
278 279 case M_READ:
279 280 freemsg(mp);
280 281 break;
281 282
282 283 case M_IOCTL:
283 284 iocp = (struct iocblk *)mp->b_rptr;
284 285
285 286 switch (iocp->ioc_cmd) {
286 287 case TCSBRK:
287 288 /*
288 289 * Send a break message upstream.
289 290 *
290 291 * XXX: Shouldn't the argument come into play in
291 292 * determining whether or not so send an M_BREAK?
292 293 * It certainly does in the write-side direction.
293 294 */
294 295 error = miocpullup(mp, sizeof (int));
295 296 if (error != 0) {
296 297 miocnak(q, mp, 0, error);
297 298 break;
298 299 }
299 300 if (!(*(int *)mp->b_cont->b_rptr)) {
300 301 if (!putnextctl(q, M_BREAK)) {
301 302 /*
302 303 * Send an NAK reply back
303 304 */
304 305 miocnak(q, mp, 0, EAGAIN);
305 306 break;
306 307 }
307 308 }
308 309 /*
309 310 * ACK it.
310 311 */
311 312 mioc2ack(mp, NULL, 0, 0);
312 313 qreply(q, mp);
313 314 break;
314 315
315 316 case JWINSIZE:
316 317 case TIOCGWINSZ:
317 318 case TIOCSWINSZ:
318 319 ptioc(q, mp, RDSIDE);
319 320 break;
320 321
321 322 case TIOCSIGNAL:
322 323 /*
323 324 * The following subtle logic is due to the fact that
324 325 * `mp' may be in any one of three distinct formats:
325 326 *
326 327 * 1. A transparent M_IOCTL with an intptr_t-sized
327 328 * payload containing the signal number.
328 329 *
329 330 * 2. An I_STR M_IOCTL with an int-sized payload
330 331 * containing the signal number.
331 332 *
332 333 * 3. An M_IOCDATA with an int-sized payload
333 334 * containing the signal number.
334 335 */
335 336 if (iocp->ioc_count == TRANSPARENT) {
336 337 intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;
337 338
338 339 if (sig < 1 || sig >= NSIG) {
339 340 /*
340 341 * it's transparent with pointer
341 342 * to the arg
342 343 */
343 344 mcopyin(mp, NULL, sizeof (int), NULL);
344 345 qreply(q, mp);
345 346 break;
346 347 }
347 348 }
348 349 ptioc(q, mp, RDSIDE);
349 350 break;
350 351
351 352 case TIOCREMOTE:
352 353 if (iocp->ioc_count != TRANSPARENT)
353 354 ptioc(q, mp, RDSIDE);
354 355 else {
355 356 mcopyin(mp, NULL, sizeof (int), NULL);
356 357 qreply(q, mp);
357 358 }
358 359 break;
359 360
360 361 default:
361 362 putnext(q, mp);
362 363 break;
363 364 }
364 365 break;
365 366
366 367 case M_IOCDATA:
367 368 resp = (struct copyresp *)mp->b_rptr;
368 369 if (resp->cp_rval) {
369 370 /*
370 371 * Just free message on failure.
371 372 */
372 373 freemsg(mp);
373 374 break;
374 375 }
375 376
376 377 /*
377 378 * Only need to copy data for the SET case.
378 379 */
379 380 switch (resp->cp_cmd) {
380 381
381 382 case TIOCSWINSZ:
382 383 case TIOCSIGNAL:
383 384 case TIOCREMOTE:
384 385 ptioc(q, mp, RDSIDE);
385 386 break;
386 387
387 388 case JWINSIZE:
388 389 case TIOCGWINSZ:
389 390 mp->b_datap->db_type = M_IOCACK;
390 391 mioc2ack(mp, NULL, 0, 0);
391 392 qreply(q, mp);
392 393 break;
393 394
394 395 default:
395 396 freemsg(mp);
396 397 break;
397 398 }
398 399 break;
399 400
400 401 case M_IOCACK:
401 402 case M_IOCNAK:
402 403 /*
403 404 * We only pass write-side ioctls through to the master that
404 405 * we've already ACKed or NAKed to the stream head. Thus, we
405 406 * discard ones arriving from below, since they're redundant
406 407 * from the point of view of modules above us.
407 408 */
408 409 freemsg(mp);
409 410 break;
410 411
411 412 case M_HANGUP:
412 413 /*
413 414 * clear blocked state.
414 415 */
415 416 {
416 417 struct ptem *ntp = (struct ptem *)q->q_ptr;
417 418 if (ntp->state & OFLOW_CTL) {
418 419 ntp->state &= ~OFLOW_CTL;
419 420 qenable(WR(q));
420 421 }
421 422 }
422 423 default:
423 424 putnext(q, mp);
424 425 break;
425 426 }
426 427 }
427 428
428 429
429 430 /*
430 431 * ptemwput - Module write queue put procedure.
431 432 *
432 433 * This is called from the module or stream head upstream.
433 434 *
434 435 * XXX: This routine is quite lazy about handling allocation failures,
435 436 * basically just giving up and reporting failure. It really ought to
436 437 * set up bufcalls and only fail when it's absolutely necessary.
437 438 */
438 439 static void
439 440 ptemwput(queue_t *q, mblk_t *mp)
440 441 {
441 442 struct ptem *ntp = (struct ptem *)q->q_ptr;
442 443 struct iocblk *iocp; /* outgoing ioctl structure */
443 444 struct copyresp *resp;
444 445 unsigned char type = mp->b_datap->db_type;
445 446
446 447 if (type >= QPCTL) {
447 448 switch (type) {
448 449
449 450 case M_IOCDATA:
450 451 resp = (struct copyresp *)mp->b_rptr;
451 452 if (resp->cp_rval) {
452 453 /*
453 454 * Just free message on failure.
454 455 */
455 456 freemsg(mp);
456 457 break;
457 458 }
458 459
459 460 /*
460 461 * Only need to copy data for the SET case.
461 462 */
462 463 switch (resp->cp_cmd) {
463 464
464 465 case TIOCSWINSZ:
465 466 ptioc(q, mp, WRSIDE);
466 467 break;
467 468
468 469 case JWINSIZE:
469 470 case TIOCGWINSZ:
470 471 mioc2ack(mp, NULL, 0, 0);
471 472 qreply(q, mp);
472 473 break;
473 474
474 475 default:
475 476 freemsg(mp);
476 477 }
477 478 break;
478 479
479 480 case M_FLUSH:
480 481 if (*mp->b_rptr & FLUSHW) {
481 482 if ((ntp->state & IS_PTSTTY) &&
482 483 (*mp->b_rptr & FLUSHBAND))
483 484 flushband(q, *(mp->b_rptr + 1),
484 485 FLUSHDATA);
485 486 else
486 487 flushq(q, FLUSHDATA);
487 488 }
488 489 putnext(q, mp);
489 490 break;
490 491
491 492 case M_READ:
492 493 freemsg(mp);
493 494 break;
494 495
495 496 case M_STOP:
496 497 /*
497 498 * Set the output flow control state.
498 499 */
499 500 ntp->state |= OFLOW_CTL;
500 501 putnext(q, mp);
501 502 break;
502 503
503 504 case M_START:
504 505 /*
505 506 * Relieve the output flow control state.
506 507 */
507 508 ntp->state &= ~OFLOW_CTL;
508 509 putnext(q, mp);
509 510 qenable(q);
510 511 break;
511 512 default:
512 513 putnext(q, mp);
513 514 break;
514 515 }
515 516 return;
516 517 }
517 518 /*
518 519 * If our queue is nonempty or flow control persists
519 520 * downstream or module in stopped state, queue this message.
520 521 */
521 522 if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
522 523 /*
523 524 * Exception: ioctls, except for those defined to
524 525 * take effect after output has drained, should be
525 526 * processed immediately.
526 527 */
527 528 switch (type) {
528 529
529 530 case M_IOCTL:
530 531 iocp = (struct iocblk *)mp->b_rptr;
531 532 switch (iocp->ioc_cmd) {
532 533 /*
533 534 * Queue these.
534 535 */
535 536 case TCSETSW:
536 537 case TCSETSF:
537 538 case TCSETAW:
538 539 case TCSETAF:
539 540 case TCSBRK:
540 541 break;
541 542
542 543 /*
543 544 * Handle all others immediately.
544 545 */
545 546 default:
546 547 (void) ptemwmsg(q, mp);
547 548 return;
548 549 }
549 550 break;
550 551
551 552 case M_DELAY: /* tty delays not supported */
552 553 freemsg(mp);
553 554 return;
554 555
555 556 case M_DATA:
556 557 if ((mp->b_wptr - mp->b_rptr) < 0) {
557 558 /*
558 559 * Free all bad length messages.
559 560 */
560 561 freemsg(mp);
561 562 return;
562 563 } else if ((mp->b_wptr - mp->b_rptr) == 0) {
563 564 if (!(ntp->state & IS_PTSTTY)) {
564 565 freemsg(mp);
565 566 return;
566 567 }
567 568 }
568 569 }
569 570 (void) putq(q, mp);
570 571 return;
571 572 }
572 573 /*
573 574 * fast path into ptemwmsg to dispose of mp.
574 575 */
575 576 if (!ptemwmsg(q, mp))
576 577 (void) putq(q, mp);
577 578 }
578 579
579 580 /*
580 581 * ptem write queue service procedure.
581 582 */
582 583 static void
583 584 ptemwsrv(queue_t *q)
584 585 {
585 586 mblk_t *mp;
586 587
587 588 while ((mp = getq(q)) != NULL) {
588 589 if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
589 590 (void) putbq(q, mp);
590 591 break;
591 592 }
592 593 }
593 594 }
594 595
595 596
596 597 /*
597 598 * This routine is called from both ptemwput and ptemwsrv to do the
598 599 * actual work of dealing with mp. ptmewput will have already
599 600 * dealt with high priority messages.
600 601 *
601 602 * Return 1 if the message was processed completely and 0 if not.
602 603 */
603 604 static int
604 605 ptemwmsg(queue_t *q, mblk_t *mp)
605 606 {
606 607 struct ptem *ntp = (struct ptem *)q->q_ptr;
607 608 struct iocblk *iocp; /* outgoing ioctl structure */
608 609 struct termio *termiop;
609 610 struct termios *termiosp;
610 611 mblk_t *dack_ptr; /* disconnect message ACK block */
611 612 mblk_t *pckt_msgp; /* message sent to the PCKT module */
612 613 mblk_t *dp; /* ioctl reply data */
613 614 tcflag_t cflags;
614 615 int error;
615 616
616 617 switch (mp->b_datap->db_type) {
617 618
618 619 case M_IOCTL:
619 620 /*
620 621 * Note: for each "set" type operation a copy
621 622 * of the M_IOCTL message is made and passed
622 623 * downstream. Eventually the PCKT module, if
623 624 * it has been pushed, should pick up this message.
624 625 * If the PCKT module has not been pushed the master
625 626 * side stream head will free it.
626 627 */
627 628 iocp = (struct iocblk *)mp->b_rptr;
628 629 switch (iocp->ioc_cmd) {
629 630
630 631 case TCSETAF:
631 632 case TCSETSF:
632 633 /*
633 634 * Flush the read queue.
634 635 */
635 636 if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
636 637 miocnak(q, mp, 0, EAGAIN);
637 638 break;
638 639 }
639 640 /* FALLTHROUGH */
640 641
641 642 case TCSETA:
642 643 case TCSETAW:
643 644 case TCSETS:
644 645 case TCSETSW:
645 646
646 647 switch (iocp->ioc_cmd) {
647 648 case TCSETAF:
648 649 case TCSETA:
649 650 case TCSETAW:
650 651 error = miocpullup(mp, sizeof (struct termio));
651 652 if (error != 0) {
652 653 miocnak(q, mp, 0, error);
653 654 goto out;
654 655 }
655 656 cflags = ((struct termio *)
656 657 mp->b_cont->b_rptr)->c_cflag;
657 658 ntp->cflags =
658 659 (ntp->cflags & 0xffff0000 | cflags);
659 660 break;
660 661
661 662 case TCSETSF:
662 663 case TCSETS:
663 664 case TCSETSW:
664 665 error = miocpullup(mp, sizeof (struct termios));
665 666 if (error != 0) {
666 667 miocnak(q, mp, 0, error);
667 668 goto out;
668 669 }
669 670 cflags = ((struct termios *)
670 671 mp->b_cont->b_rptr)->c_cflag;
671 672 ntp->cflags = cflags;
672 673 break;
673 674 }
674 675
675 676 if ((cflags & CBAUD) == B0) {
676 677 /*
677 678 * Hang-up: Send a zero length message.
678 679 */
679 680 dack_ptr = ntp->dack_ptr;
680 681
681 682 if (dack_ptr) {
682 683 ntp->dack_ptr = NULL;
683 684 /*
684 685 * Send a zero length message
685 686 * downstream.
686 687 */
687 688 putnext(q, dack_ptr);
688 689 }
689 690 } else {
690 691 /*
691 692 * Make a copy of this message and pass it on
692 693 * to the PCKT module.
693 694 */
694 695 if ((pckt_msgp = copymsg(mp)) == NULL) {
695 696 miocnak(q, mp, 0, EAGAIN);
696 697 break;
697 698 }
698 699 putnext(q, pckt_msgp);
699 700 }
700 701 /*
701 702 * Send ACK upstream.
702 703 */
703 704 mioc2ack(mp, NULL, 0, 0);
704 705 qreply(q, mp);
705 706 out:
706 707 break;
707 708
708 709 case TCGETA:
709 710 dp = allocb(sizeof (struct termio), BPRI_MED);
710 711 if (dp == NULL) {
711 712 miocnak(q, mp, 0, EAGAIN);
712 713 break;
713 714 }
714 715 termiop = (struct termio *)dp->b_rptr;
715 716 termiop->c_cflag = (ushort_t)ntp->cflags;
716 717 mioc2ack(mp, dp, sizeof (struct termio), 0);
717 718 qreply(q, mp);
718 719 break;
719 720
720 721 case TCGETS:
721 722 dp = allocb(sizeof (struct termios), BPRI_MED);
722 723 if (dp == NULL) {
723 724 miocnak(q, mp, 0, EAGAIN);
724 725 break;
725 726 }
726 727 termiosp = (struct termios *)dp->b_rptr;
727 728 termiosp->c_cflag = ntp->cflags;
728 729 mioc2ack(mp, dp, sizeof (struct termios), 0);
729 730 qreply(q, mp);
730 731 break;
731 732
732 733 case TCSBRK:
733 734 error = miocpullup(mp, sizeof (int));
734 735 if (error != 0) {
735 736 miocnak(q, mp, 0, error);
736 737 break;
737 738 }
738 739
739 740 /*
740 741 * Need a copy of this message to pass it on to
741 742 * the PCKT module.
742 743 */
743 744 if ((pckt_msgp = copymsg(mp)) == NULL) {
744 745 miocnak(q, mp, 0, EAGAIN);
745 746 break;
746 747 }
747 748 /*
748 749 * Send a copy of the M_IOCTL to the PCKT module.
749 750 */
750 751 putnext(q, pckt_msgp);
751 752
752 753 /*
753 754 * TCSBRK meaningful if data part of message is 0
754 755 * cf. termio(7).
755 756 */
756 757 if (!(*(int *)mp->b_cont->b_rptr))
757 758 (void) putnextctl(q, M_BREAK);
758 759 /*
759 760 * ACK the ioctl.
760 761 */
761 762 mioc2ack(mp, NULL, 0, 0);
762 763 qreply(q, mp);
763 764 break;
764 765
765 766 case JWINSIZE:
766 767 case TIOCGWINSZ:
767 768 case TIOCSWINSZ:
768 769 ptioc(q, mp, WRSIDE);
769 770 break;
770 771
771 772 case TIOCSTI:
772 773 /*
773 774 * Simulate typing of a character at the terminal. In
774 775 * all cases, we acknowledge the ioctl and pass a copy
775 776 * of it along for the PCKT module to encapsulate. If
776 777 * not in remote mode, we also process the ioctl
777 778 * itself, looping the character given as its argument
778 779 * back around to the read side.
779 780 */
780 781
781 782 /*
782 783 * Need a copy of this message to pass on to the PCKT
783 784 * module.
784 785 */
785 786 if ((pckt_msgp = copymsg(mp)) == NULL) {
786 787 miocnak(q, mp, 0, EAGAIN);
787 788 break;
788 789 }
789 790 if ((ntp->state & REMOTEMODE) == 0) {
790 791 mblk_t *bp;
791 792
792 793 error = miocpullup(mp, sizeof (char));
793 794 if (error != 0) {
794 795 freemsg(pckt_msgp);
795 796 miocnak(q, mp, 0, error);
796 797 break;
797 798 }
798 799
799 800 /*
800 801 * The permission checking has already been
801 802 * done at the stream head, since it has to be
802 803 * done in the context of the process doing
803 804 * the call.
804 805 */
805 806 if ((bp = allocb(1, BPRI_MED)) == NULL) {
806 807 freemsg(pckt_msgp);
807 808 miocnak(q, mp, 0, EAGAIN);
808 809 break;
809 810 }
810 811 /*
811 812 * XXX: Is EAGAIN really the right response to
812 813 * flow control blockage?
813 814 */
814 815 if (!bcanputnext(RD(q), mp->b_band)) {
815 816 freemsg(bp);
816 817 freemsg(pckt_msgp);
817 818 miocnak(q, mp, 0, EAGAIN);
818 819 break;
819 820 }
820 821 *bp->b_wptr++ = *mp->b_cont->b_rptr;
821 822 qreply(q, bp);
822 823 }
823 824
824 825 putnext(q, pckt_msgp);
825 826 mioc2ack(mp, NULL, 0, 0);
826 827 qreply(q, mp);
827 828 break;
828 829
829 830 case PTSSTTY:
830 831 if (ntp->state & IS_PTSTTY) {
831 832 miocnak(q, mp, 0, EEXIST);
832 833 } else {
833 834 ntp->state |= IS_PTSTTY;
834 835 mioc2ack(mp, NULL, 0, 0);
835 836 qreply(q, mp);
836 837 }
837 838 break;
838 839
839 840 default:
840 841 /*
841 842 * End of the line. The slave driver doesn't see any
842 843 * ioctls that we don't explicitly pass along to it.
843 844 */
844 845 miocnak(q, mp, 0, EINVAL);
845 846 break;
846 847 }
847 848 break;
848 849
849 850 case M_DELAY: /* tty delays not supported */
850 851 freemsg(mp);
851 852 break;
852 853
853 854 case M_DATA:
854 855 if ((mp->b_wptr - mp->b_rptr) < 0) {
855 856 /*
856 857 * Free all bad length messages.
857 858 */
858 859 freemsg(mp);
859 860 break;
860 861 } else if ((mp->b_wptr - mp->b_rptr) == 0) {
861 862 if (!(ntp->state & IS_PTSTTY)) {
862 863 freemsg(mp);
863 864 break;
864 865 }
865 866 }
866 867 if (ntp->state & OFLOW_CTL)
867 868 return (0);
868 869
869 870 default:
870 871 putnext(q, mp);
871 872 break;
872 873
873 874 }
874 875
875 876 return (1);
876 877 }
877 878
878 879 /*
879 880 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
880 881 */
881 882 static void
882 883 ptioc(queue_t *q, mblk_t *mp, int qside)
883 884 {
884 885 struct ptem *tp;
885 886 struct iocblk *iocp;
886 887 struct winsize *wb;
887 888 struct jwinsize *jwb;
888 889 mblk_t *tmp;
889 890 mblk_t *pckt_msgp; /* message sent to the PCKT module */
890 891 int error;
891 892
892 893 iocp = (struct iocblk *)mp->b_rptr;
893 894 tp = (struct ptem *)q->q_ptr;
894 895
895 896 switch (iocp->ioc_cmd) {
896 897
897 898 case JWINSIZE:
898 899 /*
899 900 * For compatibility: If all zeros, NAK the message for dumb
900 901 * terminals.
901 902 */
902 903 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
903 904 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
904 905 miocnak(q, mp, 0, EINVAL);
905 906 return;
906 907 }
907 908
908 909 tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
909 910 if (tmp == NULL) {
910 911 miocnak(q, mp, 0, EAGAIN);
911 912 return;
912 913 }
913 914
914 915 if (iocp->ioc_count == TRANSPARENT)
915 916 mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
916 917 else
917 918 mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
918 919
919 920 jwb = (struct jwinsize *)mp->b_cont->b_rptr;
920 921 jwb->bytesx = tp->wsz.ws_col;
921 922 jwb->bytesy = tp->wsz.ws_row;
922 923 jwb->bitsx = tp->wsz.ws_xpixel;
923 924 jwb->bitsy = tp->wsz.ws_ypixel;
924 925
925 926 qreply(q, mp);
926 927 return;
927 928
928 929 case TIOCGWINSZ:
929 930 /*
930 931 * If all zeros NAK the message for dumb terminals.
931 932 */
932 933 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
933 934 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
934 935 miocnak(q, mp, 0, EINVAL);
935 936 return;
936 937 }
937 938
938 939 tmp = allocb(sizeof (struct winsize), BPRI_MED);
939 940 if (tmp == NULL) {
940 941 miocnak(q, mp, 0, EAGAIN);
941 942 return;
942 943 }
943 944
944 945 mioc2ack(mp, tmp, sizeof (struct winsize), 0);
945 946
946 947 wb = (struct winsize *)mp->b_cont->b_rptr;
947 948 wb->ws_row = tp->wsz.ws_row;
948 949 wb->ws_col = tp->wsz.ws_col;
949 950 wb->ws_xpixel = tp->wsz.ws_xpixel;
950 951 wb->ws_ypixel = tp->wsz.ws_ypixel;
951 952
952 953 qreply(q, mp);
953 954 return;
954 955
955 956 case TIOCSWINSZ:
956 957 error = miocpullup(mp, sizeof (struct winsize));
957 958 if (error != 0) {
958 959 miocnak(q, mp, 0, error);
959 960 return;
960 961 }
961 962
962 963 wb = (struct winsize *)mp->b_cont->b_rptr;
963 964 /*
964 965 * Send a SIGWINCH signal if the row/col information has
965 966 * changed.
966 967 */
967 968 if ((tp->wsz.ws_row != wb->ws_row) ||
968 969 (tp->wsz.ws_col != wb->ws_col) ||
969 970 (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
970 971 (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
971 972 /*
972 973 * SIGWINCH is always sent upstream.
973 974 */
974 975 if (qside == WRSIDE)
975 976 (void) putnextctl1(RD(q), M_SIG, SIGWINCH);
976 977 else if (qside == RDSIDE)
977 978 (void) putnextctl1(q, M_SIG, SIGWINCH);
978 979 /*
979 980 * Message may have come in as an M_IOCDATA; pass it
980 981 * to the master side as an M_IOCTL.
981 982 */
982 983 mp->b_datap->db_type = M_IOCTL;
983 984 if (qside == WRSIDE) {
984 985 /*
985 986 * Need a copy of this message to pass on to
986 987 * the PCKT module, only if the M_IOCTL
987 988 * orginated from the slave side.
988 989 */
989 990 if ((pckt_msgp = copymsg(mp)) == NULL) {
990 991 miocnak(q, mp, 0, EAGAIN);
991 992 return;
992 993 }
993 994 putnext(q, pckt_msgp);
994 995 }
995 996 tp->wsz.ws_row = wb->ws_row;
996 997 tp->wsz.ws_col = wb->ws_col;
997 998 tp->wsz.ws_xpixel = wb->ws_xpixel;
998 999 tp->wsz.ws_ypixel = wb->ws_ypixel;
999 1000 }
1000 1001
1001 1002 mioc2ack(mp, NULL, 0, 0);
1002 1003 qreply(q, mp);
1003 1004 return;
1004 1005
1005 1006 case TIOCSIGNAL: {
1006 1007 /*
1007 1008 * This ioctl can emanate from the master side in remote
1008 1009 * mode only.
1009 1010 */
1010 1011 int sig;
1011 1012
1012 1013 if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1013 1014 error = miocpullup(mp, sizeof (int));
1014 1015 if (error != 0) {
1015 1016 miocnak(q, mp, 0, error);
1016 1017 return;
1017 1018 }
1018 1019 }
1019 1020
1020 1021 if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1021 1022 sig = *(int *)mp->b_cont->b_rptr;
1022 1023 else
1023 1024 sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1024 1025
1025 1026 if (sig < 1 || sig >= NSIG) {
1026 1027 miocnak(q, mp, 0, EINVAL);
1027 1028 return;
1028 1029 }
1029 1030
1030 1031 /*
1031 1032 * Send an M_PCSIG message up the slave's read side and
1032 1033 * respond back to the master with an ACK or NAK as
1033 1034 * appropriate.
1034 1035 */
1035 1036 if (putnextctl1(q, M_PCSIG, sig) == 0) {
1036 1037 miocnak(q, mp, 0, EAGAIN);
1037 1038 return;
1038 1039 }
1039 1040
1040 1041 mioc2ack(mp, NULL, 0, 0);
1041 1042 qreply(q, mp);
1042 1043 return;
1043 1044 }
1044 1045
1045 1046 case TIOCREMOTE: {
1046 1047 int onoff;
1047 1048 mblk_t *mctlp;
1048 1049
1049 1050 if (DB_TYPE(mp) == M_IOCTL) {
1050 1051 error = miocpullup(mp, sizeof (int));
1051 1052 if (error != 0) {
1052 1053 miocnak(q, mp, 0, error);
1053 1054 return;
1054 1055 }
1055 1056 }
1056 1057
1057 1058 onoff = *(int *)mp->b_cont->b_rptr;
1058 1059
1059 1060 /*
1060 1061 * Send M_CTL up using the iocblk format.
1061 1062 */
1062 1063 mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1063 1064 if (mctlp == NULL) {
1064 1065 miocnak(q, mp, 0, EAGAIN);
1065 1066 return;
1066 1067 }
1067 1068 mctlp->b_datap->db_type = M_CTL;
1068 1069 putnext(q, mctlp);
1069 1070
1070 1071 /*
1071 1072 * ACK the ioctl.
1072 1073 */
1073 1074 mioc2ack(mp, NULL, 0, 0);
1074 1075 qreply(q, mp);
1075 1076
1076 1077 /*
1077 1078 * Record state change.
1078 1079 */
1079 1080 if (onoff)
1080 1081 tp->state |= REMOTEMODE;
1081 1082 else
1082 1083 tp->state &= ~REMOTEMODE;
1083 1084 return;
1084 1085 }
1085 1086
1086 1087 default:
1087 1088 putnext(q, mp);
1088 1089 return;
1089 1090 }
1090 1091 }
|
↓ open down ↓ |
1015 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX