2 * sys-bsd.c - System-dependent procedures for setting up
3 * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
5 * Copyright (c) 1989 Carnegie Mellon University.
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by Carnegie Mellon University. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 * $FreeBSD: src/usr.sbin/ppp/arp.c,v 1.37.2.3 2002/09/01 02:12:22 brian Exp $
21 * $DragonFly: src/usr.sbin/ppp/arp.c,v 1.2 2003/06/17 04:30:00 dillon Exp $
29 #include <sys/param.h>
30 #include <sys/socket.h>
32 #include <net/route.h>
33 #include <net/if_dl.h>
34 #include <netinet/in.h>
35 #include <netinet/if_ether.h>
36 #include <arpa/inet.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/ip.h>
45 #include <sys/sysctl.h>
57 #include "throughput.h"
58 #include "slcompress.h"
64 #include "descriptor.h"
79 * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
82 #define SET_SA_FAMILY(addr, family) \
83 memset((char *) &(addr), '\0', sizeof(addr)); \
84 addr.sa_family = (family); \
85 addr.sa_len = sizeof(addr);
91 * arp_SetProxy - Make a proxy ARP entry for the peer.
95 struct sockaddr_inarp dst
;
96 struct sockaddr_dl hwa
;
101 arp_ProxySub(struct bundle
*bundle
, struct in_addr addr
, int add
)
106 * Get the hardware address of an interface on the same subnet as our local
110 memset(&arpmsg
, 0, sizeof arpmsg
);
111 if (!arp_EtherAddr(addr
, &arpmsg
.hwa
, 0)) {
112 log_Printf(LogWARN
, "%s: Cannot determine ethernet address for proxy ARP\n",
116 routes
= ID0socket(PF_ROUTE
, SOCK_RAW
, AF_INET
);
118 log_Printf(LogERROR
, "arp_SetProxy: opening routing socket: %s\n",
122 arpmsg
.hdr
.rtm_type
= add
? RTM_ADD
: RTM_DELETE
;
123 arpmsg
.hdr
.rtm_flags
= RTF_ANNOUNCE
| RTF_HOST
| RTF_STATIC
;
124 arpmsg
.hdr
.rtm_version
= RTM_VERSION
;
125 arpmsg
.hdr
.rtm_seq
= ++bundle
->routing_seq
;
126 arpmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
127 arpmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
128 arpmsg
.dst
.sin_len
= sizeof(struct sockaddr_inarp
);
129 arpmsg
.dst
.sin_family
= AF_INET
;
130 arpmsg
.dst
.sin_addr
.s_addr
= addr
.s_addr
;
131 arpmsg
.dst
.sin_other
= SIN_PROXY
;
133 arpmsg
.hdr
.rtm_msglen
= (char *) &arpmsg
.hwa
- (char *) &arpmsg
134 + arpmsg
.hwa
.sdl_len
;
137 if (ID0write(routes
, &arpmsg
, arpmsg
.hdr
.rtm_msglen
) < 0 &&
138 !(!add
&& errno
== ESRCH
)) {
139 log_Printf(LogERROR
, "%s proxy arp entry %s: %s\n",
140 add
? "Add" : "Delete", inet_ntoa(addr
), strerror(errno
));
149 arp_SetProxy(struct bundle
*bundle
, struct in_addr addr
)
151 return (arp_ProxySub(bundle
, addr
, 1));
155 * arp_ClearProxy - Delete the proxy ARP entry for the peer.
158 arp_ClearProxy(struct bundle
*bundle
, struct in_addr addr
)
160 return (arp_ProxySub(bundle
, addr
, 0));
163 #else /* RTM_VERSION */
166 * arp_SetProxy - Make a proxy ARP entry for the peer.
169 arp_SetProxy(struct bundle
*bundle
, struct in_addr addr
, int s
)
171 struct arpreq arpreq
;
173 struct sockaddr_dl sdl
;
177 memset(&arpreq
, '\0', sizeof arpreq
);
180 * Get the hardware address of an interface on the same subnet as our local
183 if (!arp_EtherAddr(addr
, &dls
.sdl
, 1)) {
184 log_Printf(LOG_PHASE_BIT
, "Cannot determine ethernet address for "
188 arpreq
.arp_ha
.sa_len
= sizeof(struct sockaddr
);
189 arpreq
.arp_ha
.sa_family
= AF_UNSPEC
;
190 memcpy(arpreq
.arp_ha
.sa_data
, LLADDR(&dls
.sdl
), dls
.sdl
.sdl_alen
);
191 SET_SA_FAMILY(arpreq
.arp_pa
, AF_INET
);
192 ((struct sockaddr_in
*)&arpreq
.arp_pa
)->sin_addr
.s_addr
= addr
.s_addr
;
193 arpreq
.arp_flags
= ATF_PERM
| ATF_PUBL
;
194 if (ID0ioctl(s
, SIOCSARP
, (caddr_t
) & arpreq
) < 0) {
195 log_Printf(LogERROR
, "arp_SetProxy: ioctl(SIOCSARP): %s\n",
203 * arp_ClearProxy - Delete the proxy ARP entry for the peer.
206 arp_ClearProxy(struct bundle
*bundle
, struct in_addr addr
, int s
)
208 struct arpreq arpreq
;
210 memset(&arpreq
, '\0', sizeof arpreq
);
211 SET_SA_FAMILY(arpreq
.arp_pa
, AF_INET
);
212 ((struct sockaddr_in
*)&arpreq
.arp_pa
)->sin_addr
.s_addr
= addr
.s_addr
;
213 if (ID0ioctl(s
, SIOCDARP
, (caddr_t
) & arpreq
) < 0) {
214 log_Printf(LogERROR
, "arp_ClearProxy: ioctl(SIOCDARP): %s\n",
221 #endif /* RTM_VERSION */
225 * arp_EtherAddr - get the hardware address of an interface on the
226 * the same subnet as ipaddr.
230 arp_EtherAddr(struct in_addr ipaddr
, struct sockaddr_dl
*hwaddr
,
235 char *buf
, *ptr
, *end
;
236 struct if_msghdr
*ifm
;
237 struct ifa_msghdr
*ifam
;
238 struct sockaddr_dl
*dl
;
239 struct sockaddr
*sa
[RTAX_MAX
];
245 mib
[4] = NET_RT_IFLIST
;
248 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
249 log_Printf(LogERROR
, "arp_EtherAddr: sysctl: estimate: %s\n",
254 if ((buf
= malloc(needed
)) == NULL
)
257 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
265 ifm
= (struct if_msghdr
*)ptr
; /* On if_msghdr */
266 if (ifm
->ifm_type
!= RTM_IFINFO
)
268 dl
= (struct sockaddr_dl
*)(ifm
+ 1); /* Single _dl at end */
269 skip
= (ifm
->ifm_flags
& (IFF_UP
| IFF_BROADCAST
| IFF_POINTOPOINT
|
270 IFF_NOARP
| IFF_LOOPBACK
)) != (IFF_UP
| IFF_BROADCAST
);
271 ptr
+= ifm
->ifm_msglen
; /* First ifa_msghdr */
273 ifam
= (struct ifa_msghdr
*)ptr
; /* Next ifa_msghdr (alias) */
274 if (ifam
->ifam_type
!= RTM_NEWADDR
) /* finished ? */
276 ptr
+= ifam
->ifam_msglen
;
277 if (skip
|| (ifam
->ifam_addrs
& (RTA_NETMASK
|RTA_IFA
)) !=
278 (RTA_NETMASK
|RTA_IFA
))
280 /* Found a candidate. Do the addresses match ? */
281 if (log_IsKept(LogDEBUG
) &&
282 ptr
== (char *)ifm
+ ifm
->ifm_msglen
+ ifam
->ifam_msglen
)
283 log_Printf(LogDEBUG
, "%.*s interface is a candidate for proxy\n",
284 dl
->sdl_nlen
, dl
->sdl_data
);
286 iface_ParseHdr(ifam
, sa
);
288 if (sa
[RTAX_IFA
]->sa_family
== AF_INET
) {
289 struct sockaddr_in
*ifa
, *netmask
;
291 ifa
= (struct sockaddr_in
*)sa
[RTAX_IFA
];
292 netmask
= (struct sockaddr_in
*)sa
[RTAX_NETMASK
];
294 if (log_IsKept(LogDEBUG
)) {
297 strncpy(a
, inet_ntoa(netmask
->sin_addr
), sizeof a
- 1);
298 a
[sizeof a
- 1] = '\0';
299 log_Printf(LogDEBUG
, "Check addr %s, mask %s\n",
300 inet_ntoa(ifa
->sin_addr
), a
);
303 if ((ifa
->sin_addr
.s_addr
& netmask
->sin_addr
.s_addr
) ==
304 (ipaddr
.s_addr
& netmask
->sin_addr
.s_addr
)) {
305 log_Printf(verbose
? LogPHASE
: LogDEBUG
,
306 "Found interface %.*s for %s\n", dl
->sdl_alen
,
307 dl
->sdl_data
, inet_ntoa(ipaddr
));
308 memcpy(hwaddr
, dl
, dl
->sdl_len
);