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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Ethernet routines. Includes ARP and Reverse ARP. Used for ethernet-like
31 * media also - so be sure NOT to use ETHERMTU as a mtu limit. macinit()
32 * will set this appropriately.
35 #include <sys/types.h>
36 #include <socket_impl.h>
37 #include <socket_inet.h>
39 #include <sys/socket.h>
41 #include <net/if_arp.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/in.h>
44 #include <netinet/ip.h>
45 #include <netinet/if_ether.h>
46 #include <sys/promif.h>
47 #include <sys/prom_plat.h>
48 #include <sys/salib.h>
49 #include <sys/bootdebug.h>
52 #include "ipv4_impl.h"
55 #include "ethernet_inet.h"
57 ether_addr_t etherbroadcastaddr
= {
58 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
62 struct ether_header arp_eh
;
63 struct ether_arp arp_ea
;
64 #define USED_SIZE (sizeof (struct ether_header) + sizeof (struct ether_arp))
65 char filler
[ETHERMIN
- sizeof (struct ether_arp
)];
69 ether_print(ether_addr_t ea
)
71 static char eprintbuf
[20];
73 (void) sprintf(eprintbuf
, "%x:%x:%x:%x:%x:%x", ea
[0], ea
[1], ea
[2],
79 * Common ARP code. Broadcast the packet and wait for the right response.
81 * If rarp is called for, caller expects an IPv4 address in the target
82 * protocol address (tpa) field of the "out" argument.
84 * If arp is called for, caller expects a hardware address in the
85 * source hardware address (sha) field of the "out" argument.
87 * Returns TRUE if transaction succeeded, FALSE otherwise.
89 * The timeout argument is the number of milliseconds to wait for a
90 * response. An infinite timeout can be specified as 0xffffffff.
93 ether_comarp(struct arp_packet
*out
, uint32_t timeout
)
95 struct arp_packet
*in
= (struct arp_packet
*)mac_state
.mac_buf
;
96 int count
, time
, feedback
, len
, delay
= 2;
98 struct in_addr tmp_ia
;
101 bcopy((caddr_t
)etherbroadcastaddr
, (caddr_t
)&out
->arp_eh
.ether_dhost
,
102 sizeof (ether_addr_t
));
103 bcopy((caddr_t
)mac_state
.mac_addr_buf
,
104 (caddr_t
)&out
->arp_eh
.ether_shost
, sizeof (ether_addr_t
));
106 out
->arp_ea
.arp_hrd
= htons(ARPHRD_ETHER
);
107 out
->arp_ea
.arp_pro
= htons(ETHERTYPE_IP
);
108 out
->arp_ea
.arp_hln
= sizeof (ether_addr_t
);
109 out
->arp_ea
.arp_pln
= sizeof (struct in_addr
);
110 bcopy(mac_state
.mac_addr_buf
, (caddr_t
)&out
->arp_ea
.arp_sha
,
111 sizeof (ether_addr_t
));
112 ipv4_getipaddr(&tmp_ia
);
113 tmp_ia
.s_addr
= htonl(tmp_ia
.s_addr
);
114 bcopy((caddr_t
)&tmp_ia
, (caddr_t
)out
->arp_ea
.arp_spa
,
115 sizeof (struct in_addr
));
118 wait_time
= prom_gettime() + timeout
;
119 for (count
= 0; timeout
== ~0U || prom_gettime() < wait_time
; count
++) {
120 if (count
== ETHER_WAITCNT
) {
121 if (out
->arp_ea
.arp_op
== ARPOP_REQUEST
) {
122 bcopy((caddr_t
)out
->arp_ea
.arp_tpa
,
123 (caddr_t
)&tmp_ia
, sizeof (struct in_addr
));
125 "\nRequesting Ethernet address for: %s\n",
128 printf("\nRequesting Internet address for %s\n",
129 ether_print(out
->arp_ea
.arp_tha
));
133 (void) prom_write(mac_state
.mac_dev
, (caddr_t
)out
,
134 sizeof (*out
), 0, NETWORK
);
136 if (count
>= ETHER_WAITCNT
)
137 printf("%c\b", ind
[feedback
++ % 4]); /* activity */
139 time
= prom_gettime() + (delay
* 1000); /* broadcast delay */
140 while (prom_gettime() <= time
) {
141 len
= prom_read(mac_state
.mac_dev
, mac_state
.mac_buf
,
142 mac_state
.mac_mtu
, 0, NETWORK
);
145 if (in
->arp_ea
.arp_pro
!= ntohs(ETHERTYPE_IP
))
147 if (out
->arp_ea
.arp_op
== ntohs(ARPOP_REQUEST
)) {
148 if (in
->arp_eh
.ether_type
!=
149 ntohs(ETHERTYPE_ARP
))
151 if (in
->arp_ea
.arp_op
!= ntohs(ARPOP_REPLY
))
153 if (bcmp((caddr_t
)in
->arp_ea
.arp_spa
,
154 (caddr_t
)out
->arp_ea
.arp_tpa
,
155 sizeof (struct in_addr
)) != 0)
157 if (boothowto
& RB_VERBOSE
) {
158 bcopy((caddr_t
)in
->arp_ea
.arp_spa
,
160 sizeof (struct in_addr
));
161 printf("Found %s @ %s\n",
163 ether_print(in
->arp_ea
.arp_sha
));
165 /* copy hardware addr into "out" for caller */
166 bcopy((caddr_t
)&in
->arp_ea
.arp_sha
,
167 (caddr_t
)&out
->arp_ea
.arp_sha
,
168 sizeof (ether_addr_t
));
170 } else { /* Reverse ARP */
171 if (in
->arp_eh
.ether_type
!=
172 ntohs(ETHERTYPE_REVARP
))
174 if (in
->arp_ea
.arp_op
!= ntohs(REVARP_REPLY
))
176 if (bcmp((caddr_t
)in
->arp_ea
.arp_tha
,
177 (caddr_t
)out
->arp_ea
.arp_tha
,
178 sizeof (ether_addr_t
)) != 0)
180 if (boothowto
& RB_VERBOSE
) {
181 bcopy((caddr_t
)in
->arp_ea
.arp_tpa
,
183 sizeof (struct in_addr
));
184 printf("Internet address is: %s\n",
187 /* copy IP address into "out" for caller */
188 bcopy((caddr_t
)in
->arp_ea
.arp_tpa
,
189 (caddr_t
)out
->arp_ea
.arp_tpa
,
190 sizeof (struct in_addr
));
195 delay
= delay
* 2; /* Double the request delay */
196 if (delay
> 64) /* maximum delay is 64 seconds */
204 * Broadcasts to determine MAC address given network order IP address.
207 * Returns TRUE if successful, FALSE otherwise.
210 ether_arp(struct in_addr
*ip
, void *hap
, uint32_t timeout
)
212 ether_addr_t
*ep
= (ether_addr_t
*)hap
;
213 struct arp_packet out
;
217 prom_panic("Ethernet device is not initialized.");
219 bzero((char *)&out
, sizeof (struct arp_packet
));
221 out
.arp_eh
.ether_type
= htons(ETHERTYPE_ARP
);
222 out
.arp_ea
.arp_op
= htons(ARPOP_REQUEST
);
223 bcopy((caddr_t
)etherbroadcastaddr
, (caddr_t
)&out
.arp_ea
.arp_tha
,
224 sizeof (ether_addr_t
));
225 bcopy((caddr_t
)ip
, (caddr_t
)out
.arp_ea
.arp_tpa
,
226 sizeof (struct in_addr
));
228 result
= ether_comarp(&out
, timeout
);
230 if (result
&& (ep
!= NULL
)) {
231 bcopy((caddr_t
)&out
.arp_ea
.arp_sha
, (caddr_t
)ep
,
232 sizeof (ether_addr_t
));
238 * Reverse ARP client side
239 * Determine our Internet address given our MAC address
246 struct arp_packet out
;
249 prom_panic("Ethernet device is not initialized.");
251 bzero((char *)&out
, sizeof (struct arp_packet
));
253 out
.arp_eh
.ether_type
= htons(ETHERTYPE_REVARP
);
254 out
.arp_ea
.arp_op
= htons(REVARP_REQUEST
);
255 bcopy(mac_state
.mac_addr_buf
, (caddr_t
)&out
.arp_ea
.arp_tha
,
256 sizeof (ether_addr_t
));
259 (void) ether_comarp(&out
, 0xffffffff);
261 bcopy((caddr_t
)&out
.arp_ea
.arp_tpa
, (caddr_t
)&ip
,
262 sizeof (struct in_addr
));
264 ip
.s_addr
= ntohl(ip
.s_addr
);
270 ether_header_len(struct inetgram
*igm
)
272 return (sizeof (struct ether_header
));
276 * Handle a IP datagram addressed to our ethernet address or to the
277 * ethernet broadcast address. Also respond to ARP requests. Generates
278 * inetgrams as long as there's data and the mac level IP timeout timer
279 * hasn't expired. As soon as there is no data, we try for
280 * ETHER_INPUT_ATTEMPTS for more, then exit the loop, even if there is time
281 * left, since we expect to have data waiting for us when we're called, we just
282 * don't know how much.
284 * We workaround slow proms (some proms have hard sleeps for as much as 3msec)
285 * even though there are is data waiting.
287 * Returns the total number of MEDIA_LVL frames placed on the socket.
288 * Caller is expected to free up the inetgram resources.
291 ether_input(int index
)
293 struct inetgram
*inp
;
294 struct ether_header
*eh
;
295 int frames
= 0; /* successful frames */
296 int attempts
= 0; /* failed attempts after success */
297 int16_t len
= 0, data_len
;
298 uint32_t timeout
, reltime
;
299 uint32_t pre_pr
, post_pr
; /* prom_read interval */
302 int failures
= 0; /* total failures */
303 int total_attempts
= 0; /* total prom_read */
304 int no_data
= 0; /* no data in prom */
305 int arps
= 0; /* arp requests processed */
306 uint32_t tot_pr
= 0; /* prom_read time */
307 uint32_t tot_pc
= 0; /* inetgram creation time */
313 prom_panic("Ethernet device is not initialized.");
315 if ((reltime
= sockets
[index
].in_timeout
) == 0)
316 reltime
= mac_state
.mac_in_timeout
;
317 timeout
= prom_gettime() + reltime
;
320 if (frames
> ETHER_MAX_FRAMES
) {
321 /* someone is trying a denial of service attack */
326 * The following is a workaround for a calvin prom (V2) bug
327 * where prom_read() returns a nonzero length, even when it's
328 * not read a packet. So we zero out the header to compensate.
330 bzero(mac_state
.mac_buf
, sizeof (struct ether_header
));
333 * Prom_read() will return 0 or -2 if no data is present. A
334 * return value of -1 means an error has occurred. We adjust
335 * the timeout by calling the time spent in prom_read() "free".
336 * prom_read() returns the number of bytes actually read, but
337 * will only copy "len" bytes into our buffer. Adjust in
338 * case the MTU is wrong.
340 pre_pr
= prom_gettime();
341 len
= prom_read(mac_state
.mac_dev
, mac_state
.mac_buf
,
342 mac_state
.mac_mtu
, 0, NETWORK
);
343 post_pr
= prom_gettime();
344 timeout
+= (post_pr
- pre_pr
);
346 tot_pr
+= (post_pr
- pre_pr
);
350 if (len
> mac_state
.mac_mtu
) {
351 dprintf("ether_input: adjusting MTU %d -> %d\n",
352 mac_state
.mac_mtu
, len
);
353 bkmem_free(mac_state
.mac_buf
, mac_state
.mac_mtu
);
354 mac_state
.mac_mtu
= len
;
355 mac_state
.mac_buf
= bkmem_alloc(mac_state
.mac_mtu
);
356 if (mac_state
.mac_buf
== NULL
) {
357 prom_panic("ether_input: Cannot reallocate "
360 len
= 0; /* pretend there was no data */
369 if (len
== 0 || len
== -2) {
378 eh
= (struct ether_header
*)mac_state
.mac_buf
;
379 if (eh
->ether_type
== ntohs(ETHERTYPE_IP
) &&
380 len
>= (sizeof (struct ether_header
) +
381 sizeof (struct ip
))) {
385 pre_pc
= prom_gettime();
388 inp
= (struct inetgram
*)bkmem_zalloc(
389 sizeof (struct inetgram
));
392 return (frames
== 0 ? -1 : frames
);
394 offset
= sizeof (struct ether_header
);
395 data_len
= len
- offset
;
396 inp
->igm_mp
= allocb(data_len
, 0);
397 if (inp
->igm_mp
== NULL
) {
399 bkmem_free((caddr_t
)inp
,
400 sizeof (struct inetgram
));
401 return (frames
== 0 ? -1 : frames
);
403 bcopy((caddr_t
)(mac_state
.mac_buf
+ offset
),
404 inp
->igm_mp
->b_rptr
, data_len
);
405 inp
->igm_mp
->b_wptr
+= data_len
;
406 inp
->igm_level
= NETWORK_LVL
;
407 add_grams(&sockets
[index
].inq
, inp
);
411 tot_pc
+= prom_gettime() - pre_pc
;
416 if (eh
->ether_type
== ntohs(ETHERTYPE_ARP
) &&
417 len
>= (sizeof (struct ether_header
) +
418 sizeof (struct ether_arp
))) {
421 struct ether_arp
*ea
;
424 printf("ether_input: ARP message received\n");
428 ea
= (struct ether_arp
*)(mac_state
.mac_buf
+
429 sizeof (struct ether_header
));
430 if (ea
->arp_pro
!= ntohs(ETHERTYPE_IP
))
434 ip
.s_addr
= ntohl(ip
.s_addr
);
436 if (ea
->arp_op
== ntohs(ARPOP_REQUEST
) &&
437 ip
.s_addr
!= INADDR_ANY
&&
438 (bcmp((caddr_t
)ea
->arp_tpa
, (caddr_t
)&ip
,
439 sizeof (struct in_addr
)) == 0)) {
440 ea
->arp_op
= htons(ARPOP_REPLY
);
441 bcopy((caddr_t
)ea
->arp_sha
,
442 (caddr_t
)&eh
->ether_dhost
,
443 sizeof (ether_addr_t
));
444 bcopy(mac_state
.mac_addr_buf
,
445 (caddr_t
)&eh
->ether_shost
,
446 mac_state
.mac_addr_len
);
447 bcopy((caddr_t
)ea
->arp_sha
,
448 (caddr_t
)ea
->arp_tha
,
449 sizeof (ether_addr_t
));
450 bcopy((caddr_t
)ea
->arp_spa
,
451 (caddr_t
)ea
->arp_tpa
,
452 sizeof (struct in_addr
));
453 bcopy(mac_state
.mac_addr_buf
,
454 (caddr_t
)ea
->arp_sha
,
455 mac_state
.mac_addr_len
);
456 bcopy((caddr_t
)&ip
, (caddr_t
)ea
->arp_spa
,
457 sizeof (struct in_addr
));
458 (void) prom_write(mac_state
.mac_dev
,
460 sizeof (struct arp_packet
),
462 /* don't charge for ARP replies */
466 } while (attempts
< ETHER_INPUT_ATTEMPTS
&&
468 (now
= prom_gettime()) < timeout
);
470 prom_gettime() < timeout
);
474 printf("ether_input(%d): T/S/N/A/F/P/M: %d/%d/%d/%d/%d/%d/%d "
475 "T/O: %d < %d = %s\n", index
, total_attempts
, frames
, no_data
,
476 arps
, failures
, tot_pr
, tot_pc
, now
, timeout
,
477 (now
< timeout
) ? "TRUE" : "FALSE");
483 * Send out an ethernet datagram. We expect a IP frame appropriately fragmented
486 * Errno is set and -1 is returned if an error occurs. Number of bytes sent
487 * is returned on success.
491 ether_output(int index
, struct inetgram
*ogp
)
493 int header_len
, result
;
494 struct ether_header eh
;
496 struct in_addr tmpip
, ipdst
, netid
;
497 int broadcast
= FALSE
;
503 printf("ether_output (%d): size %d\n", index
,
504 ogp
->igm_mp
->b_wptr
- ogp
->igm_mp
->b_rptr
);
507 prom_panic("Ethernet device is not initialized.");
509 if (ogp
->igm_level
!= MEDIA_LVL
) {
510 dprintf("ether_output: frame type wrong: socket: %d\n",
516 header_len
= sizeof (struct ether_header
);
518 size
= mp
->b_wptr
- mp
->b_rptr
;
519 if (size
> mac_state
.mac_mtu
) {
520 dprintf("ether_output: frame size too big: %d\n", size
);
526 ip
= (struct ip
*)(mp
->b_rptr
);
528 eh
.ether_type
= htons(ETHERTYPE_IP
);
529 bcopy(mac_state
.mac_addr_buf
, (caddr_t
)&eh
.ether_shost
,
530 mac_state
.mac_addr_len
);
531 bcopy((caddr_t
)&ip
->ip_dst
, (caddr_t
)&ipdst
, sizeof (ipdst
));
533 if (ipdst
.s_addr
== htonl(INADDR_BROADCAST
))
534 broadcast
= TRUE
; /* limited broadcast */
539 ipv4_getnetid(&netid
);
540 ipv4_getnetmask(&mask
);
541 mask
.s_addr
= htonl(mask
.s_addr
);
542 netid
.s_addr
= htonl(netid
.s_addr
);
545 * check for all-hosts directed broadcast for
548 if (mask
.s_addr
!= htonl(INADDR_BROADCAST
) &&
549 (ipdst
.s_addr
& ~mask
.s_addr
) == 0 &&
550 (ipdst
.s_addr
& mask
.s_addr
) == netid
.s_addr
) {
551 broadcast
= TRUE
; /* directed broadcast */
553 if (ogp
->igm_router
.s_addr
!= htonl(INADDR_ANY
))
554 tmpip
.s_addr
= ogp
->igm_router
.s_addr
;
556 tmpip
.s_addr
= ipdst
.s_addr
;
558 result
= mac_get_arp(&tmpip
, (void *)&eh
.ether_dhost
,
559 sizeof (ether_addr_t
), mac_state
.mac_arp_timeout
);
562 dprintf("ether_output: ARP request for %s "
563 "timed out.\n", inet_ntoa(tmpip
));
570 bcopy((caddr_t
)etherbroadcastaddr
,
571 (caddr_t
)&eh
.ether_dhost
, sizeof (ether_addr_t
));
574 /* add the ethernet header */
575 mp
->b_rptr
-= sizeof (eh
);
576 bcopy((caddr_t
)&eh
, mp
->b_rptr
, sizeof (eh
));
578 printf("ether_output(%d): level(%d) frame(0x%x) len(%d)\n",
579 index
, ogp
->igm_level
, mp
->b_rptr
, size
);
581 printf("Dump ethernet (%d): \n", size
);
582 hexdump((char *)mp
->b_rptr
, size
);
584 #endif /* DEBUG > 1 */
586 return (prom_write(mac_state
.mac_dev
, (char *)mp
->b_rptr
, size
,