2 This file is part of systemd.
4 Copyright (C) 2014 Intel Corporation. All rights reserved.
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/icmp6.h>
22 #include <netinet/in.h>
23 #include <netinet/ip6.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
29 #include <linux/if_packet.h>
32 #include "icmp6-util.h"
33 #include "socket-util.h"
35 #define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
36 { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
39 #define IN6ADDR_ALL_NODES_MULTICAST_INIT \
40 { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
43 int icmp6_bind_router_solicitation(int index
) {
44 struct icmp6_filter filter
= { };
45 struct ipv6_mreq mreq
= {
46 .ipv6mr_multiaddr
= IN6ADDR_ALL_NODES_MULTICAST_INIT
,
47 .ipv6mr_interface
= index
,
49 _cleanup_close_
int s
= -1;
50 int r
, zero
= 0, one
= 1, hops
= 255;
52 s
= socket(AF_INET6
, SOCK_RAW
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, IPPROTO_ICMPV6
);
56 ICMP6_FILTER_SETBLOCKALL(&filter
);
57 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT
, &filter
);
58 r
= setsockopt(s
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filter
, sizeof(filter
));
62 /* RFC 3315, section 6.7, bullet point 2 may indicate that an
63 IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
64 Empirical experiments indicates otherwise and therefore an
65 IPV6_MULTICAST_IF socket option is used here instead */
66 r
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &index
, sizeof(index
));
70 r
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &zero
, sizeof(zero
));
74 r
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &hops
, sizeof(hops
));
78 r
= setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
));
82 r
= setsockopt(s
, SOL_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
91 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
92 struct sockaddr_in6 dst
= {
93 .sin6_family
= AF_INET6
,
94 .sin6_addr
= IN6ADDR_ALL_ROUTERS_MULTICAST_INIT
,
97 struct nd_router_solicit rs
;
98 struct nd_opt_hdr rs_opt
;
99 struct ether_addr rs_opt_mac
;
101 .rs
.nd_rs_type
= ND_ROUTER_SOLICIT
,
102 .rs_opt
.nd_opt_type
= ND_OPT_SOURCE_LINKADDR
,
103 .rs_opt
.nd_opt_len
= 1,
107 .iov_len
= sizeof(rs
),
109 struct msghdr msg
= {
111 .msg_namelen
= sizeof(dst
),
120 rs
.rs_opt_mac
= *ether_addr
;
122 r
= sendmsg(s
, &msg
, 0);