1 /* $OpenBSD: tty_subr.c,v 1.36 2022/08/14 01:58:28 jsg 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/tty.h>
35 #include <sys/malloc.h>
36
37 /*
38 * If TTY_QUOTE functionality isn't required by a line discipline,
39 * it can free c_cq and set it to NULL. This speeds things up,
40 * and also does not use any extra memory. This is useful for (say)
41 * a SLIP line discipline that wants a 32K ring buffer for data
42 * but doesn't need quoting.
43 */
44 #define QMEM(n) ((((n)-1)/NBBY)+1)
45
46 void clrbits(u_char *, int, int);
47
48 /*
49 * Initialize a particular clist. Ok, they are really ring buffers,
50 * of the specified length, with/without quoting support.
51 */
52 void
clalloc(struct clist * clp,int size,int quot)53 clalloc(struct clist *clp, int size, int quot)
54 {
55
56 clp->c_cs = malloc(size, M_TTYS, M_WAITOK|M_ZERO);
57
58 if (quot)
59 clp->c_cq = malloc(QMEM(size), M_TTYS, M_WAITOK|M_ZERO);
60 else
61 clp->c_cq = NULL;
62
63 clp->c_cf = clp->c_cl = NULL;
64 clp->c_ce = clp->c_cs + size;
65 clp->c_cn = size;
66 clp->c_cc = 0;
67 }
68
69 void
clfree(struct clist * clp)70 clfree(struct clist *clp)
71 {
72 if (clp->c_cs) {
73 explicit_bzero(clp->c_cs, clp->c_cn);
74 free(clp->c_cs, M_TTYS, clp->c_cn);
75 }
76 if (clp->c_cq) {
77 explicit_bzero(clp->c_cq, QMEM(clp->c_cn));
78 free(clp->c_cq, M_TTYS, QMEM(clp->c_cn));
79 }
80 clp->c_cs = clp->c_cq = NULL;
81 }
82
83
84 /*
85 * Get a character from a clist.
86 */
87 int
getc(struct clist * clp)88 getc(struct clist *clp)
89 {
90 int c = -1;
91 int s;
92
93 s = spltty();
94 if (clp->c_cc == 0)
95 goto out;
96
97 c = *clp->c_cf & 0xff;
98 *clp->c_cf = 0;
99 if (clp->c_cq) {
100 if (isset(clp->c_cq, clp->c_cf - clp->c_cs))
101 c |= TTY_QUOTE;
102 clrbit(clp->c_cq, clp->c_cf - clp->c_cs);
103 }
104 if (++clp->c_cf == clp->c_ce)
105 clp->c_cf = clp->c_cs;
106 if (--clp->c_cc == 0)
107 clp->c_cf = clp->c_cl = NULL;
108 out:
109 splx(s);
110 return c;
111 }
112
113 /*
114 * Copy clist to buffer.
115 * Return number of bytes moved.
116 */
117 int
q_to_b(struct clist * clp,u_char * cp,int count)118 q_to_b(struct clist *clp, u_char *cp, int count)
119 {
120 int cc;
121 u_char *p = cp;
122 int s;
123
124 s = spltty();
125 /* optimize this while loop */
126 while (count > 0 && clp->c_cc > 0) {
127 cc = clp->c_cl - clp->c_cf;
128 if (clp->c_cf >= clp->c_cl)
129 cc = clp->c_ce - clp->c_cf;
130 if (cc > count)
131 cc = count;
132 memcpy(p, clp->c_cf, cc);
133 memset(clp->c_cf, 0, cc);
134 if (clp->c_cq)
135 clrbits(clp->c_cq, clp->c_cf - clp->c_cs, cc);
136 count -= cc;
137 p += cc;
138 clp->c_cc -= cc;
139 clp->c_cf += cc;
140 if (clp->c_cf == clp->c_ce)
141 clp->c_cf = clp->c_cs;
142 }
143 if (clp->c_cc == 0)
144 clp->c_cf = clp->c_cl = NULL;
145 splx(s);
146 return p - cp;
147 }
148
149 /*
150 * Return count of contiguous characters in clist.
151 * Stop counting if flag&character is non-null.
152 */
153 int
ndqb(struct clist * clp,int flag)154 ndqb(struct clist *clp, int flag)
155 {
156 int count = 0;
157 int i;
158 int cc;
159 int s;
160
161 s = spltty();
162 if ((cc = clp->c_cc) == 0)
163 goto out;
164
165 if (flag == 0) {
166 count = clp->c_cl - clp->c_cf;
167 if (count <= 0)
168 count = clp->c_ce - clp->c_cf;
169 goto out;
170 }
171
172 i = clp->c_cf - clp->c_cs;
173 if (flag & TTY_QUOTE) {
174 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
175 isset(clp->c_cq, i))) {
176 count++;
177 if (i == clp->c_cn)
178 break;
179 }
180 } else {
181 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
182 count++;
183 if (i == clp->c_cn)
184 break;
185 }
186 }
187 out:
188 splx(s);
189 return count;
190 }
191
192 /*
193 * Flush count bytes from clist.
194 */
195 void
ndflush(struct clist * clp,int count)196 ndflush(struct clist *clp, int count)
197 {
198 int cc;
199 int s;
200
201 s = spltty();
202 if (count == clp->c_cc) {
203 clp->c_cc = 0;
204 clp->c_cf = clp->c_cl = NULL;
205 goto out;
206 }
207 /* optimize this while loop */
208 while (count > 0 && clp->c_cc > 0) {
209 cc = clp->c_cl - clp->c_cf;
210 if (clp->c_cf >= clp->c_cl)
211 cc = clp->c_ce - clp->c_cf;
212 if (cc > count)
213 cc = count;
214 count -= cc;
215 clp->c_cc -= cc;
216 clp->c_cf += cc;
217 if (clp->c_cf == clp->c_ce)
218 clp->c_cf = clp->c_cs;
219 }
220 if (clp->c_cc == 0)
221 clp->c_cf = clp->c_cl = NULL;
222 out:
223 splx(s);
224 }
225
226 /*
227 * Put a character into the output queue.
228 */
229 int
putc(int c,struct clist * clp)230 putc(int c, struct clist *clp)
231 {
232 int i;
233 int s;
234
235 s = spltty();
236 if (clp->c_cc == clp->c_cn) {
237 splx(s);
238 return -1;
239 }
240
241 if (clp->c_cc == 0) {
242 if (!clp->c_cs)
243 panic("%s: tty has no clist", __func__);
244 clp->c_cf = clp->c_cl = clp->c_cs;
245 }
246
247 *clp->c_cl = c & 0xff;
248 i = clp->c_cl - clp->c_cs;
249 if (clp->c_cq) {
250 if (c & TTY_QUOTE)
251 setbit(clp->c_cq, i);
252 else
253 clrbit(clp->c_cq, i);
254 }
255 clp->c_cc++;
256 clp->c_cl++;
257 if (clp->c_cl == clp->c_ce)
258 clp->c_cl = clp->c_cs;
259 splx(s);
260 return 0;
261 }
262
263 /*
264 * optimized version of
265 *
266 * for (i = 0; i < len; i++)
267 * clrbit(cp, off + i);
268 */
269 void
clrbits(u_char * cp,int off,int len)270 clrbits(u_char *cp, int off, int len)
271 {
272 int sby, sbi, eby, ebi;
273 int i;
274 u_char mask;
275
276 if (len==1) {
277 clrbit(cp, off);
278 return;
279 }
280
281 sby = off / NBBY;
282 sbi = off % NBBY;
283 eby = (off+len) / NBBY;
284 ebi = (off+len) % NBBY;
285 if (sby == eby) {
286 mask = ((1 << (ebi - sbi)) - 1) << sbi;
287 cp[sby] &= ~mask;
288 } else {
289 mask = (1<<sbi) - 1;
290 cp[sby++] &= mask;
291
292 for (i = sby; i < eby; i++)
293 cp[i] = 0x00;
294
295 mask = (1<<ebi) - 1;
296 if (mask) /* if no mask, eby may be 1 too far */
297 cp[eby] &= ~mask;
298
299 }
300 }
301
302 /*
303 * Copy buffer to clist.
304 * Return number of bytes not transferred.
305 */
306 int
b_to_q(u_char * cp,int count,struct clist * clp)307 b_to_q(u_char *cp, int count, struct clist *clp)
308 {
309 int cc;
310 u_char *p = cp;
311 int s;
312
313 if (count <= 0)
314 return 0;
315
316 s = spltty();
317 if (clp->c_cc == clp->c_cn)
318 goto out;
319
320 if (clp->c_cc == 0) {
321 if (!clp->c_cs)
322 panic("%s: tty has no clist", __func__);
323 clp->c_cf = clp->c_cl = clp->c_cs;
324 }
325
326 /* optimize this while loop */
327 while (count > 0 && clp->c_cc < clp->c_cn) {
328 cc = clp->c_ce - clp->c_cl;
329 if (clp->c_cf > clp->c_cl)
330 cc = clp->c_cf - clp->c_cl;
331 if (cc > count)
332 cc = count;
333 memcpy(clp->c_cl, p, cc);
334 if (clp->c_cq)
335 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
336 p += cc;
337 count -= cc;
338 clp->c_cc += cc;
339 clp->c_cl += cc;
340 if (clp->c_cl == clp->c_ce)
341 clp->c_cl = clp->c_cs;
342 }
343 out:
344 splx(s);
345 return count;
346 }
347
348 /*
349 * Given a non-NULL pointer into the clist return the pointer
350 * to the next character in the list or return NULL if no more chars.
351 *
352 * Callers must not allow getc's to happen between firstc's and nextc's
353 * so that the pointer becomes invalid. Note that interrupts are NOT
354 * masked.
355 */
356 u_char *
nextc(struct clist * clp,u_char * cp,int * c,int * ccp)357 nextc(struct clist *clp, u_char *cp, int *c, int *ccp)
358 {
359
360 if (clp->c_cf == cp) {
361 /*
362 * First time initialization.
363 */
364 *ccp = clp->c_cc;
365 }
366 if (*ccp == 0 || cp == NULL)
367 return NULL;
368 if (--(*ccp) == 0)
369 return NULL;
370 if (++cp == clp->c_ce)
371 cp = clp->c_cs;
372 *c = *cp & 0xff;
373 if (clp->c_cq) {
374 if (isset(clp->c_cq, cp - clp->c_cs))
375 *c |= TTY_QUOTE;
376 }
377 return cp;
378 }
379
380 /*
381 * Given a non-NULL pointer into the clist return the pointer
382 * to the first character in the list or return NULL if no more chars.
383 *
384 * Callers must not allow getc's to happen between firstc's and nextc's
385 * so that the pointer becomes invalid. Note that interrupts are NOT
386 * masked.
387 *
388 * *c is set to the NEXT character
389 */
390 u_char *
firstc(struct clist * clp,int * c,int * ccp)391 firstc(struct clist *clp, int *c, int *ccp)
392 {
393 u_char *cp;
394
395 *ccp = clp->c_cc;
396 if (*ccp == 0)
397 return NULL;
398 cp = clp->c_cf;
399 *c = *cp & 0xff;
400 if (clp->c_cq) {
401 if (isset(clp->c_cq, cp - clp->c_cs))
402 *c |= TTY_QUOTE;
403 }
404 return clp->c_cf;
405 }
406
407 /*
408 * Remove the last character in the clist and return it.
409 */
410 int
unputc(struct clist * clp)411 unputc(struct clist *clp)
412 {
413 unsigned int c = -1;
414 int s;
415
416 s = spltty();
417 if (clp->c_cc == 0)
418 goto out;
419
420 if (clp->c_cl == clp->c_cs)
421 clp->c_cl = clp->c_ce - 1;
422 else
423 --clp->c_cl;
424 clp->c_cc--;
425
426 c = *clp->c_cl & 0xff;
427 *clp->c_cl = 0;
428 if (clp->c_cq) {
429 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
430 c |= TTY_QUOTE;
431 clrbit(clp->c_cq, clp->c_cl - clp->c_cs);
432 }
433 if (clp->c_cc == 0)
434 clp->c_cf = clp->c_cl = NULL;
435 out:
436 splx(s);
437 return c;
438 }
439
440 /*
441 * Put the chars in the from queue on the end of the to queue.
442 */
443 void
catq(struct clist * from,struct clist * to)444 catq(struct clist *from, struct clist *to)
445 {
446 int c;
447 int s;
448
449 s = spltty();
450 if (from->c_cc == 0) { /* nothing to move */
451 splx(s);
452 return;
453 }
454
455 /*
456 * if `to' queue is empty and the queues are the same max size,
457 * it is more efficient to just swap the clist structures.
458 */
459 if (to->c_cc == 0 && from->c_cn == to->c_cn) {
460 struct clist tmp;
461
462 tmp = *from;
463 *from = *to;
464 *to = tmp;
465 splx(s);
466 return;
467 }
468 splx(s);
469
470 while ((c = getc(from)) != -1)
471 putc(c, to);
472 }
473