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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
30 #include <sys/types.h>
32 #include <sys/sysmacros.h>
36 #define IPADDRL sizeof (struct in_addr)
40 * The following value (8) is determined to work reliably in switched 10/100MB
41 * ethernet environments. Use caution if you plan on decreasing it.
45 static char defaultfile
[] = "/etc/inet/rarp";
46 static char retries_var
[] = "RARP_RETRIES=";
47 static int rarp_timeout
= RARPTIMEOUT
;
48 static int rarp_retries
= RARPRETRIES
;
50 static dlpi_handle_t
rarp_open(const char *, size_t *, uchar_t
*, uchar_t
*);
51 static int rarp_recv(dlpi_handle_t
, struct arphdr
*, size_t, size_t, int64_t);
54 doifrevarp(const char *linkname
, struct sockaddr_in
*laddr
)
57 struct arphdr
*req
, *ans
;
59 struct in_addr answer
;
62 size_t physaddrlen
, ifrarplen
;
63 uchar_t my_macaddr
[DLPI_PHYSADDR_MAX
];
64 uchar_t my_broadcast
[DLPI_PHYSADDR_MAX
];
67 if (linkname
[0] == '\0') {
68 (void) fprintf(stderr
, "ifconfig: doifrevarp: name not set\n");
73 (void) printf("doifrevarp interface %s\n", linkname
);
75 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
76 Perror0_exit("socket");
78 (void) strlcpy(lifr
.lifr_name
, linkname
, sizeof (lifr
.lifr_name
));
79 if (ioctl(s
, SIOCGLIFFLAGS
, (char *)&lifr
) < 0) {
81 Perror0_exit("SIOCGLIFFLAGS");
84 /* don't try to revarp if we know it won't work */
85 if ((lifr
.lifr_flags
& IFF_LOOPBACK
) ||
86 (lifr
.lifr_flags
& IFF_NOARP
) ||
87 (lifr
.lifr_flags
& IFF_IPMP
) ||
88 (lifr
.lifr_flags
& IFF_POINTOPOINT
)) {
93 /* open rarp interface */
94 dh
= rarp_open(linkname
, &physaddrlen
, my_macaddr
, my_broadcast
);
101 * RARP looks at /etc/ethers and NIS, which only works
102 * with 6 byte addresses currently.
104 if (physaddrlen
!= ETHERADDRL
) {
110 ifrarplen
= sizeof (struct arphdr
) + (2 * IPADDRL
) + (2 * physaddrlen
);
112 /* look for adjustments to rarp_retries in the RARP defaults file */
113 if (defopen(defaultfile
) == 0) {
116 if (cp
= defread(retries_var
)) {
121 rarp_retries
= ntries
;
123 (void) defopen(NULL
); /* close default file */
126 /* allocate request and response buffers */
127 if (((req
= malloc(ifrarplen
)) == NULL
) ||
128 ((ans
= malloc(ifrarplen
)) == NULL
)) {
135 /* create rarp request */
136 (void) memset(req
, 0, ifrarplen
);
137 req
->ar_hrd
= htons(ARPHRD_ETHER
);
138 req
->ar_pro
= htons(ETHERTYPE_IP
);
139 req
->ar_hln
= physaddrlen
;
140 req
->ar_pln
= IPADDRL
;
141 req
->ar_op
= htons(REVARP_REQUEST
);
143 (void) memcpy(&req
[1], my_macaddr
, physaddrlen
);
144 (void) memcpy((uchar_t
*)req
+ sizeof (struct arphdr
) + IPADDRL
+
145 physaddrlen
, my_macaddr
, physaddrlen
);
147 for (tries_left
= rarp_retries
; tries_left
> 0; --tries_left
) {
148 /* send the request */
149 retval
= dlpi_send(dh
, my_broadcast
, physaddrlen
, req
,
151 if (retval
!= DLPI_SUCCESS
) {
152 Perrdlpi("doifrevarp: cannot send rarp request",
158 (void) printf("rarp sent\n");
160 retval
= rarp_recv(dh
, ans
, ifrarplen
, physaddrlen
,
161 rarp_timeout
* MILLISEC
);
163 if (retval
!= DLPI_ETIMEDOUT
)
167 (void) printf("rarp retry\n");
170 if (retval
== DLPI_SUCCESS
) {
171 (void) memcpy(&answer
, (uchar_t
*)ans
+
172 sizeof (struct arphdr
) + (2 * physaddrlen
) + IPADDRL
,
174 (void) memcpy(&from
, (uchar_t
*)ans
+ physaddrlen
+
175 sizeof (struct arphdr
), sizeof (from
));
178 (void) printf("answer: %s", inet_ntoa(answer
));
179 (void) printf(" [from %s]\n", inet_ntoa(from
));
181 laddr
->sin_addr
= answer
;
183 Perrdlpi("doifrevarp: could not receive rarp reply",
191 return (retval
== DLPI_SUCCESS
);
195 * Open the datalink provider device and bind to the REVARP type.
196 * Return the resulting DLPI handle.
199 rarp_open(const char *linkname
, size_t *alen
, uchar_t
*myaddr
, uchar_t
*mybaddr
)
202 char *physaddr
, *bcastaddr
;
207 (void) printf("rarp_open %s\n", linkname
);
209 if ((retval
= dlpi_open(linkname
, &dh
, 0)) != DLPI_SUCCESS
) {
210 Perrdlpi("rarp_open: dlpi_open failed", linkname
, retval
);
214 if ((retval
= dlpi_bind(dh
, ETHERTYPE_REVARP
, NULL
)) != DLPI_SUCCESS
) {
215 Perrdlpi("rarp_open: dlpi_bind failed", linkname
, retval
);
219 if ((retval
= dlpi_info(dh
, &dlinfo
, 0)) != DLPI_SUCCESS
) {
220 Perrdlpi("rarp_open: dlpi_info failed", linkname
, retval
);
224 if (dlinfo
.di_bcastaddrlen
== 0) {
225 (void) fprintf(stderr
, "ifconfig: rarp_open: %s broadcast "
226 "not supported\n", linkname
);
230 /* we assume the following are equal and fill in 'alen' */
231 assert(dlinfo
.di_bcastaddrlen
== dlinfo
.di_physaddrlen
);
233 (void) memcpy(mybaddr
, dlinfo
.di_bcastaddr
, dlinfo
.di_bcastaddrlen
);
235 *alen
= dlinfo
.di_physaddrlen
;
237 (void) memcpy(myaddr
, dlinfo
.di_physaddr
, dlinfo
.di_physaddrlen
);
240 bcastaddr
= _link_ntoa(mybaddr
, NULL
, dlinfo
.di_bcastaddrlen
,
243 physaddr
= _link_ntoa(myaddr
, NULL
, dlinfo
.di_physaddrlen
,
246 if (physaddr
!= NULL
&& bcastaddr
!= NULL
) {
247 (void) printf("device %s: broadcast address %s, mac "
248 "address %s\n", linkname
, bcastaddr
, physaddr
);
254 (void) printf("rarp_open: addr length = %d\n",
255 dlinfo
.di_physaddrlen
);
266 * Read reply for RARP request. If a reply is received within waitms,
267 * validate the reply. If it is a correct RARP reply return DLPI_SUCCESS,
268 * otherwise return DLPI_ETIMEDOUT. If there is an error while reading retrun
272 rarp_recv(dlpi_handle_t dh
, struct arphdr
*ans
, size_t msglen
,
273 size_t physaddrlen
, int64_t waitms
)
277 size_t anslen
= msglen
;
278 hrtime_t endtime
= gethrtime() + MSEC2NSEC(waitms
);
281 while ((currtime
= gethrtime()) < endtime
) {
282 waitms
= NSEC2MSEC(endtime
- currtime
);
283 retval
= dlpi_recv(dh
, NULL
, NULL
, ans
, &anslen
, waitms
, NULL
);
284 if (retval
== DLPI_SUCCESS
) {
288 cause
= "short packet";
289 else if (ans
->ar_hrd
!= htons(ARPHRD_ETHER
))
290 cause
= "hardware type not Ethernet";
291 else if (ans
->ar_pro
!= htons(ETHERTYPE_IP
))
292 cause
= "protocol type not IP";
293 else if (ans
->ar_hln
!= physaddrlen
)
294 cause
= "unexpected hardware address length";
295 else if (ans
->ar_pln
!= IPADDRL
)
296 cause
= "unexpected protocol address length";
298 (void) fprintf(stderr
, "RARP packet received "
299 "but discarded (%s)\n", cause
);
302 switch (ntohs(ans
->ar_op
)) {
305 (void) printf("Got a rarp request.\n");
309 return (DLPI_SUCCESS
);
312 (void) fprintf(stderr
, "ifconfig: unknown "
313 "RARP opcode 0x%x\n", ans
->ar_op
);
316 } else if (retval
!= DLPI_ETIMEDOUT
) {
317 Perrdlpi("doifrevarp: dlpi_recv failed",
318 dlpi_linkname(dh
), retval
);
323 return (DLPI_ETIMEDOUT
);
327 dlpi_print_address(const char *linkname
)
329 uint_t physaddrlen
= DLPI_PHYSADDR_MAX
;
330 uchar_t physaddr
[DLPI_PHYSADDR_MAX
];
336 if (dlpi_open(linkname
, &dh
, 0) != DLPI_SUCCESS
) {
337 /* Do not report an error */
341 retv
= dlpi_get_physaddr(dh
, DL_CURR_PHYS_ADDR
, physaddr
, &physaddrlen
);
342 if (retv
!= DLPI_SUCCESS
) {
343 Perrdlpi("dlpi_get_physaddr failed", linkname
, retv
);
348 retv
= dlpi_info(dh
, &dlinfo
, 0);
349 if (retv
!= DLPI_SUCCESS
) {
350 Perrdlpi("dlpi_info failed", linkname
, retv
);
356 str
= _link_ntoa(physaddr
, NULL
, physaddrlen
, IFT_OTHER
);
358 if (str
!= NULL
&& physaddrlen
!= 0) {
359 switch (dlinfo
.di_mactype
) {
361 (void) printf("\tipib %s \n", str
);
364 (void) printf("\tether %s \n", str
);