8 #include <sys/socket.h>
10 #include <arpa/inet.h>
15 #include <asm/types.h>
16 #include <linux/netlink.h>
17 #include <linux/rtnetlink.h>
18 /*XXX #include <linux/ipv6.h>*/
20 struct in6_addr ifr6_addr;
25 typedef unsigned int nid_t;
26 typedef unsigned int xid_t;
29 #define HAS_ADDRESS 0x01
30 #define HAS_PREFIX 0x02
32 struct prefix_list *prev;
33 struct prefix_list *next;
48 /* from linux/include/net/ipv6.h */
49 static inline int ipv6_prefix_equal(struct in6_addr *prefix,
50 struct in6_addr *addr, int prefixlen)
52 uint32_t *a1 = prefix->s6_addr32, *a2 = addr->s6_addr32;
55 /* check complete u32 in prefix */
57 if (pdw && memcmp(a1, a2, pdw << 2))
60 /* check incomplete u32 in prefix */
61 pbi = prefixlen & 0x1f;
62 if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi))))
68 static int add_address_to_interface(int ifindex, struct in6_addr *address, int prefix)
70 struct in6_ifreq ireq;
73 ireq.ifr6_ifindex = ifindex;
74 ireq.ifr6_prefixlen = prefix;
75 memcpy(&ireq.ifr6_addr, address, sizeof(*address));
77 /* XXX should use netlink */
78 sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
82 if (ioctl(sock, SIOCSIFADDR, &ireq) == -1 && errno != EEXIST) {
91 static void do_slices_autoconf(struct prefix_list *head)
96 struct vc_net_nx addr;
97 struct prefix_list *i, *expired = NULL;
99 if ((dp = opendir("/proc/virtnet")) == NULL)
101 while ((de = readdir(dp)) != NULL) {
102 if (!isdigit(de->d_name[0]))
105 nid = strtoul(de->d_name, NULL, 10);
106 addr.type = vcNET_IPV6;
108 if (vc_net_remove(nid, &addr) == -1)
111 for (i = head->next; i;) {
113 if (i->mask & HAS_PREFIX && i->prefix.valid_until < time(NULL)) {
114 struct prefix_list *tmp;
116 i->next->prev = i->prev;
118 i->prev->next = i->next;
125 if (i->mask != (HAS_ADDRESS|HAS_PREFIX))
129 addr.mask[0] = i->prefix.prefix_len;
130 memcpy(addr.ip, &i->address.addr, sizeof(struct in6_addr));
131 addr.ip[2] = htonl((ntohl(addr.ip[2]) & 0xffffff00) | ((nid & 0x7f00) >> 7));
132 addr.ip[3] = htonl((ntohl(addr.ip[3]) & 0x00ffffff) | ((nid & 0xff) << 25));
133 if (vc_net_add(nid, &addr) == -1) {
134 perror("vc_net_add");
137 if (add_address_to_interface(i->ifindex, (struct in6_addr *) addr.ip, i->prefix.prefix_len) == -1) {
138 perror("add_address_to_interface");
148 static int add_prefix(struct prefix_list *head, struct prefixmsg *msg,
149 struct in6_addr *prefix, struct prefix_cacheinfo *cache)
151 struct prefix_list *i = head;
152 if (!msg || !prefix || !cache)
158 if (ipv6_prefix_equal(prefix, &i->prefix.addr, msg->prefix_len) ||
159 ipv6_prefix_equal(prefix, &i->address.addr, msg->prefix_len)) {
160 i->mask |= HAS_PREFIX;
161 i->ifindex = msg->prefix_ifindex;
162 memcpy(&i->prefix.addr, prefix, sizeof(*prefix));
163 i->prefix.prefix_len = msg->prefix_len;
164 i->prefix.valid_until = time(NULL) + cache->preferred_time;
169 i->next = calloc(1, sizeof(*i));
174 i->mask = HAS_PREFIX;
175 memcpy(&i->prefix.addr, prefix, sizeof(*prefix));
176 i->prefix.prefix_len = msg->prefix_len;
177 i->prefix.valid_until = time(NULL) + cache->preferred_time;
182 static inline int add_address(struct prefix_list *head, struct ifaddrmsg *msg,
183 struct in6_addr *address, struct ifa_cacheinfo *cache)
185 struct prefix_list *i = head;
186 if (!msg || !address || !cache)
189 if (address->s6_addr[11] != 0xFF || address->s6_addr[12] != 0xFE)
195 if (ipv6_prefix_equal(address, &i->prefix.addr, msg->ifa_prefixlen) ||
196 ipv6_prefix_equal(address, &i->address.addr, msg->ifa_prefixlen)) {
197 i->mask |= HAS_ADDRESS;
198 memcpy(&i->address.addr, address, sizeof(*address));
199 i->address.prefix_len = msg->ifa_prefixlen;
200 i->address.valid_until = time(NULL) + cache->ifa_prefered;
205 i->next = calloc(1, sizeof(*i));
210 i->mask = HAS_ADDRESS;
211 memcpy(&i->address.addr, address, sizeof(*address));
212 i->address.prefix_len = msg->ifa_prefixlen;
213 i->address.valid_until = time(NULL) + cache->ifa_prefered;
218 int main(int argc, char *argv[])
221 struct sockaddr_nl sa;
222 struct prefix_list head = { .prev = NULL, .next = NULL };
224 sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
229 sa.nl_family = AF_NETLINK;
230 sa.nl_groups = RTMGRP_IPV6_PREFIX|RTMGRP_IPV6_IFADDR;
231 if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
237 char buf[4000], *payload;
238 struct nlmsghdr *nlh;
239 ssize_t len, this_len;
240 socklen_t socklen = sizeof(sa);
242 if ((len = recvfrom(sock, buf, sizeof(buf), 0,
243 (struct sockaddr *) &sa, &socklen)) <= 0)
245 for (nlh = (struct nlmsghdr *) buf; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
248 if (nlh->nlmsg_type == NLMSG_DONE)
250 else if (nlh->nlmsg_type == NLMSG_ERROR)
253 this_len = NLMSG_ALIGN((nlh)->nlmsg_len) - NLMSG_LENGTH(0);
254 payload = NLMSG_DATA(nlh);
255 if (sa.nl_groups == RTMGRP_IPV6_PREFIX) {
256 struct prefixmsg *prefixmsg;
257 struct in6_addr *prefix;
258 struct prefix_cacheinfo *cacheinfo;
260 prefixmsg = (struct prefixmsg *) payload;
263 for (nla = (struct nlattr *)(payload + sizeof(*prefixmsg)); nla < payload + this_len; nla = (char *) nla + nla->nla_len) {
264 if (nla->nla_type == PREFIX_ADDRESS)
265 prefix = (struct in6_addr *)(((char *) nla) + sizeof(*nla));
266 else if (nla->nla_type == PREFIX_CACHEINFO)
267 cacheinfo = (struct prefix_cacheinfo *)(((char *) nla) + sizeof(*nla));
269 if (add_prefix(&head, prefixmsg, prefix, cacheinfo) == -1) {
270 printf("Adding prefix failed!\n");
273 else if (sa.nl_groups == RTMGRP_IPV6_IFADDR) {
274 struct ifaddrmsg *ifaddrmsg;
275 struct in6_addr *address;
276 struct ifa_cacheinfo *cacheinfo;
278 ifaddrmsg = (struct ifaddrmsg *) payload;
281 for (nla = (struct nlattr *)(payload + sizeof(*ifaddrmsg)); nla < payload + this_len; nla = (char *) nla + nla->nla_len) {
282 if (nla->nla_type == IFA_ADDRESS)
283 address = (struct in6_addr *)(((char *) nla) + sizeof(*nla));
284 else if (nla->nla_type == IFA_CACHEINFO)
285 cacheinfo = (struct ifa_cacheinfo *)(((char *) nla) + sizeof(*nla));
287 if (add_address(&head, ifaddrmsg, address, cacheinfo) == -1) {
288 printf("Adding address failed!\n");
292 do_slices_autoconf(&head);