xref: /illumos-gate/usr/src/stand/lib/inet/mac.c (revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <socket_impl.h>
31 #include <socket_inet.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <net/if.h>
36 #include <net/if_arp.h>
37 #include <net/if_types.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/in.h>
40 #include <netinet/if_ether.h>
41 #include <sys/promif.h>
42 #include <sys/prom_plat.h>
43 #include <sys/salib.h>
44 
45 #include "mac.h"
46 #include "mac_impl.h"
47 #include "atm_inet.h"
48 #include "ethernet_inet.h"
49 #include "fddi_inet.h"
50 #include "token_inet.h"
51 #include "ibd_inet.h"
52 
53 /*
54  * MAC layer interface
55  */
56 boolean_t		initialized;	/* Boolean state */
57 struct mac_type		mac_state;
58 int			arp_index;	/* current arp table index */
59 static struct arptable	atable[ARP_TABLE_SIZE];
60 
61 #if	!defined(__i386)
62 struct ofw_net_types {
63 	char	*n_name;	/* OFW network media name */
64 	int	n_type;		/* IFT */
65 } ofw_types[] = {
66 	{ "atm",	IFT_ATM	},
67 	{ "ethernet",	IFT_ETHER },
68 	{ "fddi",	IFT_FDDI },
69 	{ "token-ring",	IFT_ISO88025 },
70 	{ "ipib",	IFT_IB }
71 };
72 #endif	/* !__i386 */
73 
74 /*
75  * given the mac type, initialize the mac interface state.
76  */
77 void
78 mac_init(char *bootdevicename)
79 {
80 	int		type = 0;
81 #if !defined(__i386)
82 	static char	*mtu_name = "max-frame-size";
83 	static char	*chosen_net = "chosen-network-type";
84 	static char	*supported_net = "supported-network-types";
85 	static char	*netiftype = "network-interface-type";
86 	pnode_t		node;
87 	char		*wp, *media_type;
88 	int		len = 0, i;
89 #endif	/* !__i386 */
90 	char		tmpbuf[MAXNAMELEN];
91 	char		devname[MAXNAMELEN];
92 
93 	if (initialized)
94 		return;
95 
96 	mac_state.mac_in_timeout = MAC_IN_TIMEOUT;
97 
98 #ifdef	DEBUG
99 	printf("mac_init: device path: %s\n", bootdevicename);
100 #endif	/* DEBUG */
101 
102 	if ((mac_state.mac_dev = prom_open(bootdevicename)) == 0) {
103 		(void) snprintf(tmpbuf, sizeof (tmpbuf),
104 		    "Cannot prom_open network device %s.", bootdevicename);
105 		prom_panic(tmpbuf);
106 	}
107 
108 #if !defined(__i386)
109 	(void) prom_devname_from_pathname(bootdevicename, devname);
110 #else
111 	(void) strcpy(devname, bootdevicename);
112 #endif	/* !__i386 */
113 
114 #ifdef	DEBUG
115 	printf("mac_init: Network device name: %s\n", devname);
116 #endif	/* DEBUG */
117 
118 #if !defined(__i386)
119 	/*
120 	 * Ask the prom for our MTU and media type. "chosen-network-type"
121 	 * is of the form of "<network type>,<speed (Mbps)>,<connector type>,
122 	 * <duplex mode>: e.g.: "ethernet,100,rj45,full"
123 	 */
124 	node = prom_finddevice(devname);
125 	if (node != OBP_NONODE && node != OBP_BADNODE) {
126 		if (prom_getproplen(node, mtu_name) == sizeof (ihandle_t)) {
127 			(void) prom_getprop(node, mtu_name,
128 			    (caddr_t)&mac_state.mac_mtu);
129 		}
130 		bzero(tmpbuf, sizeof (tmpbuf));
131 		/*
132 		 * The following order of looking for properties is
133 		 * from FWARC 2002/345.
134 		 */
135 		if ((len = prom_getproplen(node, netiftype)) > 0 &&
136 		    len < sizeof (tmpbuf)) {
137 			(void) prom_getprop(node, netiftype, tmpbuf);
138 		} else if ((len = prom_getproplen(node, chosen_net)) > 0 &&
139 		    len < sizeof (tmpbuf)) {
140 			(void) prom_getprop(node, chosen_net, tmpbuf);
141 		} else if ((len = prom_getproplen(node, supported_net)) > 0 &&
142 		    len < sizeof (tmpbuf)) {
143 			(void) prom_getprop(node, supported_net, tmpbuf);
144 		}
145 		media_type = NULL;
146 		if (len > 0) {
147 			if ((wp = strstr(tmpbuf, ",")) != NULL)
148 				*wp = '\0';
149 			media_type = tmpbuf;
150 		}
151 		if (media_type != NULL) {
152 #ifdef	DEBUG
153 			printf("mac_init: Media type: %s\n", media_type);
154 #endif	/* DEBUG */
155 			for (i = 0; i < sizeof (ofw_types) /
156 			    sizeof (struct ofw_net_types); i++) {
157 				if (strcmp(ofw_types[i].n_name,
158 				    media_type) == 0) {
159 					type = ofw_types[i].n_type;
160 					break;
161 				}
162 			}
163 		}
164 	}
165 #else
166 	type = IFT_ETHER;	/* default to ethernet */
167 #endif	/* !__i386 */
168 
169 	switch (type) {
170 	case IFT_ATM:
171 		/*
172 		 * ATM is currently treated mostly like ethernet,
173 		 * with the exception that the MTU is most likely
174 		 * different.
175 		 */
176 		mac_state.mac_type = IFT_ATM;
177 		mac_state.mac_arp_timeout = ATM_ARP_TIMEOUT;
178 		mac_state.mac_in_timeout = ATM_IN_TIMEOUT;
179 		if (mac_state.mac_mtu == 0)
180 			mac_state.mac_mtu = ATMSIZE;
181 		mac_state.mac_addr_len = sizeof (ether_addr_t);
182 		mac_state.mac_addr_buf = bkmem_alloc(mac_state.mac_addr_len);
183 		if (mac_state.mac_addr_buf == NULL)
184 			prom_panic("mac_init: Cannot allocate memory.");
185 		if (prom_getmacaddr(mac_state.mac_dev,
186 		    (caddr_t)mac_state.mac_addr_buf) != 0)
187 			prom_panic("mac_init: Cannot obtain MAC address.");
188 		mac_state.mac_arp = ether_arp;
189 		mac_state.mac_rarp = ether_revarp;
190 		mac_state.mac_header_len = ether_header_len;
191 		mac_state.mac_input = ether_input;
192 		mac_state.mac_output = ether_output;
193 		break;
194 
195 	case IFT_FDDI:
196 		/*
197 		 * FDDI is currently treated mostly like ethernet,
198 		 * with the exception that the MTU is most likely
199 		 * different.
200 		 */
201 		mac_state.mac_type = IFT_FDDI;
202 		mac_state.mac_arp_timeout = FDDI_ARP_TIMEOUT;
203 		mac_state.mac_in_timeout = FDDI_IN_TIMEOUT;
204 		if (mac_state.mac_mtu == 0)
205 			mac_state.mac_mtu = FDDISIZE;
206 		mac_state.mac_addr_len = sizeof (ether_addr_t);
207 		mac_state.mac_addr_buf = bkmem_alloc(mac_state.mac_addr_len);
208 		if (mac_state.mac_addr_buf == NULL)
209 			prom_panic("mac_init: Cannot allocate memory.");
210 		if (prom_getmacaddr(mac_state.mac_dev,
211 		    (caddr_t)mac_state.mac_addr_buf) != 0)
212 			prom_panic("mac_init: Cannot obtain MAC address.");
213 		mac_state.mac_arp = ether_arp;
214 		mac_state.mac_rarp = ether_revarp;
215 		mac_state.mac_header_len = ether_header_len;
216 		mac_state.mac_input = ether_input;
217 		mac_state.mac_output = ether_output;
218 		break;
219 
220 	case IFT_ISO88025:
221 		/*
222 		 * Token ring is currently treated mostly like ethernet,
223 		 * with the exception that the MTU is most likely different.
224 		 */
225 		mac_state.mac_type = IFT_ISO88025;
226 		mac_state.mac_arp_timeout = TOKEN_ARP_TIMEOUT;
227 		mac_state.mac_in_timeout = TOKEN_IN_TIMEOUT;
228 		if (mac_state.mac_mtu == 0)
229 			mac_state.mac_mtu = TOKENSIZE;
230 		mac_state.mac_addr_len = sizeof (ether_addr_t);
231 		mac_state.mac_addr_buf = bkmem_alloc(mac_state.mac_addr_len);
232 		if (mac_state.mac_addr_buf == NULL)
233 			prom_panic("mac_init: Cannot allocate memory.");
234 		if (prom_getmacaddr(mac_state.mac_dev,
235 		    (caddr_t)mac_state.mac_addr_buf) != 0)
236 			prom_panic("mac_init: Cannot obtain MAC address.");
237 		mac_state.mac_arp = ether_arp;
238 		mac_state.mac_rarp = ether_revarp;
239 		mac_state.mac_header_len = ether_header_len;
240 		mac_state.mac_input = ether_input;
241 		mac_state.mac_output = ether_output;
242 		break;
243 
244 	case IFT_IB:
245 		mac_state.mac_type = IFT_IB;
246 		ibd_init();
247 		break;
248 
249 	case IFT_ETHER:
250 		/* FALLTHRU - default to ethernet */
251 	default:
252 		mac_state.mac_type = IFT_ETHER;
253 		mac_state.mac_mtu = ETHERSIZE;
254 		mac_state.mac_arp_timeout = ETHER_ARP_TIMEOUT;
255 		mac_state.mac_in_timeout = ETHER_IN_TIMEOUT;
256 		if (mac_state.mac_mtu == 0)
257 			mac_state.mac_mtu = ETHERSIZE;
258 		mac_state.mac_addr_len = sizeof (ether_addr_t);
259 		mac_state.mac_addr_buf = bkmem_alloc(mac_state.mac_addr_len);
260 		if (mac_state.mac_addr_buf == NULL)
261 			prom_panic("mac_init: Cannot allocate memory.");
262 		if (prom_getmacaddr(mac_state.mac_dev,
263 		    (caddr_t)mac_state.mac_addr_buf) != 0)
264 			prom_panic("mac_init: Cannot obtain MAC address.");
265 		mac_state.mac_arp = ether_arp;
266 		mac_state.mac_rarp = ether_revarp;
267 		mac_state.mac_header_len = ether_header_len;
268 		mac_state.mac_input = ether_input;
269 		mac_state.mac_output = ether_output;
270 		break;
271 	}
272 
273 	mac_state.mac_buf = bkmem_alloc(mac_state.mac_mtu);
274 	if (mac_state.mac_buf == NULL)
275 		prom_panic("mac_init: Cannot allocate netbuf memory.");
276 	else
277 		initialized = B_TRUE;
278 }
279 
280 void
281 mac_fini()
282 {
283 	if (mac_state.mac_addr_buf != NULL) {
284 		bkmem_free((caddr_t)mac_state.mac_addr_buf,
285 		    mac_state.mac_addr_len);
286 		mac_state.mac_addr_buf = NULL;
287 	}
288 	if (mac_state.mac_buf != NULL) {
289 		bkmem_free(mac_state.mac_buf, mac_state.mac_mtu);
290 		mac_state.mac_buf = NULL;
291 	}
292 	(void) prom_close(mac_state.mac_dev);
293 	initialized = B_FALSE;
294 }
295 
296 /* MAC layer specific socket initialization */
297 void
298 mac_socket_init(struct inetboot_socket *isp)
299 {
300 	isp->input[MEDIA_LVL] = mac_state.mac_input;
301 	isp->output[MEDIA_LVL] = mac_state.mac_output;
302 	isp->close[MEDIA_LVL] = NULL;
303 	isp->headerlen[MEDIA_LVL] = mac_state.mac_header_len;
304 	isp->in_timeout = mac_state.mac_in_timeout;
305 }
306 
307 /*
308  * Add an entry to the ARP table. All values in table are network order.
309  * No checking is done to determine whether there's duplicates.
310  */
311 void
312 mac_set_arp(struct in_addr *ip, void *hp, int hl)
313 {
314 	atable[arp_index].ia.s_addr = ip->s_addr;
315 	bcopy(hp, (char *)atable[arp_index].ha, hl);
316 	atable[arp_index].hl = hl;
317 	arp_index++;
318 	if (arp_index >= ARP_TABLE_SIZE)
319 		arp_index = 0;
320 }
321 
322 /*
323  * Retrieve an entry from the ARP table using network-order IP address as
324  * search criteria. HW address buffer is filled in up to hl in len. (make
325  * sure the buffer is big enough given the mac type)
326  *
327  * Returns TRUE if successful, FALSE otherwise. Will wait timeout milliseconds
328  * for a response.
329  */
330 int
331 mac_get_arp(struct in_addr *ip, void *hp, int hl, uint32_t timeout)
332 {
333 	int i, result;
334 
335 	for (i = 0; i < ARP_TABLE_SIZE; i++) {
336 		if (ip->s_addr == atable[i].ia.s_addr) {
337 			bcopy((char *)atable[i].ha, hp, hl);
338 			return (TRUE);
339 		}
340 	}
341 
342 	/* Not found. ARP for it. */
343 	bzero(hp, hl);
344 	result = mac_state.mac_arp(ip, hp, timeout);
345 
346 	if (result) {
347 		/* Cool - add it to the arp table */
348 		mac_set_arp(ip, hp, hl);
349 	}
350 	return (result);
351 }
352 
353 int
354 mac_get_mtu(void)
355 {
356 	if (!initialized)
357 		return (-1);
358 	else
359 		return (mac_state.mac_mtu);
360 }
361 
362 int
363 mac_get_dev(void)
364 {
365 	if (!initialized)
366 		return (-1);
367 	else
368 		return (mac_state.mac_dev);
369 }
370 
371 uint8_t *
372 mac_get_addr_buf(void)
373 {
374 	if (!initialized)
375 		return (NULL);
376 	else
377 		return (mac_state.mac_addr_buf);
378 }
379 
380 int
381 mac_get_addr_len(void)
382 {
383 	if (!initialized)
384 		return (-1);
385 	else
386 		return (mac_state.mac_addr_len);
387 }
388 
389 int
390 mac_get_type(void)
391 {
392 	if (!initialized)
393 		return (-1);
394 	else
395 		return (mac_state.mac_type);
396 }
397 
398 int
399 mac_get_arp_timeout(void)
400 {
401 	if (!initialized)
402 		return (-1);
403 	else
404 		return (mac_state.mac_arp_timeout);
405 }
406 
407 int
408 mac_get_hdr_len(void)
409 {
410 	if (!initialized)
411 		return (-1);
412 	else
413 		return (mac_state.mac_header_len(NULL));
414 }
415 
416 int
417 mac_call_arp(struct in_addr *addr, void *buf, uint32_t timeout)
418 {
419 	return (mac_state.mac_arp(addr, buf, timeout));
420 }
421 
422 void
423 mac_call_rarp(void)
424 {
425 	mac_state.mac_rarp();
426 }
427 
428 /*
429  * Map a IFT_ type to an RFC 1700 arp hwtype.
430  */
431 uint8_t
432 mac_arp_type(uint8_t ift_type)
433 {
434 	uint8_t arptype;
435 
436 	switch (ift_type) {
437 	case IFT_ISO88025:
438 		arptype = 4;	/* token ring */
439 		break;
440 	case IFT_ATM:
441 		arptype = 16;	/* ATM */
442 		break;
443 	case IFT_FDDI:
444 		arptype = 18;	/* Fiber Channel */
445 		break;
446 	case IFT_IB:
447 		arptype = 32;	/* Infiniband */
448 		break;
449 	case IFT_ETHER:
450 		/* FALLTHRU */
451 	default:
452 		arptype = 1;	/* default to ethernet */
453 		break;
454 	}
455 	return (arptype);
456 }
457