slc.c revision 1.12 1 /* $NetBSD: slc.c,v 1.12 2003/07/15 05:03:49 itojun Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)slc.c 8.1 (Berkeley) 6/4/93";
40 #else
41 __RCSID("$NetBSD: slc.c,v 1.12 2003/07/15 05:03:49 itojun Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include "telnetd.h"
46
47 #ifdef LINEMODE
48 /*
49 * local varibles
50 */
51 static unsigned char *def_slcbuf = (unsigned char *)0;
52 static int def_slclen = 0;
53 static int slcchange; /* change to slc is requested */
54 static unsigned char *slcptr; /* pointer into slc buffer */
55 static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */
56
57 void default_slc __P((void));
58 void process_slc __P((u_int, u_int, cc_t));
59
60 /*
61 * send_slc
62 *
63 * Write out the current special characters to the client.
64 */
65 void
66 send_slc()
67 {
68 register int i;
69
70 /*
71 * Send out list of triplets of special characters
72 * to client. We only send info on the characters
73 * that are currently supported.
74 */
75 for (i = 1; i <= NSLC; i++) {
76 if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
77 continue;
78 add_slc((unsigned char)i, slctab[i].current.flag,
79 slctab[i].current.val);
80 }
81
82 } /* end of send_slc */
83
84 /*
85 * default_slc
86 *
87 * Set pty special characters to all the defaults.
88 */
89 void
90 default_slc()
91 {
92 register int i;
93
94 for (i = 1; i <= NSLC; i++) {
95 slctab[i].current.val = slctab[i].defset.val;
96 if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE))
97 slctab[i].current.flag = SLC_NOSUPPORT;
98 else
99 slctab[i].current.flag = slctab[i].defset.flag;
100 if (slctab[i].sptr) {
101 *(slctab[i].sptr) = slctab[i].defset.val;
102 }
103 }
104 slcchange = 1;
105
106 } /* end of default_slc */
107 #endif /* LINEMODE */
108
109 /*
110 * get_slc_defaults
111 *
112 * Initialize the slc mapping table.
113 */
114 void
115 get_slc_defaults()
116 {
117 register int i;
118
119 init_termbuf();
120
121 for (i = 1; i <= NSLC; i++) {
122 slctab[i].defset.flag =
123 spcset(i, &slctab[i].defset.val, &slctab[i].sptr);
124 slctab[i].current.flag = SLC_NOSUPPORT;
125 slctab[i].current.val = 0;
126 }
127
128 } /* end of get_slc_defaults */
129
130 #ifdef LINEMODE
131 /*
132 * add_slc
133 *
134 * Add an slc triplet to the slc buffer.
135 */
136 void
137 add_slc(func, flag, val)
138 register char func, flag;
139 register cc_t val;
140 {
141
142 if ((*slcptr++ = (unsigned char)func) == 0xff)
143 *slcptr++ = 0xff;
144
145 if ((*slcptr++ = (unsigned char)flag) == 0xff)
146 *slcptr++ = 0xff;
147
148 if ((*slcptr++ = (unsigned char)val) == 0xff)
149 *slcptr++ = 0xff;
150
151 } /* end of add_slc */
152
153 /*
154 * start_slc
155 *
156 * Get ready to process incoming slc's and respond to them.
157 *
158 * The parameter getit is non-zero if it is necessary to grab a copy
159 * of the terminal control structures.
160 */
161 void
162 start_slc(getit)
163 register int getit;
164 {
165
166 slcchange = 0;
167 if (getit)
168 init_termbuf();
169 (void)snprintf((char *)slcbuf, sizeof slcbuf, "%c%c%c%c",
170 IAC, SB, TELOPT_LINEMODE, LM_SLC);
171 slcptr = slcbuf + 4;
172
173 } /* end of start_slc */
174
175 /*
176 * end_slc
177 *
178 * Finish up the slc negotiation. If something to send, then send it.
179 */
180 int
181 end_slc(bufp)
182 register unsigned char **bufp;
183 {
184 register int len;
185
186 /*
187 * If a change has occurred, store the new terminal control
188 * structures back to the terminal driver.
189 */
190 if (slcchange) {
191 set_termbuf();
192 }
193
194 /*
195 * If the pty state has not yet been fully processed and there is a
196 * deferred slc request from the client, then do not send any
197 * sort of slc negotiation now. We will respond to the client's
198 * request very soon.
199 */
200 if (def_slcbuf && (terminit() == 0)) {
201 return(0);
202 }
203
204 if (slcptr > (slcbuf + 4)) {
205 if (bufp) {
206 *bufp = &slcbuf[4];
207 return(slcptr - slcbuf - 4);
208 } else {
209 (void) snprintf((char *)slcptr,
210 sizeof(slcbuf) - (slcptr - slcbuf), "%c%c",
211 IAC, SE);
212 slcptr += 2;
213 len = slcptr - slcbuf;
214 writenet(slcbuf, len);
215 netflush(); /* force it out immediately */
216 DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
217 }
218 }
219 return (0);
220
221 } /* end of end_slc */
222
223 /*
224 * process_slc
225 *
226 * Figure out what to do about the client's slc
227 */
228 void
229 process_slc(func, flag, val)
230 u_int func, flag;
231 cc_t val;
232 {
233 int hislevel, mylevel, ack;
234
235 /*
236 * Ensure that we know something about this function
237 */
238 if (func > NSLC) {
239 add_slc(func, SLC_NOSUPPORT, 0);
240 return;
241 }
242
243 /*
244 * Process the special case requests of 0 SLC_DEFAULT 0
245 * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't
246 * worry about whether the value is actually 0 or not.
247 */
248 if (func == 0) {
249 if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
250 default_slc();
251 send_slc();
252 } else if (flag == SLC_VARIABLE) {
253 send_slc();
254 }
255 return;
256 }
257
258 /*
259 * Appears to be a function that we know something about. So
260 * get on with it and see what we know.
261 */
262
263 hislevel = flag & SLC_LEVELBITS;
264 mylevel = slctab[func].current.flag & SLC_LEVELBITS;
265 ack = flag & SLC_ACK;
266 /*
267 * ignore the command if:
268 * the function value and level are the same as what we already have;
269 * or the level is the same and the ack bit is set
270 */
271 if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
272 return;
273 } else if (ack) {
274 /*
275 * If we get here, we got an ack, but the levels don't match.
276 * This shouldn't happen. If it does, it is probably because
277 * we have sent two requests to set a variable without getting
278 * a response between them, and this is the first response.
279 * So, ignore it, and wait for the next response.
280 */
281 return;
282 } else {
283 change_slc(func, flag, val);
284 }
285
286 } /* end of process_slc */
287
288 /*
289 * change_slc
290 *
291 * Process a request to change one of our special characters.
292 * Compare client's request with what we are capable of supporting.
293 */
294 void
295 change_slc(func, flag, val)
296 int func, flag;
297 cc_t val;
298 {
299 int hislevel, mylevel;
300
301 hislevel = flag & SLC_LEVELBITS;
302 mylevel = slctab[func].defset.flag & SLC_LEVELBITS;
303 /*
304 * If client is setting a function to NOSUPPORT
305 * or DEFAULT, then we can easily and directly
306 * accomodate the request.
307 */
308 if (hislevel == SLC_NOSUPPORT) {
309 slctab[func].current.flag = flag;
310 slctab[func].current.val = (cc_t)_POSIX_VDISABLE;
311 flag |= SLC_ACK;
312 add_slc(func, flag, val);
313 return;
314 }
315 if (hislevel == SLC_DEFAULT) {
316 /*
317 * Special case here. If client tells us to use
318 * the default on a function we don't support, then
319 * return NOSUPPORT instead of what we may have as a
320 * default level of DEFAULT.
321 */
322 if (mylevel == SLC_DEFAULT) {
323 slctab[func].current.flag = SLC_NOSUPPORT;
324 } else {
325 slctab[func].current.flag = slctab[func].defset.flag;
326 }
327 slctab[func].current.val = slctab[func].defset.val;
328 add_slc(func, slctab[func].current.flag,
329 slctab[func].current.val);
330 return;
331 }
332
333 /*
334 * Client wants us to change to a new value or he
335 * is telling us that he can't change to our value.
336 * Some of the slc's we support and can change,
337 * some we do support but can't change,
338 * and others we don't support at all.
339 * If we can change it then we have a pointer to
340 * the place to put the new value, so change it,
341 * otherwise, continue the negotiation.
342 */
343 if (slctab[func].sptr) {
344 /*
345 * We can change this one.
346 */
347 slctab[func].current.val = val;
348 *(slctab[func].sptr) = val;
349 slctab[func].current.flag = flag;
350 flag |= SLC_ACK;
351 slcchange = 1;
352 add_slc(func, flag, val);
353 } else {
354 /*
355 * It is not possible for us to support this
356 * request as he asks.
357 *
358 * If our level is DEFAULT, then just ack whatever was
359 * sent.
360 *
361 * If he can't change and we can't change,
362 * then degenerate to NOSUPPORT.
363 *
364 * Otherwise we send our level back to him, (CANTCHANGE
365 * or NOSUPPORT) and if CANTCHANGE, send
366 * our value as well.
367 */
368 if (mylevel == SLC_DEFAULT) {
369 slctab[func].current.flag = flag;
370 slctab[func].current.val = val;
371 flag |= SLC_ACK;
372 } else if (hislevel == SLC_CANTCHANGE &&
373 mylevel == SLC_CANTCHANGE) {
374 flag &= ~SLC_LEVELBITS;
375 flag |= SLC_NOSUPPORT;
376 slctab[func].current.flag = flag;
377 } else {
378 flag &= ~SLC_LEVELBITS;
379 flag |= mylevel;
380 slctab[func].current.flag = flag;
381 if (mylevel == SLC_CANTCHANGE) {
382 slctab[func].current.val =
383 slctab[func].defset.val;
384 val = slctab[func].current.val;
385 }
386 }
387 add_slc(func, flag, val);
388 }
389
390 } /* end of change_slc */
391
392 #if VEOF == VMIN
393 cc_t oldeofc = '\004';
394 #endif
395
396 /*
397 * check_slc
398 *
399 * Check the special characters in use and notify the client if any have
400 * changed. Only those characters that are capable of being changed are
401 * likely to have changed. If a local change occurs, kick the support level
402 * and flags up to the defaults.
403 */
404 void
405 check_slc()
406 {
407 register int i;
408
409 for (i = 1; i <= NSLC; i++) {
410 #if VEOF == VMIN
411 /*
412 * In a perfect world this would be a neat little
413 * function. But in this world, we should not notify
414 * client of changes to the VEOF char when
415 * ICANON is off, because it is not representing
416 * a special character.
417 */
418 if (i == SLC_EOF) {
419 if (!tty_isediting())
420 continue;
421 else if (slctab[i].sptr)
422 oldeofc = *(slctab[i].sptr);
423 }
424 #endif /* VEOF == VMIN */
425 if (slctab[i].sptr &&
426 (*(slctab[i].sptr) != slctab[i].current.val)) {
427 slctab[i].current.val = *(slctab[i].sptr);
428 if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE)
429 slctab[i].current.flag = SLC_NOSUPPORT;
430 else
431 slctab[i].current.flag = slctab[i].defset.flag;
432 add_slc((unsigned char)i, slctab[i].current.flag,
433 slctab[i].current.val);
434 }
435 }
436 } /* check_slc */
437
438 /*
439 * do_opt_slc
440 *
441 * Process an slc option buffer. Defer processing of incoming slc's
442 * until after the terminal state has been processed. Save the first slc
443 * request that comes along, but discard all others.
444 *
445 * ptr points to the beginning of the buffer, len is the length.
446 */
447 void
448 do_opt_slc(ptr, len)
449 register unsigned char *ptr;
450 register int len;
451 {
452 register unsigned char func, flag;
453 cc_t val;
454 register unsigned char *end = ptr + len;
455
456 if (terminit()) { /* go ahead */
457 while (ptr < end) {
458 func = *ptr++;
459 if (ptr >= end) break;
460 flag = *ptr++;
461 if (ptr >= end) break;
462 val = (cc_t)*ptr++;
463
464 process_slc((u_int)func, (u_int)flag, val);
465
466 }
467 } else {
468 /*
469 * save this slc buffer if it is the first, otherwise dump
470 * it.
471 */
472 if (def_slcbuf == (unsigned char *)0) {
473 def_slclen = len;
474 def_slcbuf = (unsigned char *)malloc((unsigned)len);
475 if (def_slcbuf == (unsigned char *)0)
476 return; /* too bad */
477 memcpy(def_slcbuf, ptr, len);
478 }
479 }
480
481 } /* end of do_opt_slc */
482
483 /*
484 * deferslc
485 *
486 * Do slc stuff that was deferred.
487 */
488 void
489 deferslc()
490 {
491 if (def_slcbuf) {
492 start_slc(1);
493 do_opt_slc(def_slcbuf, def_slclen);
494 (void) end_slc(0);
495 free(def_slcbuf);
496 def_slcbuf = (unsigned char *)0;
497 def_slclen = 0;
498 }
499
500 } /* end of deferslc */
501
502 #endif /* LINEMODE */
503