2 * $Id: device-linux.c,v 1.28 2011/02/06 03:41:38 reubenhwk Exp $
5 * Lars Fenneberg <lf@elemental.net>
7 * This software is Copyright 1996,1997 by the above mentioned author(s),
10 * The license which is distributed with this software in the file COPYRIGHT
11 * applies to this software. If your distribution is missing this file, you
12 * may request it from <pekkas@netcore.fi>.
20 #include "pathnames.h" /* for PATH_PROC_NET_IF_INET6 */
22 #ifndef IPV6_ADDR_LINKLOCAL
23 #define IPV6_ADDR_LINKLOCAL 0x0020U
27 * this function gets the hardware type and address of an interface,
28 * determines the link layer token length and checks it against
29 * the defined prefixes
32 setup_deviceinfo(struct Interface
*iface
)
35 struct AdvPrefix
*prefix
;
36 char zero
[sizeof(iface
->if_addr
)];
38 strncpy(ifr
.ifr_name
, iface
->Name
, IFNAMSIZ
-1);
39 ifr
.ifr_name
[IFNAMSIZ
-1] = '\0';
41 if (ioctl(sock
, SIOCGIFMTU
, &ifr
) < 0) {
42 flog(LOG_ERR
, "ioctl(SIOCGIFMTU) failed for %s: %s",
43 iface
->Name
, strerror(errno
));
47 dlog(LOG_DEBUG
, 3, "mtu for %s is %d", iface
->Name
, ifr
.ifr_mtu
);
48 iface
->if_maxmtu
= ifr
.ifr_mtu
;
50 if (ioctl(sock
, SIOCGIFHWADDR
, &ifr
) < 0)
52 flog(LOG_ERR
, "ioctl(SIOCGIFHWADDR) failed for %s: %s",
53 iface
->Name
, strerror(errno
));
57 dlog(LOG_DEBUG
, 3, "hardware type for %s is %d", iface
->Name
,
58 ifr
.ifr_hwaddr
.sa_family
);
60 switch(ifr
.ifr_hwaddr
.sa_family
)
63 iface
->if_hwaddr_len
= 48;
64 iface
->if_prefix_len
= 64;
68 iface
->if_hwaddr_len
= 48;
69 iface
->if_prefix_len
= 64;
71 #endif /* ARPHDR_FDDI */
74 iface
->if_hwaddr_len
= 8;
75 iface
->if_prefix_len
= -1;
76 iface
->if_maxmtu
= -1;
78 #endif /* ARPHDR_ARCNET */
80 iface
->if_hwaddr_len
= -1;
81 iface
->if_prefix_len
= -1;
82 iface
->if_maxmtu
= -1;
86 dlog(LOG_DEBUG
, 3, "link layer token length for %s is %d", iface
->Name
,
87 iface
->if_hwaddr_len
);
89 dlog(LOG_DEBUG
, 3, "prefix length for %s is %d", iface
->Name
,
90 iface
->if_prefix_len
);
92 if (iface
->if_hwaddr_len
!= -1) {
93 unsigned int if_hwaddr_len_bytes
= (iface
->if_hwaddr_len
+ 7) >> 3;
95 if (if_hwaddr_len_bytes
> sizeof(iface
->if_hwaddr
)) {
96 flog(LOG_ERR
, "address length %d too big for %s", if_hwaddr_len_bytes
, iface
->Name
);
99 memcpy(iface
->if_hwaddr
, ifr
.ifr_hwaddr
.sa_data
, if_hwaddr_len_bytes
);
101 memset(zero
, 0, sizeof(zero
));
102 if (!memcmp(iface
->if_hwaddr
, zero
, if_hwaddr_len_bytes
))
103 flog(LOG_WARNING
, "WARNING, MAC address on %s is all zero!",
107 prefix
= iface
->AdvPrefixList
;
110 if ((iface
->if_prefix_len
!= -1) &&
111 (iface
->if_prefix_len
!= prefix
->PrefixLen
))
113 flog(LOG_WARNING
, "prefix length should be %d for %s",
114 iface
->if_prefix_len
, iface
->Name
);
117 prefix
= prefix
->next
;
124 * this function extracts the link local address and interface index
125 * from PATH_PROC_NET_IF_INET6. Note: 'sock' unused in Linux.
127 int setup_linklocal_addr(struct Interface
*iface
)
131 unsigned int plen
, scope
, dad_status
, if_idx
;
132 char devname
[IFNAMSIZ
];
134 if ((fp
= fopen(PATH_PROC_NET_IF_INET6
, "r")) == NULL
)
136 flog(LOG_ERR
, "can't open %s: %s", PATH_PROC_NET_IF_INET6
,
141 while (fscanf(fp
, "%32s %x %02x %02x %02x %15s\n",
142 str_addr
, &if_idx
, &plen
, &scope
, &dad_status
,
145 if (scope
== IPV6_ADDR_LINKLOCAL
&&
146 strcmp(devname
, iface
->Name
) == 0)
148 struct in6_addr addr
;
154 sscanf(str_addr
+ i
* 2, "%02x", &ap
);
155 addr
.s6_addr
[i
] = (unsigned char)ap
;
157 memcpy(&iface
->if_addr
, &addr
, sizeof(iface
->if_addr
));
159 iface
->if_index
= if_idx
;
165 flog(LOG_ERR
, "no linklocal address configured for %s", iface
->Name
);
170 int setup_allrouters_membership(struct Interface
*iface
)
172 struct ipv6_mreq mreq
;
174 memset(&mreq
, 0, sizeof(mreq
));
175 mreq
.ipv6mr_interface
= iface
->if_index
;
177 /* ipv6-allrouters: ff02::2 */
178 mreq
.ipv6mr_multiaddr
.s6_addr32
[0] = htonl(0xFF020000);
179 mreq
.ipv6mr_multiaddr
.s6_addr32
[3] = htonl(0x2);
181 if (setsockopt(sock
, SOL_IPV6
, IPV6_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
)) < 0)
183 /* linux-2.6.12-bk4 returns error with HUP signal but keep listening */
184 if (errno
!= EADDRINUSE
)
186 flog(LOG_ERR
, "can't join ipv6-allrouters on %s", iface
->Name
);
194 int check_allrouters_membership(struct Interface
*iface
)
196 #define ALL_ROUTERS_MCAST "ff020000000000000000000000000002"
199 unsigned int if_idx
, allrouters_ok
=0;
201 char buffer
[301] = {""}, *str
;
204 if ((fp
= fopen(PATH_PROC_NET_IGMP6
, "r")) == NULL
)
206 flog(LOG_ERR
, "can't open %s: %s", PATH_PROC_NET_IGMP6
,
211 str
= fgets(buffer
, 300, fp
);
213 while (str
&& (ret
= sscanf(str
, "%u %*s %32[0-9A-Fa-f]", &if_idx
, addr
)) ) {
215 if (iface
->if_index
== if_idx
) {
216 if (strncmp(addr
, ALL_ROUTERS_MCAST
, sizeof(addr
)) == 0){
222 str
= fgets(buffer
, 300, fp
);
227 if (!allrouters_ok
) {
228 flog(LOG_WARNING
, "resetting ipv6-allrouters membership on %s", iface
->Name
);
229 setup_allrouters_membership(iface
);
235 /* note: also called from the root context */
237 set_interface_var(const char *iface
,
238 const char *var
, const char *name
,
242 char spath
[64+IFNAMSIZ
]; /* XXX: magic constant */
243 if (snprintf(spath
, sizeof(spath
), var
, iface
) >= sizeof(spath
))
246 if (access(spath
, F_OK
) != 0)
249 fp
= fopen(spath
, "w");
252 flog(LOG_ERR
, "failed to set %s (%u) for %s: %s",
253 name
, val
, iface
, strerror(errno
));
256 fprintf(fp
, "%u", val
);
263 set_interface_linkmtu(const char *iface
, uint32_t mtu
)
265 if (privsep_enabled())
266 return privsep_interface_linkmtu(iface
, mtu
);
268 return set_interface_var(iface
,
269 PROC_SYS_IP6_LINKMTU
, "LinkMTU",
274 set_interface_curhlim(const char *iface
, uint8_t hlim
)
276 if (privsep_enabled())
277 return privsep_interface_curhlim(iface
, hlim
);
279 return set_interface_var(iface
,
280 PROC_SYS_IP6_CURHLIM
, "CurHopLimit",
285 set_interface_reachtime(const char *iface
, uint32_t rtime
)
289 if (privsep_enabled())
290 return privsep_interface_reachtime(iface
, rtime
);
292 ret
= set_interface_var(iface
,
293 PROC_SYS_IP6_BASEREACHTIME_MS
,
297 ret
= set_interface_var(iface
,
298 PROC_SYS_IP6_BASEREACHTIME
,
299 "BaseReachableTimer",
300 rtime
/ 1000); /* sec */
305 set_interface_retranstimer(const char *iface
, uint32_t rettimer
)
309 if (privsep_enabled())
310 return privsep_interface_retranstimer(iface
, rettimer
);
312 ret
= set_interface_var(iface
,
313 PROC_SYS_IP6_RETRANSTIMER_MS
,
317 ret
= set_interface_var(iface
,
318 PROC_SYS_IP6_RETRANSTIMER
,
320 rettimer
/ 1000 * USER_HZ
); /* XXX user_hz */