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