1 /* $Id: ethernet.c,v 1.4 2006/11/15 22:17:30 fredette Exp $ */
2
3 /* generic/ethernet.c - generic ethernet implementation support: */
4
5 /*
6 * Copyright (c) 2003 Matt Fredette
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Matt Fredette.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <tme/common.h>
37 _TME_RCSID("$Id: ethernet.c,v 1.4 2006/11/15 22:17:30 fredette Exp $");
38
39 /* includes: */
40 #include <tme/generic/ethernet.h>
41 #include <stdlib.h>
42 #include <errno.h>
43
44 /* the Ethernet broadcast address: */
45 const tme_uint8_t tme_ethernet_addr_broadcast[TME_ETHERNET_ADDR_SIZE] = {
46 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
47 };
48
49 /* this scores an Ethernet connection: */
50 int
tme_ethernet_connection_score(struct tme_connection * conn,unsigned int * _score)51 tme_ethernet_connection_score(struct tme_connection *conn, unsigned int *_score)
52 {
53 /* both sides must be Ethernet connections: */
54 assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET);
55 assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET);
56
57 /* XXX we don't do any real checking: */
58 *_score = 1;
59 return (TME_OK);
60 }
61
62 /* this parses an ethernet address: */
63 int
tme_ethernet_addr_parse(const char * addr_string,tme_uint8_t * addr_bytes)64 tme_ethernet_addr_parse(const char *addr_string, tme_uint8_t *addr_bytes)
65 {
66 const char *p1;
67 char *p2;
68 unsigned long byte;
69 int byte_i;
70
71 /* if we were given a NULL string, the parse fails: */
72 if (addr_string == NULL) {
73 return (EINVAL);
74 }
75
76 /* loop converting bytes: */
77 p1 = addr_string;
78 byte_i = 0;
79 for(;;) {
80
81 /* convert the next byte: */
82 byte = strtoul(p1, &p2, 16);
83
84 /* if some characters were converted: */
85 if (p2 != p1) {
86
87 /* if this byte is out of range, the parse fails: */
88 if (byte > 0xff) {
89 return (EINVAL);
90 }
91
92 /* if this is one too many bytes for an Ethernet address, the parse fails: */
93 else if (byte_i == TME_ETHERNET_ADDR_SIZE) {
94 return (EINVAL);
95 }
96
97 /* store this byte: */
98 addr_bytes[byte_i++] = byte;
99 }
100
101 /* if the conversion stopped on a NUL: */
102 if (*p2 == '\0') {
103
104 /* if we haven't converted enough bytes, the parse fails,
105 otherwise the parse succeeds: */
106 return ((byte_i == TME_ETHERNET_ADDR_SIZE)
107 ? TME_OK
108 : EINVAL);
109 }
110
111 /* if the conversion stopped on a colon, skip the colon and continue: */
112 else if (*p2 == ':') {
113 p1 = p2 + 1;
114 }
115
116 /* otherwise, the parse fails: */
117 else {
118 return (EINVAL);
119 }
120 }
121 /* NOTREACHED */
122 }
123
124 /* this copies frame chunks: */
125 unsigned int
tme_ethernet_chunks_copy(const struct tme_ethernet_frame_chunk * chunks_dst,const struct tme_ethernet_frame_chunk * chunks_src)126 tme_ethernet_chunks_copy(const struct tme_ethernet_frame_chunk *chunks_dst,
127 const struct tme_ethernet_frame_chunk *chunks_src)
128 {
129 const struct tme_ethernet_frame_chunk *chunk_dst;
130 const struct tme_ethernet_frame_chunk *chunk_src;
131 tme_uint8_t *chunk_bytes_dst;
132 const tme_uint8_t *chunk_bytes_src;
133 unsigned int chunk_size_dst;
134 unsigned int chunk_size_src;
135 unsigned int chunk_size;
136 unsigned int frame_size_total;
137
138 chunk_src = chunks_src;
139 chunk_bytes_src = chunk_src->tme_ethernet_frame_chunk_bytes;
140 chunk_size_src = chunk_src->tme_ethernet_frame_chunk_bytes_count;
141
142 frame_size_total = 0;
143
144 /* if we have been given a destination: */
145 if (chunks_dst != NULL) {
146
147 chunk_dst = chunks_dst;
148 chunk_bytes_dst = chunk_dst->tme_ethernet_frame_chunk_bytes;
149 chunk_size_dst = chunk_dst->tme_ethernet_frame_chunk_bytes_count;
150
151 /* copy until we run out of source or destination chunks: */
152 for (; (chunk_dst != NULL
153 && chunk_src != NULL); ) {
154
155 /* get the amount we can copy now: */
156 chunk_size = TME_MIN(chunk_size_dst, chunk_size_src);
157 assert(chunk_size > 0);
158
159 /* copy: */
160 memcpy(chunk_bytes_dst, chunk_bytes_src, chunk_size);
161
162 /* update: */
163 frame_size_total += chunk_size;
164 chunk_bytes_src += chunk_size;
165 chunk_size_src -= chunk_size;
166 if (chunk_size_src == 0
167 && (chunk_src = chunk_src->tme_ethernet_frame_chunk_next) != NULL) {
168 chunk_bytes_src = chunk_src->tme_ethernet_frame_chunk_bytes;
169 chunk_size_src = chunk_src->tme_ethernet_frame_chunk_bytes_count;
170 }
171 chunk_bytes_dst += chunk_size;
172 chunk_size_dst -= chunk_size;
173 if (chunk_size_dst == 0
174 && (chunk_dst = chunk_dst->tme_ethernet_frame_chunk_next) != NULL) {
175 chunk_bytes_dst = chunk_dst->tme_ethernet_frame_chunk_bytes;
176 chunk_size_dst = chunk_dst->tme_ethernet_frame_chunk_bytes_count;
177 }
178 }
179 }
180
181 /* count up the uncopied bytes: */
182 for (; chunk_src != NULL; ) {
183 frame_size_total += chunk_size_src;
184 if ((chunk_src = chunk_src->tme_ethernet_frame_chunk_next) != NULL) {
185 chunk_size_src = chunk_src->tme_ethernet_frame_chunk_bytes_count;
186 }
187 }
188
189 /* done: */
190 return (frame_size_total);
191 }
192
193 /* this calculates a little-endian Ethernet CRC. this was cribbed
194 from NetBSD's src/sys/net/if_ethersubr.c: */
195 tme_uint32_t
tme_ethernet_crc32_el(const tme_uint8_t * buf,unsigned int len)196 tme_ethernet_crc32_el(const tme_uint8_t *buf, unsigned int len)
197 {
198 static const tme_uint32_t crctab[] = {
199 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
200 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
201 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
202 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
203 };
204 tme_uint32_t crc;
205 unsigned int i;
206
207 crc = ((tme_uint32_t) 0) - 1; /* initial value */
208
209 for (i = 0; i < len; i++) {
210 crc ^= buf[i];
211 crc = (crc >> 4) ^ crctab[crc & 0xf];
212 crc = (crc >> 4) ^ crctab[crc & 0xf];
213 }
214
215 return (crc);
216 }
217