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.
28 #include <sys/param.h>
29 #include <sys/socket.h>
31 #include <net/route.h>
32 #include <net/if_dl.h>
33 #include <netinet/in.h>
34 #include <netinet/if_ether.h>
35 #include <arpa/inet.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
44 #include <sys/sysctl.h>
56 #include "throughput.h"
57 #include "slcompress.h"
63 #include "descriptor.h"
78 * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
81 #define SET_SA_FAMILY(addr, family) \
82 memset((char *) &(addr), '\0', sizeof(addr)); \
83 addr.sa_family = (family); \
84 addr.sa_len = sizeof(addr);
90 * arp_SetProxy - Make a proxy ARP entry for the peer.
94 struct sockaddr_inarp dst
;
95 struct sockaddr_dl hwa
;
100 arp_ProxySub(struct bundle
*bundle
, struct in_addr addr
, int add
)
105 * Get the hardware address of an interface on the same subnet as our local
109 memset(&arpmsg
, 0, sizeof arpmsg
);
110 if (!arp_EtherAddr(addr
, &arpmsg
.hwa
, 0)) {
111 log_Printf(LogWARN
, "%s: Cannot determine ethernet address for proxy ARP\n",
115 routes
= ID0socket(PF_ROUTE
, SOCK_RAW
, AF_INET
);
117 log_Printf(LogERROR
, "arp_SetProxy: opening routing socket: %s\n",
121 arpmsg
.hdr
.rtm_type
= add
? RTM_ADD
: RTM_DELETE
;
122 arpmsg
.hdr
.rtm_flags
= RTF_ANNOUNCE
| RTF_HOST
| RTF_STATIC
;
123 arpmsg
.hdr
.rtm_version
= RTM_VERSION
;
124 arpmsg
.hdr
.rtm_seq
= ++bundle
->routing_seq
;
125 arpmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
126 arpmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
127 arpmsg
.dst
.sin_len
= sizeof(struct sockaddr_inarp
);
128 arpmsg
.dst
.sin_family
= AF_INET
;
129 arpmsg
.dst
.sin_addr
.s_addr
= addr
.s_addr
;
130 arpmsg
.dst
.sin_other
= SIN_PROXY
;
132 arpmsg
.hdr
.rtm_msglen
= (char *) &arpmsg
.hwa
- (char *) &arpmsg
133 + arpmsg
.hwa
.sdl_len
;
136 if (ID0write(routes
, &arpmsg
, arpmsg
.hdr
.rtm_msglen
) < 0 &&
137 !(!add
&& errno
== ESRCH
)) {
138 log_Printf(LogERROR
, "%s proxy arp entry %s: %s\n",
139 add
? "Add" : "Delete", inet_ntoa(addr
), strerror(errno
));
148 arp_SetProxy(struct bundle
*bundle
, struct in_addr addr
)
150 return (arp_ProxySub(bundle
, addr
, 1));
154 * arp_ClearProxy - Delete the proxy ARP entry for the peer.
157 arp_ClearProxy(struct bundle
*bundle
, struct in_addr addr
)
159 return (arp_ProxySub(bundle
, addr
, 0));
162 #else /* RTM_VERSION */
165 * arp_SetProxy - Make a proxy ARP entry for the peer.
168 arp_SetProxy(struct bundle
*bundle
, struct in_addr addr
, int s
)
170 struct arpreq arpreq
;
172 struct sockaddr_dl sdl
;
176 memset(&arpreq
, '\0', sizeof arpreq
);
179 * Get the hardware address of an interface on the same subnet as our local
182 if (!arp_EtherAddr(addr
, &dls
.sdl
, 1)) {
183 log_Printf(LOG_PHASE_BIT
, "Cannot determine ethernet address for "
187 arpreq
.arp_ha
.sa_len
= sizeof(struct sockaddr
);
188 arpreq
.arp_ha
.sa_family
= AF_UNSPEC
;
189 memcpy(arpreq
.arp_ha
.sa_data
, LLADDR(&dls
.sdl
), dls
.sdl
.sdl_alen
);
190 SET_SA_FAMILY(arpreq
.arp_pa
, AF_INET
);
191 ((struct sockaddr_in
*)&arpreq
.arp_pa
)->sin_addr
.s_addr
= addr
.s_addr
;
192 arpreq
.arp_flags
= ATF_PERM
| ATF_PUBL
;
193 if (ID0ioctl(s
, SIOCSARP
, (caddr_t
) & arpreq
) < 0) {
194 log_Printf(LogERROR
, "arp_SetProxy: ioctl(SIOCSARP): %s\n",
202 * arp_ClearProxy - Delete the proxy ARP entry for the peer.
205 arp_ClearProxy(struct bundle
*bundle
, struct in_addr addr
, int s
)
207 struct arpreq arpreq
;
209 memset(&arpreq
, '\0', sizeof arpreq
);
210 SET_SA_FAMILY(arpreq
.arp_pa
, AF_INET
);
211 ((struct sockaddr_in
*)&arpreq
.arp_pa
)->sin_addr
.s_addr
= addr
.s_addr
;
212 if (ID0ioctl(s
, SIOCDARP
, (caddr_t
) & arpreq
) < 0) {
213 log_Printf(LogERROR
, "arp_ClearProxy: ioctl(SIOCDARP): %s\n",
220 #endif /* RTM_VERSION */
224 * arp_EtherAddr - get the hardware address of an interface on the
225 * the same subnet as ipaddr.
229 arp_EtherAddr(struct in_addr ipaddr
, struct sockaddr_dl
*hwaddr
,
234 char *buf
, *ptr
, *end
;
235 struct if_msghdr
*ifm
;
236 struct ifa_msghdr
*ifam
;
237 struct sockaddr_dl
*dl
;
238 struct sockaddr
*sa
[RTAX_MAX
];
244 mib
[4] = NET_RT_IFLIST
;
247 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
248 log_Printf(LogERROR
, "arp_EtherAddr: sysctl: estimate: %s\n",
253 if ((buf
= malloc(needed
)) == NULL
)
256 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
264 ifm
= (struct if_msghdr
*)ptr
; /* On if_msghdr */
265 if (ifm
->ifm_type
!= RTM_IFINFO
)
267 dl
= (struct sockaddr_dl
*)(ifm
+ 1); /* Single _dl at end */
268 skip
= (ifm
->ifm_flags
& (IFF_UP
| IFF_BROADCAST
| IFF_POINTOPOINT
|
269 IFF_NOARP
| IFF_LOOPBACK
)) != (IFF_UP
| IFF_BROADCAST
);
270 ptr
+= ifm
->ifm_msglen
; /* First ifa_msghdr */
272 ifam
= (struct ifa_msghdr
*)ptr
; /* Next ifa_msghdr (alias) */
273 if (ifam
->ifam_type
!= RTM_NEWADDR
) /* finished ? */
275 ptr
+= ifam
->ifam_msglen
;
276 if (skip
|| (ifam
->ifam_addrs
& (RTA_NETMASK
|RTA_IFA
)) !=
277 (RTA_NETMASK
|RTA_IFA
))
279 /* Found a candidate. Do the addresses match ? */
280 if (log_IsKept(LogDEBUG
) &&
281 ptr
== (char *)ifm
+ ifm
->ifm_msglen
+ ifam
->ifam_msglen
)
282 log_Printf(LogDEBUG
, "%.*s interface is a candidate for proxy\n",
283 dl
->sdl_nlen
, dl
->sdl_data
);
285 iface_ParseHdr(ifam
, sa
);
287 if (sa
[RTAX_IFA
]->sa_family
== AF_INET
) {
288 struct sockaddr_in
*ifa
, *netmask
;
290 ifa
= (struct sockaddr_in
*)sa
[RTAX_IFA
];
291 netmask
= (struct sockaddr_in
*)sa
[RTAX_NETMASK
];
293 if (log_IsKept(LogDEBUG
)) {
296 strncpy(a
, inet_ntoa(netmask
->sin_addr
), sizeof a
- 1);
297 a
[sizeof a
- 1] = '\0';
298 log_Printf(LogDEBUG
, "Check addr %s, mask %s\n",
299 inet_ntoa(ifa
->sin_addr
), a
);
302 if ((ifa
->sin_addr
.s_addr
& netmask
->sin_addr
.s_addr
) ==
303 (ipaddr
.s_addr
& netmask
->sin_addr
.s_addr
)) {
304 log_Printf(verbose
? LogPHASE
: LogDEBUG
,
305 "Found interface %.*s for %s\n", dl
->sdl_nlen
,
306 dl
->sdl_data
, inet_ntoa(ipaddr
));
307 memcpy(hwaddr
, dl
, dl
->sdl_len
);