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