3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 #include <linux/netlink.h>
12 #include <linux/rtnetlink.h>
13 #include <linux/if_addr.h>
14 #include <linux/if_arp.h>
15 #include <linux/inetdevice.h>
16 #include <net/netlink.h>
20 struct socket
*nlsock
;
21 struct afs_interface
*bufs
;
31 int (*parse
)(struct afs_rtm_desc
*, struct nlmsghdr
*);
35 * parse an RTM_GETADDR response
37 static int afs_rtm_getaddr_parse(struct afs_rtm_desc
*desc
,
38 struct nlmsghdr
*nlhdr
)
40 struct afs_interface
*this;
41 struct ifaddrmsg
*ifa
;
42 struct rtattr
*rtattr
;
46 ifa
= (struct ifaddrmsg
*) NLMSG_DATA(nlhdr
);
48 _enter("{ix=%d,af=%d}", ifa
->ifa_index
, ifa
->ifa_family
);
50 if (ifa
->ifa_family
!= AF_INET
) {
51 _leave(" = 0 [family %d]", ifa
->ifa_family
);
54 if (desc
->nbufs
>= desc
->maxbufs
) {
55 _leave(" = 0 [max %zu/%zu]", desc
->nbufs
, desc
->maxbufs
);
59 this = &desc
->bufs
[desc
->nbufs
];
61 this->index
= ifa
->ifa_index
;
62 this->netmask
.s_addr
= inet_make_mask(ifa
->ifa_prefixlen
);
65 rtattr
= NLMSG_DATA(nlhdr
) + NLMSG_ALIGN(sizeof(struct ifaddrmsg
));
66 len
= NLMSG_PAYLOAD(nlhdr
, sizeof(struct ifaddrmsg
));
69 for (; RTA_OK(rtattr
, len
); rtattr
= RTA_NEXT(rtattr
, len
)) {
70 switch (rtattr
->rta_type
) {
72 memcpy(&this->address
, RTA_DATA(rtattr
), 4);
75 name
= RTA_DATA(rtattr
);
80 _debug("%s: "NIPQUAD_FMT
"/"NIPQUAD_FMT
,
81 name
, NIPQUAD(this->address
), NIPQUAD(this->netmask
));
89 * parse an RTM_GETLINK response for MTUs
91 static int afs_rtm_getlink_if_parse(struct afs_rtm_desc
*desc
,
92 struct nlmsghdr
*nlhdr
)
94 struct afs_interface
*this;
95 struct ifinfomsg
*ifi
;
96 struct rtattr
*rtattr
;
100 ifi
= (struct ifinfomsg
*) NLMSG_DATA(nlhdr
);
102 _enter("{ix=%d}", ifi
->ifi_index
);
104 for (loop
= 0; loop
< desc
->nbufs
; loop
++) {
105 this = &desc
->bufs
[loop
];
106 if (this->index
== ifi
->ifi_index
)
110 _leave(" = 0 [no match]");
114 if (ifi
->ifi_type
== ARPHRD_LOOPBACK
&& !desc
->wantloopback
) {
115 _leave(" = 0 [loopback]");
119 rtattr
= NLMSG_DATA(nlhdr
) + NLMSG_ALIGN(sizeof(struct ifinfomsg
));
120 len
= NLMSG_PAYLOAD(nlhdr
, sizeof(struct ifinfomsg
));
123 for (; RTA_OK(rtattr
, len
); rtattr
= RTA_NEXT(rtattr
, len
)) {
124 switch (rtattr
->rta_type
) {
126 memcpy(&this->mtu
, RTA_DATA(rtattr
), 4);
129 name
= RTA_DATA(rtattr
);
134 _debug("%s: "NIPQUAD_FMT
"/"NIPQUAD_FMT
" mtu %u",
135 name
, NIPQUAD(this->address
), NIPQUAD(this->netmask
),
143 * parse an RTM_GETLINK response for the MAC address belonging to the lowest
144 * non-internal interface
146 static int afs_rtm_getlink_mac_parse(struct afs_rtm_desc
*desc
,
147 struct nlmsghdr
*nlhdr
)
149 struct ifinfomsg
*ifi
;
150 struct rtattr
*rtattr
;
155 ifi
= (struct ifinfomsg
*) NLMSG_DATA(nlhdr
);
157 _enter("{ix=%d}", ifi
->ifi_index
);
159 if (ifi
->ifi_index
>= desc
->mac_index
) {
160 _leave(" = 0 [high]");
163 if (ifi
->ifi_type
== ARPHRD_LOOPBACK
) {
164 _leave(" = 0 [loopback]");
168 rtattr
= NLMSG_DATA(nlhdr
) + NLMSG_ALIGN(sizeof(struct ifinfomsg
));
169 remain
= NLMSG_PAYLOAD(nlhdr
, sizeof(struct ifinfomsg
));
173 for (; RTA_OK(rtattr
, remain
); rtattr
= RTA_NEXT(rtattr
, remain
)) {
174 switch (rtattr
->rta_type
) {
176 len
= RTA_PAYLOAD(rtattr
);
177 memcpy(desc
->mac
, RTA_DATA(rtattr
),
178 min_t(size_t, len
, 6));
179 desc
->mac_index
= ifi
->ifi_index
;
183 name
= RTA_DATA(rtattr
);
189 _debug("%s: %02x:%02x:%02x:%02x:%02x:%02x",
191 desc
->mac
[0], desc
->mac
[1], desc
->mac
[2],
192 desc
->mac
[3], desc
->mac
[4], desc
->mac
[5]);
199 * read the rtnetlink response and pass to parsing routine
201 static int afs_read_rtm(struct afs_rtm_desc
*desc
)
203 struct nlmsghdr
*nlhdr
, tmphdr
;
208 int len
, ret
, remain
;
213 /* first of all peek to see how big the packet is */
214 memset(&msg
, 0, sizeof(msg
));
215 iov
[0].iov_base
= &tmphdr
;
216 iov
[0].iov_len
= sizeof(tmphdr
);
217 len
= kernel_recvmsg(desc
->nlsock
, &msg
, iov
, 1,
218 sizeof(tmphdr
), MSG_PEEK
| MSG_TRUNC
);
220 _leave(" = %d [peek]", len
);
225 if (len
< sizeof(tmphdr
) || len
< NLMSG_PAYLOAD(&tmphdr
, 0)) {
226 _leave(" = -EMSGSIZE");
230 if (desc
->datamax
< len
) {
233 data
= kmalloc(len
, GFP_KERNEL
);
240 /* read all the data from this packet */
241 iov
[0].iov_base
= desc
->data
;
242 iov
[0].iov_len
= desc
->datamax
;
243 desc
->datalen
= kernel_recvmsg(desc
->nlsock
, &msg
, iov
, 1,
245 if (desc
->datalen
< 0) {
246 _leave(" = %ld [recv]", desc
->datalen
);
247 return desc
->datalen
;
252 /* check if the header is valid */
253 if (!NLMSG_OK(nlhdr
, desc
->datalen
) ||
254 nlhdr
->nlmsg_type
== NLMSG_ERROR
) {
259 /* see if this is the last message */
260 if (nlhdr
->nlmsg_type
== NLMSG_DONE
||
261 !(nlhdr
->nlmsg_flags
& NLM_F_MULTI
))
264 /* parse the bits we got this time */
265 nlmsg_for_each_msg(nlhdr
, desc
->data
, desc
->datalen
, remain
) {
266 ret
= desc
->parse(desc
, nlhdr
);
268 _leave(" = %d [parse]", ret
);
280 * list the interface bound addresses to get the address and netmask
282 static int afs_rtm_getaddr(struct afs_rtm_desc
*desc
)
289 struct nlmsghdr nl_msg
__attribute__((aligned(NLMSG_ALIGNTO
)));
290 struct ifaddrmsg addr_msg
__attribute__((aligned(NLMSG_ALIGNTO
)));
295 memset(&request
, 0, sizeof(request
));
297 request
.nl_msg
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
298 request
.nl_msg
.nlmsg_type
= RTM_GETADDR
;
299 request
.nl_msg
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
;
300 request
.nl_msg
.nlmsg_seq
= desc
->msg_seq
++;
301 request
.nl_msg
.nlmsg_pid
= 0;
303 memset(&msg
, 0, sizeof(msg
));
304 iov
[0].iov_base
= &request
;
305 iov
[0].iov_len
= sizeof(request
);
307 ret
= kernel_sendmsg(desc
->nlsock
, &msg
, iov
, 1, iov
[0].iov_len
);
308 _leave(" = %d", ret
);
313 * list the interface link statuses to get the MTUs
315 static int afs_rtm_getlink(struct afs_rtm_desc
*desc
)
322 struct nlmsghdr nl_msg
__attribute__((aligned(NLMSG_ALIGNTO
)));
323 struct ifinfomsg link_msg
__attribute__((aligned(NLMSG_ALIGNTO
)));
328 memset(&request
, 0, sizeof(request
));
330 request
.nl_msg
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
331 request
.nl_msg
.nlmsg_type
= RTM_GETLINK
;
332 request
.nl_msg
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ROOT
;
333 request
.nl_msg
.nlmsg_seq
= desc
->msg_seq
++;
334 request
.nl_msg
.nlmsg_pid
= 0;
336 memset(&msg
, 0, sizeof(msg
));
337 iov
[0].iov_base
= &request
;
338 iov
[0].iov_len
= sizeof(request
);
340 ret
= kernel_sendmsg(desc
->nlsock
, &msg
, iov
, 1, iov
[0].iov_len
);
341 _leave(" = %d", ret
);
346 * cull any interface records for which there isn't an MTU value
348 static void afs_cull_interfaces(struct afs_rtm_desc
*desc
)
350 struct afs_interface
*bufs
= desc
->bufs
;
351 size_t nbufs
= desc
->nbufs
;
354 _enter("{%zu}", nbufs
);
356 for (loop
= 0; loop
< nbufs
; loop
++) {
357 if (desc
->bufs
[loop
].mtu
!= 0) {
359 ASSERTCMP(loop
, >, point
);
360 bufs
[point
] = bufs
[loop
];
367 _leave(" [%zu/%zu]", desc
->nbufs
, nbufs
);
371 * get a list of this system's interface IPv4 addresses, netmasks and MTUs
372 * - returns the number of interface records in the buffer
374 int afs_get_ipv4_interfaces(struct afs_interface
*bufs
, size_t maxbufs
,
377 struct afs_rtm_desc desc
;
382 memset(&desc
, 0, sizeof(desc
));
384 desc
.maxbufs
= maxbufs
;
385 desc
.wantloopback
= wantloopback
;
387 ret
= sock_create_kern(AF_NETLINK
, SOCK_DGRAM
, NETLINK_ROUTE
,
390 _leave(" = %d [sock]", ret
);
394 /* issue RTM_GETADDR */
395 desc
.parse
= afs_rtm_getaddr_parse
;
396 ret
= afs_rtm_getaddr(&desc
);
399 ret
= afs_read_rtm(&desc
);
403 /* issue RTM_GETLINK */
404 desc
.parse
= afs_rtm_getlink_if_parse
;
405 ret
= afs_rtm_getlink(&desc
);
408 ret
= afs_read_rtm(&desc
);
412 afs_cull_interfaces(&desc
);
415 for (loop
= 0; loop
< ret
; loop
++)
416 _debug("[%d] "NIPQUAD_FMT
"/"NIPQUAD_FMT
" mtu %u",
418 NIPQUAD(bufs
[loop
].address
),
419 NIPQUAD(bufs
[loop
].netmask
),
424 sock_release(desc
.nlsock
);
425 _leave(" = %d", ret
);
430 * get a MAC address from a random ethernet interface that has a real one
431 * - the buffer should be 6 bytes in size
433 int afs_get_MAC_address(u8 mac
[6])
435 struct afs_rtm_desc desc
;
440 memset(&desc
, 0, sizeof(desc
));
442 desc
.mac_index
= UINT_MAX
;
444 ret
= sock_create_kern(AF_NETLINK
, SOCK_DGRAM
, NETLINK_ROUTE
,
447 _leave(" = %d [sock]", ret
);
451 /* issue RTM_GETLINK */
452 desc
.parse
= afs_rtm_getlink_mac_parse
;
453 ret
= afs_rtm_getlink(&desc
);
456 ret
= afs_read_rtm(&desc
);
460 if (desc
.mac_index
< UINT_MAX
) {
461 /* got a MAC address */
462 _debug("[%d] %02x:%02x:%02x:%02x:%02x:%02x",
464 mac
[0], mac
[1], mac
[2], mac
[3], mac
[4], mac
[5]);
470 sock_release(desc
.nlsock
);
471 _leave(" = %d", ret
);