xref: /netbsd-src/external/bsd/libpcap/dist/etherent.c (revision 8bda04910f1f2c366c51d4cbd40df19f5b57f1dd)
1 /*	$NetBSD: etherent.c,v 1.6 2024/09/02 15:33:36 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1990, 1993, 1994, 1995, 1996
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: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 
24 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: etherent.c,v 1.6 2024/09/02 15:33:36 christos Exp $");
26 
27 #include <config.h>
28 
29 #include <pcap-types.h>
30 
31 #include <memory.h>
32 #include <stdio.h>
33 #include <string.h>
34 
35 #include "pcap-int.h"
36 
37 #include <pcap/namedb.h>
38 
39 #include "thread-local.h"
40 
41 #ifdef HAVE_OS_PROTO_H
42 #include "os-proto.h"
43 #endif
44 
45 static inline int skip_space(FILE *);
46 static inline int skip_line(FILE *);
47 
48 /* Hex digit to integer. */
49 static inline u_char
50 xdtoi(u_char c)
51 {
52 	if (c >= '0' && c <= '9')
53 		return (u_char)(c - '0');
54 	else if (c >= 'a' && c <= 'f')
55 		return (u_char)(c - 'a' + 10);
56 	else
57 		return (u_char)(c - 'A' + 10);
58 }
59 
60 /*
61  * Skip linear white space (space and tab) and any CRs before LF.
62  * Stop when we hit a non-white-space character or an end-of-line LF.
63  */
64 static inline int
65 skip_space(FILE *f)
66 {
67 	int c;
68 
69 	do {
70 		c = getc(f);
71 	} while (c == ' ' || c == '\t' || c == '\r');
72 
73 	return c;
74 }
75 
76 static inline int
77 skip_line(FILE *f)
78 {
79 	int c;
80 
81 	do
82 		c = getc(f);
83 	while (c != '\n' && c != EOF);
84 
85 	return c;
86 }
87 
88 struct pcap_etherent *
89 pcap_next_etherent(FILE *fp)
90 {
91 	register int c, i;
92 	u_char d;
93 	char *bp;
94 	size_t namesize;
95 	static thread_local struct pcap_etherent e;
96 
97 	memset((char *)&e, 0, sizeof(e));
98 	for (;;) {
99 		/* Find addr */
100 		c = skip_space(fp);
101 		if (c == EOF)
102 			return (NULL);
103 		if (c == '\n')
104 			continue;
105 
106 		/* If this is a comment, or first thing on line
107 		   cannot be Ethernet address, skip the line. */
108 		if (!PCAP_ISXDIGIT(c)) {
109 			c = skip_line(fp);
110 			if (c == EOF)
111 				return (NULL);
112 			continue;
113 		}
114 
115 		/* must be the start of an address */
116 		for (i = 0; i < 6; i += 1) {
117 			d = xdtoi((u_char)c);
118 			c = getc(fp);
119 			if (c == EOF)
120 				return (NULL);
121 			if (PCAP_ISXDIGIT(c)) {
122 				d <<= 4;
123 				d |= xdtoi((u_char)c);
124 				c = getc(fp);
125 				if (c == EOF)
126 					return (NULL);
127 			}
128 			e.addr[i] = d;
129 			if (c != ':')
130 				break;
131 			c = getc(fp);
132 			if (c == EOF)
133 				return (NULL);
134 		}
135 
136 		/* Must be whitespace */
137 		if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
138 			c = skip_line(fp);
139 			if (c == EOF)
140 				return (NULL);
141 			continue;
142 		}
143 		c = skip_space(fp);
144 		if (c == EOF)
145 			return (NULL);
146 
147 		/* hit end of line... */
148 		if (c == '\n')
149 			continue;
150 
151 		if (c == '#') {
152 			c = skip_line(fp);
153 			if (c == EOF)
154 				return (NULL);
155 			continue;
156 		}
157 
158 		/* pick up name */
159 		bp = e.name;
160 		/* Use 'namesize' to prevent buffer overflow. */
161 		namesize = sizeof(e.name) - 1;
162 		do {
163 			*bp++ = (u_char)c;
164 			c = getc(fp);
165 			if (c == EOF)
166 				return (NULL);
167 		} while (c != ' ' && c != '\t' && c != '\r' && c != '\n'
168 		    && --namesize != 0);
169 		*bp = '\0';
170 
171 		/* Eat trailing junk */
172 		if (c != '\n')
173 			(void)skip_line(fp);
174 
175 		return &e;
176 	}
177 }
178