1 /* $NetBSD: tty_subr.c,v 1.43 2019/12/27 09:41:51 msaitoh Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994 Theo de Raadt 5 * All rights reserved. 6 * 7 * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working 8 * set of true clist functions that this is very loosely based on. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: tty_subr.c,v 1.43 2019/12/27 09:41:51 msaitoh Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/buf.h> 37 #include <sys/ioctl.h> 38 #include <sys/tty.h> 39 #include <sys/kmem.h> 40 41 /* 42 * At compile time, choose: 43 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is 44 * defined we allocate an array of bits -- 1/8th as much memory but 45 * setbit(), clrbit(), and isset() take more CPU. If QBITS is 46 * undefined, we just use an array of bytes. 47 * 48 * If TTY_QUOTE functionality isn't required by a line discipline, 49 * it can free c_cq and set it to NULL. This speeds things up, 50 * and also does not use any extra memory. This is useful for (say) 51 * a SLIP line discipline that wants a 32K ring buffer for data 52 * but doesn't need quoting. 53 */ 54 #define QBITS 55 56 #ifdef QBITS 57 #define QMEM(n) ((((n)-1)/NBBY)+1) 58 #else 59 #define QMEM(n) (n) 60 #endif 61 62 #ifdef QBITS 63 static void clrbits(u_char *, unsigned int, unsigned int); 64 #endif 65 66 /* 67 * Initialize a particular clist. Ok, they are really ring buffers, 68 * of the specified length, with/without quoting support. 69 */ 70 int 71 clalloc(struct clist *clp, int size, int quot) 72 { 73 74 clp->c_cs = kmem_zalloc(size, KM_SLEEP); 75 if (quot) 76 clp->c_cq = kmem_zalloc(QMEM(size), KM_SLEEP); 77 else 78 clp->c_cq = NULL; 79 80 clp->c_cf = clp->c_cl = NULL; 81 clp->c_ce = clp->c_cs + size; 82 clp->c_cn = size; 83 clp->c_cc = 0; 84 85 return (0); 86 } 87 88 void 89 clfree(struct clist *clp) 90 { 91 if (clp->c_cs) 92 kmem_free(clp->c_cs, clp->c_cn); 93 if (clp->c_cq) 94 kmem_free(clp->c_cq, QMEM(clp->c_cn)); 95 clp->c_cs = clp->c_cq = NULL; 96 } 97 98 /* 99 * Get a character from a clist. 100 */ 101 int 102 getc(struct clist *clp) 103 { 104 int c = -1; 105 int s; 106 107 s = spltty(); 108 if (clp->c_cc == 0) 109 goto out; 110 111 c = *clp->c_cf & 0xff; 112 if (clp->c_cq) { 113 #ifdef QBITS 114 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) ) 115 c |= TTY_QUOTE; 116 #else 117 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 118 c |= TTY_QUOTE; 119 #endif 120 } 121 *clp->c_cf = 0; /* wipe out to avoid information disclosure */ 122 if (++clp->c_cf == clp->c_ce) 123 clp->c_cf = clp->c_cs; 124 if (--clp->c_cc == 0) 125 clp->c_cf = clp->c_cl = (u_char *)0; 126 out: 127 splx(s); 128 return c; 129 } 130 131 /* 132 * Copy clist to buffer. 133 * Return number of bytes moved. 134 */ 135 int 136 q_to_b(struct clist *clp, u_char *cp, int count) 137 { 138 int cc; 139 u_char *p = cp; 140 int s; 141 142 s = spltty(); 143 /* optimize this while loop */ 144 while (count > 0 && clp->c_cc > 0) { 145 cc = clp->c_cl - clp->c_cf; 146 if (clp->c_cf >= clp->c_cl) 147 cc = clp->c_ce - clp->c_cf; 148 if (cc > count) 149 cc = count; 150 memcpy(p, clp->c_cf, cc); 151 count -= cc; 152 p += cc; 153 clp->c_cc -= cc; 154 clp->c_cf += cc; 155 if (clp->c_cf == clp->c_ce) 156 clp->c_cf = clp->c_cs; 157 } 158 if (clp->c_cc == 0) 159 clp->c_cf = clp->c_cl = (u_char *)0; 160 splx(s); 161 return p - cp; 162 } 163 164 /* 165 * Return count of contiguous characters in clist. 166 * Stop counting if flag&character is non-null. 167 */ 168 int 169 ndqb(struct clist *clp, int flag) 170 { 171 int count = 0; 172 int i; 173 int cc; 174 int s; 175 176 s = spltty(); 177 if ((cc = clp->c_cc) == 0) 178 goto out; 179 180 if (flag == 0) { 181 count = clp->c_cl - clp->c_cf; 182 if (count <= 0) 183 count = clp->c_ce - clp->c_cf; 184 goto out; 185 } 186 187 i = clp->c_cf - clp->c_cs; 188 if (flag & TTY_QUOTE) { 189 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) || 190 isset(clp->c_cq, i))) { 191 count++; 192 if (i == clp->c_cn) 193 break; 194 } 195 } else { 196 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) { 197 count++; 198 if (i == clp->c_cn) 199 break; 200 } 201 } 202 out: 203 splx(s); 204 return count; 205 } 206 207 /* 208 * Flush count bytes from clist. 209 */ 210 void 211 ndflush(struct clist *clp, int count) 212 { 213 int cc; 214 int s; 215 216 s = spltty(); 217 if (count == clp->c_cc) { 218 clp->c_cc = 0; 219 clp->c_cf = clp->c_cl = (u_char *)0; 220 goto out; 221 } 222 /* optimize this while loop */ 223 while (count > 0 && clp->c_cc > 0) { 224 cc = clp->c_cl - clp->c_cf; 225 if (clp->c_cf >= clp->c_cl) 226 cc = clp->c_ce - clp->c_cf; 227 if (cc > count) 228 cc = count; 229 count -= cc; 230 clp->c_cc -= cc; 231 clp->c_cf += cc; 232 if (clp->c_cf == clp->c_ce) 233 clp->c_cf = clp->c_cs; 234 } 235 if (clp->c_cc == 0) 236 clp->c_cf = clp->c_cl = (u_char *)0; 237 out: 238 splx(s); 239 } 240 241 /* 242 * Put a character into the output queue. 243 */ 244 int 245 putc(int c, struct clist *clp) 246 { 247 int i; 248 int s; 249 250 s = spltty(); 251 if (clp->c_cc == clp->c_cn) 252 goto out; 253 254 if (clp->c_cc == 0) { 255 if (!clp->c_cs) { 256 #if defined(DIAGNOSTIC) || 1 257 printf("putc: required clalloc\n"); 258 #endif 259 if (clalloc(clp, clp->c_cn, 1)) { 260 out: 261 splx(s); 262 return -1; 263 } 264 } 265 clp->c_cf = clp->c_cl = clp->c_cs; 266 } 267 268 *clp->c_cl = c & 0xff; 269 i = clp->c_cl - clp->c_cs; 270 if (clp->c_cq) { 271 #ifdef QBITS 272 if (c & TTY_QUOTE) 273 setbit(clp->c_cq, i); 274 else 275 clrbit(clp->c_cq, i); 276 #else 277 q = clp->c_cq + i; 278 *q = (c & TTY_QUOTE) ? 1 : 0; 279 #endif 280 } 281 clp->c_cc++; 282 clp->c_cl++; 283 if (clp->c_cl == clp->c_ce) 284 clp->c_cl = clp->c_cs; 285 splx(s); 286 return 0; 287 } 288 289 #ifdef QBITS 290 /* 291 * optimized version of 292 * 293 * for (i = 0; i < len; i++) 294 * clrbit(cp, off + len); 295 */ 296 static void 297 clrbits(u_char *cp, unsigned int off, unsigned int len) 298 { 299 unsigned int sbi, ebi; 300 u_char *scp, *ecp; 301 unsigned int end; 302 unsigned char mask; 303 304 scp = cp + off / NBBY; 305 sbi = off % NBBY; 306 end = off + len + NBBY - 1; 307 ecp = cp + end / NBBY - 1; 308 ebi = end % NBBY + 1; 309 if (scp >= ecp) { 310 mask = ((1 << len) - 1) << sbi; 311 *scp &= ~mask; 312 } else { 313 mask = (1 << sbi) - 1; 314 *scp++ &= mask; 315 316 mask = (1 << ebi) - 1; 317 *ecp &= ~mask; 318 319 while (scp < ecp) 320 *scp++ = 0x00; 321 } 322 } 323 #endif 324 325 /* 326 * Copy buffer to clist. 327 * Return number of bytes not transferred. 328 */ 329 int 330 b_to_q(const u_char *cp, int count, struct clist *clp) 331 { 332 int cc; 333 const u_char *p = cp; 334 int s; 335 336 if (count <= 0) 337 return 0; 338 339 s = spltty(); 340 if (clp->c_cc == clp->c_cn) 341 goto out; 342 343 if (clp->c_cc == 0) { 344 if (!clp->c_cs) { 345 #if defined(DIAGNOSTIC) || 1 346 printf("b_to_q: required clalloc\n"); 347 #endif 348 if (clalloc(clp, clp->c_cn, 1)) 349 goto out; 350 } 351 clp->c_cf = clp->c_cl = clp->c_cs; 352 } 353 354 /* optimize this while loop */ 355 while (count > 0 && clp->c_cc < clp->c_cn) { 356 cc = clp->c_ce - clp->c_cl; 357 if (clp->c_cf > clp->c_cl) 358 cc = clp->c_cf - clp->c_cl; 359 if (cc > count) 360 cc = count; 361 memcpy(clp->c_cl, p, cc); 362 if (clp->c_cq) { 363 #ifdef QBITS 364 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 365 #else 366 memset(clp->c_cl - clp->c_cs + clp->c_cq, 0, cc); 367 #endif 368 } 369 p += cc; 370 count -= cc; 371 clp->c_cc += cc; 372 clp->c_cl += cc; 373 if (clp->c_cl == clp->c_ce) 374 clp->c_cl = clp->c_cs; 375 } 376 out: 377 splx(s); 378 return count; 379 } 380 381 static int tty_global_cc; 382 383 /* 384 * Given a non-NULL pointer into the clist return the pointer 385 * to the next character in the list or return NULL if no more chars. 386 * 387 * Callers must not allow getc's to happen between firstc's and getc's 388 * so that the pointer becomes invalid. Note that interrupts are NOT 389 * masked. 390 */ 391 u_char * 392 nextc(struct clist *clp, u_char *cp, int *c) 393 { 394 395 if (clp->c_cf == cp) { 396 /* 397 * First time initialization. 398 */ 399 tty_global_cc = clp->c_cc; 400 } 401 if (tty_global_cc == 0 || cp == NULL) 402 return NULL; 403 if (--tty_global_cc == 0) 404 return NULL; 405 if (++cp == clp->c_ce) 406 cp = clp->c_cs; 407 *c = *cp & 0xff; 408 if (clp->c_cq) { 409 #ifdef QBITS 410 if (isset(clp->c_cq, cp - clp->c_cs)) 411 *c |= TTY_QUOTE; 412 #else 413 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 414 *c |= TTY_QUOTE; 415 #endif 416 } 417 return cp; 418 } 419 420 /* 421 * Given a non-NULL pointer into the clist return the pointer 422 * to the first character in the list or return NULL if no more chars. 423 * 424 * Callers must not allow getc's to happen between firstc's and getc's 425 * so that the pointer becomes invalid. Note that interrupts are NOT 426 * masked. 427 * 428 * *c is set to the NEXT character 429 */ 430 u_char * 431 firstc(struct clist *clp, int *c) 432 { 433 u_char *cp; 434 435 tty_global_cc = clp->c_cc; 436 if (tty_global_cc == 0) 437 return NULL; 438 cp = clp->c_cf; 439 *c = *cp & 0xff; 440 if (clp->c_cq) { 441 #ifdef QBITS 442 if (isset(clp->c_cq, cp - clp->c_cs)) 443 *c |= TTY_QUOTE; 444 #else 445 if (*(cp - clp->c_cs + clp->c_cq)) 446 *c |= TTY_QUOTE; 447 #endif 448 } 449 return clp->c_cf; 450 } 451 452 /* 453 * Remove the last character in the clist and return it. 454 */ 455 int 456 unputc(struct clist *clp) 457 { 458 unsigned int c = -1; 459 int s; 460 461 s = spltty(); 462 if (clp->c_cc == 0) 463 goto out; 464 465 if (clp->c_cl == clp->c_cs) 466 clp->c_cl = clp->c_ce - 1; 467 else 468 --clp->c_cl; 469 clp->c_cc--; 470 471 c = *clp->c_cl & 0xff; 472 if (clp->c_cq) { 473 #ifdef QBITS 474 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) 475 c |= TTY_QUOTE; 476 #else 477 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) 478 c |= TTY_QUOTE; 479 #endif 480 } 481 if (clp->c_cc == 0) 482 clp->c_cf = clp->c_cl = (u_char *)0; 483 out: 484 splx(s); 485 return c; 486 } 487 488 /* 489 * Put the chars in the from queue on the end of the to queue. 490 */ 491 void 492 catq(struct clist *from, struct clist *to) 493 { 494 int c; 495 496 while ((c = getc(from)) != -1) 497 putc(c, to); 498 } 499