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