1 1.23 rillig /* $NetBSD: linkaddr.c,v 1.23 2022/04/19 20:32:15 rillig Exp $ */ 2 1.5 cgd 3 1.1 cgd /*- 4 1.5 cgd * Copyright (c) 1990, 1993 5 1.5 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.13 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.6 christos #include <sys/cdefs.h> 33 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint) 34 1.5 cgd #if 0 35 1.5 cgd static char sccsid[] = "@(#)linkaddr.c 8.1 (Berkeley) 6/4/93"; 36 1.5 cgd #else 37 1.23 rillig __RCSID("$NetBSD: linkaddr.c,v 1.23 2022/04/19 20:32:15 rillig Exp $"); 38 1.5 cgd #endif 39 1.1 cgd #endif /* LIBC_SCCS and not lint */ 40 1.1 cgd 41 1.1 cgd #include <sys/types.h> 42 1.1 cgd #include <sys/socket.h> 43 1.1 cgd #include <net/if_dl.h> 44 1.10 lukem 45 1.10 lukem #include <assert.h> 46 1.1 cgd #include <string.h> 47 1.1 cgd 48 1.1 cgd /* States*/ 49 1.1 cgd #define NAMING 0 50 1.1 cgd #define GOTONE 1 51 1.1 cgd #define GOTTWO 2 52 1.1 cgd #define RESET 3 53 1.1 cgd /* Inputs */ 54 1.1 cgd #define DIGIT (4*0) 55 1.1 cgd #define END (4*1) 56 1.1 cgd #define DELIM (4*2) 57 1.1 cgd #define LETTER (4*3) 58 1.1 cgd 59 1.1 cgd void 60 1.15 christos link_addr(const char *addr, struct sockaddr_dl *sdl) 61 1.1 cgd { 62 1.17 christos char *cp = sdl->sdl_data; 63 1.9 christos char *cplim = sdl->sdl_len + (char *)(void *)sdl; 64 1.15 christos int byte = 0, state = NAMING; 65 1.15 christos size_t newaddr = 0; /* pacify gcc */ 66 1.1 cgd 67 1.10 lukem _DIAGASSERT(addr != NULL); 68 1.10 lukem _DIAGASSERT(sdl != NULL); 69 1.10 lukem 70 1.8 kleink (void)memset(&sdl->sdl_family, 0, (size_t)sdl->sdl_len - 1); 71 1.1 cgd sdl->sdl_family = AF_LINK; 72 1.1 cgd do { 73 1.1 cgd state &= ~LETTER; 74 1.1 cgd if ((*addr >= '0') && (*addr <= '9')) { 75 1.6 christos newaddr = *addr - '0'; 76 1.1 cgd } else if ((*addr >= 'a') && (*addr <= 'f')) { 77 1.6 christos newaddr = *addr - 'a' + 10; 78 1.1 cgd } else if ((*addr >= 'A') && (*addr <= 'F')) { 79 1.6 christos newaddr = *addr - 'A' + 10; 80 1.1 cgd } else if (*addr == 0) { 81 1.1 cgd state |= END; 82 1.1 cgd } else if (state == NAMING && 83 1.1 cgd (((*addr >= 'A') && (*addr <= 'Z')) || 84 1.1 cgd ((*addr >= 'a') && (*addr <= 'z')))) 85 1.1 cgd state |= LETTER; 86 1.1 cgd else 87 1.1 cgd state |= DELIM; 88 1.1 cgd addr++; 89 1.1 cgd switch (state /* | INPUT */) { 90 1.1 cgd case NAMING | DIGIT: 91 1.1 cgd case NAMING | LETTER: 92 1.5 cgd *cp++ = addr[-1]; 93 1.5 cgd continue; 94 1.1 cgd case NAMING | DELIM: 95 1.5 cgd state = RESET; 96 1.15 christos _DIAGASSERT(__type_fit(uint8_t, cp - sdl->sdl_data)); 97 1.15 christos sdl->sdl_nlen = (uint8_t)(cp - sdl->sdl_data); 98 1.5 cgd continue; 99 1.1 cgd case GOTTWO | DIGIT: 100 1.5 cgd *cp++ = byte; 101 1.5 cgd /* FALLTHROUGH */ 102 1.1 cgd case RESET | DIGIT: 103 1.5 cgd state = GOTONE; 104 1.15 christos byte = (int)newaddr; 105 1.5 cgd continue; 106 1.1 cgd case GOTONE | DIGIT: 107 1.5 cgd state = GOTTWO; 108 1.15 christos byte = (int)newaddr + (byte << 4); 109 1.5 cgd continue; 110 1.1 cgd default: /* | DELIM */ 111 1.5 cgd state = RESET; 112 1.5 cgd *cp++ = byte; 113 1.5 cgd byte = 0; 114 1.5 cgd continue; 115 1.1 cgd case GOTONE | END: 116 1.1 cgd case GOTTWO | END: 117 1.5 cgd *cp++ = byte; 118 1.5 cgd /* FALLTHROUGH */ 119 1.1 cgd case RESET | END: 120 1.1 cgd break; 121 1.1 cgd } 122 1.1 cgd break; 123 1.1 cgd } while (cp < cplim); 124 1.15 christos 125 1.15 christos _DIAGASSERT(__type_fit(uint8_t, cp - LLADDR(sdl))); 126 1.15 christos sdl->sdl_alen = (uint8_t)(cp - LLADDR(sdl)); 127 1.9 christos newaddr = cp - (char *)(void *)sdl; 128 1.15 christos if (newaddr > sizeof(*sdl)) { 129 1.15 christos _DIAGASSERT(__type_fit(uint8_t, newaddr)); 130 1.15 christos sdl->sdl_len = (uint8_t)newaddr; 131 1.15 christos } 132 1.1 cgd return; 133 1.1 cgd } 134 1.1 cgd 135 1.7 mycroft static const char hexlist[16] = "0123456789abcdef"; 136 1.1 cgd 137 1.1 cgd char * 138 1.16 matt link_ntoa(const struct sockaddr_dl *sdl) 139 1.1 cgd { 140 1.1 cgd static char obuf[64]; 141 1.17 christos char *out = obuf; 142 1.17 christos size_t i; 143 1.14 christos const u_char *in = (const u_char *)CLLADDR(sdl); 144 1.14 christos const u_char *inlim = in + sdl->sdl_alen; 145 1.1 cgd int firsttime = 1; 146 1.10 lukem 147 1.10 lukem _DIAGASSERT(sdl != NULL); 148 1.1 cgd 149 1.17 christos #define ADDC(ch) \ 150 1.17 christos do { \ 151 1.20 christos if (out >= obuf + sizeof(obuf) - 1) \ 152 1.20 christos return obuf; \ 153 1.17 christos *out++ = (ch); \ 154 1.23 rillig } while (0) 155 1.17 christos 156 1.21 kre /* 157 1.21 kre * This is not needed on the first call, as the static 158 1.21 kre * obuf wil be fully init'd to 0 by default. But after 159 1.21 kre * obuf has been returned to userspace the first time, 160 1.21 kre * anything may have been written to it, so, let's be safe. 161 1.21 kre * 162 1.21 kre * (An alternative method would be to make ADDC() more 163 1.21 kre * complex: 164 1.21 kre * if (out < obuf + sizeof(obuf) - ((ch) != '\0')) 165 1.21 kre * *out++ = (ch); 166 1.22 pgoyette * so it never returns, and the final ADDC(0) always works 167 1.21 kre * but that evaluates 'ch' twice, and is slower, so ...) 168 1.21 kre */ 169 1.21 kre obuf[sizeof(obuf) - 1] = '\0'; 170 1.21 kre 171 1.1 cgd if (sdl->sdl_nlen) { 172 1.17 christos if (sdl->sdl_nlen >= sizeof(obuf)) 173 1.20 christos i = sizeof(obuf) - 1; 174 1.20 christos else 175 1.20 christos i = sdl->sdl_nlen; 176 1.20 christos (void)memcpy(obuf, sdl->sdl_data, i); 177 1.20 christos out += i; 178 1.5 cgd if (sdl->sdl_alen) 179 1.17 christos ADDC(':'); 180 1.1 cgd } 181 1.1 cgd while (in < inlim) { 182 1.5 cgd if (firsttime) 183 1.5 cgd firsttime = 0; 184 1.5 cgd else 185 1.17 christos ADDC('.'); 186 1.1 cgd i = *in++; 187 1.1 cgd if (i > 0xf) { 188 1.17 christos size_t j = i & 0xf; 189 1.1 cgd i >>= 4; 190 1.17 christos ADDC(hexlist[i]); 191 1.17 christos ADDC(hexlist[j]); 192 1.1 cgd } else 193 1.17 christos ADDC(hexlist[i]); 194 1.1 cgd } 195 1.19 christos ADDC('\0'); 196 1.20 christos return obuf; 197 1.1 cgd } 198