Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: cnmagic.c,v 1.14 2017/05/04 11:01:16 kamil Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2000 Eduardo Horvath
      5  * 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  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: cnmagic.c,v 1.14 2017/05/04 11:01:16 kamil Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/systm.h>
     33 #include <sys/kernel.h>
     34 
     35 #define ENCODE_STATE(c, n) (short)(((c)&0x1ff)|(((n)&0x7f)<<9))
     36 
     37 static unsigned short cn_magic[CNS_LEN];
     38 
     39 /*
     40  * Initialize a cnm_state_t.
     41  */
     42 void
     43 cn_init_magic(cnm_state_t *cnm)
     44 {
     45 	cnm->cnm_state = 0;
     46 	cnm->cnm_magic = cn_magic;
     47 }
     48 
     49 /*
     50  * Destroy a cnm_state_t.
     51  */
     52 void
     53 cn_destroy_magic(cnm_state_t *cnm)
     54 {
     55 	cnm->cnm_state = 0;
     56 	cnm->cnm_magic = NULL;
     57 }
     58 
     59 /*
     60  * Translate a magic string to a state
     61  * machine table.
     62  */
     63 int
     64 cn_set_magic(const char *smagic)
     65 {
     66 	const unsigned char *magic = (const unsigned char *)smagic;
     67 	unsigned short i, c, n;
     68 	unsigned short m[CNS_LEN];
     69 
     70 	for (i = 0; i < CNS_LEN; i++) {
     71 		c = *magic++;
     72 		switch (c) {
     73 		case 0:
     74 			/* End of string */
     75 			if (i == 0) {
     76 				/* empty string? */
     77 #ifdef DEBUG
     78 				printf("cn_set_magic(): empty!\n");
     79 #endif
     80 			}
     81 			cn_magic[i] = 0;
     82 			while (i--)
     83 				cn_magic[i] = m[i];
     84 			return 0;
     85 		case 0x27:
     86 			/* Escape sequence */
     87 			c = *magic++;
     88 			switch (c) {
     89 			case 0x27:
     90 				break;
     91 			case 0x01:
     92 				/* BREAK */
     93 				c = CNC_BREAK;
     94 				break;
     95 			case 0x02:
     96 				/* NUL */
     97 				c = 0;
     98 				break;
     99 			}
    100 			/* FALLTHROUGH */
    101 		default:
    102 			/* Transition to the next state. */
    103 			n = *magic ? i + 1 : CNS_TERM;
    104 #ifdef DEBUG
    105 			if (!cold)
    106 				aprint_normal("mag %d %x:%x\n", i, c, n);
    107 #endif
    108 			m[i] = ENCODE_STATE(c, n);
    109 			break;
    110 		}
    111 	}
    112 	return EINVAL;
    113 }
    114 
    115 /*
    116  * Translate a state machine table back to
    117  * a magic string.
    118  */
    119 int
    120 cn_get_magic(char *magic, size_t maglen)
    121 {
    122 	size_t i, n = 0;
    123 
    124 #define ADD_CHAR(x) \
    125 do \
    126 	if (n < maglen) \
    127 		magic[n++] = (x); \
    128 	else \
    129 		goto error; \
    130 while (/*CONSTCOND*/0)
    131 
    132 	for (i = 0; i < CNS_LEN; /* empty */) {
    133 		unsigned short c = cn_magic[i];
    134 		i = CNS_MAGIC_NEXT(c);
    135 		if (i == 0)
    136 			goto finish;
    137 
    138 		/* Translate a character */
    139 		switch (CNS_MAGIC_VAL(c)) {
    140 		case CNC_BREAK:
    141 			ADD_CHAR(0x27);
    142 			ADD_CHAR(0x01);
    143 			break;
    144 		case 0:
    145 			ADD_CHAR(0x27);
    146 			ADD_CHAR(0x02);
    147 			break;
    148 		case 0x27:
    149 			ADD_CHAR(0x27);
    150 			ADD_CHAR(0x27);
    151 			break;
    152 		default:
    153 			ADD_CHAR(c);
    154 			break;
    155 		}
    156 		/* Now go to the next state */
    157 		if (i == CNS_TERM)
    158 			goto finish;
    159 	}
    160 
    161 error:
    162 	return EINVAL;
    163 
    164 finish:
    165 	/* Either termination state or empty machine */
    166 	ADD_CHAR('\0');
    167 	return 0;
    168 }
    169