aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/afs_cm.h3
-rw-r--r--fs/afs/cmservice.c98
-rw-r--r--fs/afs/internal.h42
-rw-r--r--fs/afs/main.c49
-rw-r--r--fs/afs/rxrpc.c39
-rw-r--r--fs/afs/use-rtnetlink.c473
7 files changed, 705 insertions, 0 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index cca198b2caed..01545eb1d872 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -18,6 +18,7 @@ kafs-objs := \
18 security.o \ 18 security.o \
19 server.o \ 19 server.o \
20 super.o \ 20 super.o \
21 use-rtnetlink.o \
21 vlclient.o \ 22 vlclient.o \
22 vlocation.o \ 23 vlocation.o \
23 vnode.o \ 24 vnode.o \
diff --git a/fs/afs/afs_cm.h b/fs/afs/afs_cm.h
index 7c8e3d43c8e5..d4bd201cc31e 100644
--- a/fs/afs/afs_cm.h
+++ b/fs/afs/afs_cm.h
@@ -23,6 +23,9 @@ enum AFS_CM_Operations {
23 CBGetCE = 208, /* get cache file description */ 23 CBGetCE = 208, /* get cache file description */
24 CBGetXStatsVersion = 209, /* get version of extended statistics */ 24 CBGetXStatsVersion = 209, /* get version of extended statistics */
25 CBGetXStats = 210, /* get contents of extended statistics data */ 25 CBGetXStats = 210, /* get contents of extended statistics data */
26 CBGetCapabilities = 65538, /* get client capabilities */
26}; 27};
27 28
29#define AFS_CAP_ERROR_TRANSLATION 0x1
30
28#endif /* AFS_FS_H */ 31#endif /* AFS_FS_H */
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index c3ec57a237bf..a6af3acf016e 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -22,6 +22,8 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *,
22 struct sk_buff *, bool); 22 struct sk_buff *, bool);
23static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); 23static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
24static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); 24static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
25static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
26 bool);
25static void afs_cm_destructor(struct afs_call *); 27static void afs_cm_destructor(struct afs_call *);
26 28
27/* 29/*
@@ -55,6 +57,16 @@ static const struct afs_call_type afs_SRXCBProbe = {
55}; 57};
56 58
57/* 59/*
60 * CB.GetCapabilities operation type
61 */
62static const struct afs_call_type afs_SRXCBGetCapabilites = {
63 .name = "CB.GetCapabilities",
64 .deliver = afs_deliver_cb_get_capabilities,
65 .abort_to_error = afs_abort_to_error,
66 .destructor = afs_cm_destructor,
67};
68
69/*
58 * route an incoming cache manager call 70 * route an incoming cache manager call
59 * - return T if supported, F if not 71 * - return T if supported, F if not
60 */ 72 */
@@ -74,6 +86,9 @@ bool afs_cm_incoming_call(struct afs_call *call)
74 case CBProbe: 86 case CBProbe:
75 call->type = &afs_SRXCBProbe; 87 call->type = &afs_SRXCBProbe;
76 return true; 88 return true;
89 case CBGetCapabilities:
90 call->type = &afs_SRXCBGetCapabilites;
91 return true;
77 default: 92 default:
78 return false; 93 return false;
79 } 94 }
@@ -328,3 +343,86 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
328 schedule_work(&call->work); 343 schedule_work(&call->work);
329 return 0; 344 return 0;
330} 345}
346
347/*
348 * allow the fileserver to ask about the cache manager's capabilities
349 */
350static void SRXAFSCB_GetCapabilities(struct work_struct *work)
351{
352 struct afs_interface *ifs;
353 struct afs_call *call = container_of(work, struct afs_call, work);
354 int loop, nifs;
355
356 struct {
357 struct /* InterfaceAddr */ {
358 __be32 nifs;
359 __be32 uuid[11];
360 __be32 ifaddr[32];
361 __be32 netmask[32];
362 __be32 mtu[32];
363 } ia;
364 struct /* Capabilities */ {
365 __be32 capcount;
366 __be32 caps[1];
367 } cap;
368 } reply;
369
370 _enter("");
371
372 nifs = 0;
373 ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
374 if (ifs) {
375 nifs = afs_get_ipv4_interfaces(ifs, 32, false);
376 if (nifs < 0) {
377 kfree(ifs);
378 ifs = NULL;
379 nifs = 0;
380 }
381 }
382
383 memset(&reply, 0, sizeof(reply));
384 reply.ia.nifs = htonl(nifs);
385
386 reply.ia.uuid[0] = htonl(afs_uuid.time_low);
387 reply.ia.uuid[1] = htonl(afs_uuid.time_mid);
388 reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version);
389 reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved);
390 reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low);
391 for (loop = 0; loop < 6; loop++)
392 reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]);
393
394 if (ifs) {
395 for (loop = 0; loop < nifs; loop++) {
396 reply.ia.ifaddr[loop] = ifs[loop].address.s_addr;
397 reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
398 reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
399 }
400 }
401
402 reply.cap.capcount = htonl(1);
403 reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
404 afs_send_simple_reply(call, &reply, sizeof(reply));
405
406 _leave("");
407}
408
409/*
410 * deliver request data to a CB.GetCapabilities call
411 */
412static int afs_deliver_cb_get_capabilities(struct afs_call *call,
413 struct sk_buff *skb, bool last)
414{
415 _enter(",{%u},%d", skb->len, last);
416
417 if (skb->len > 0)
418 return -EBADMSG;
419 if (!last)
420 return 0;
421
422 /* no unmarshalling required */
423 call->state = AFS_CALL_REPLYING;
424
425 INIT_WORK(&call->work, SRXAFSCB_GetCapabilities);
426 schedule_work(&call->work);
427 return 0;
428}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 8bed2429d01f..6120d4bd19e0 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -346,6 +346,40 @@ struct afs_permits {
346 struct afs_permit permits[0]; /* the permits so far examined */ 346 struct afs_permit permits[0]; /* the permits so far examined */
347}; 347};
348 348
349/*
350 * record of one of a system's set of network interfaces
351 */
352struct afs_interface {
353 unsigned index; /* interface index */
354 struct in_addr address; /* IPv4 address bound to interface */
355 struct in_addr netmask; /* netmask applied to address */
356 unsigned mtu; /* MTU of interface */
357};
358
359/*
360 * UUID definition [internet draft]
361 * - the timestamp is a 60-bit value, split 32/16/12, and goes in 100ns
362 * increments since midnight 15th October 1582
363 * - add AFS_UUID_TO_UNIX_TIME to convert unix time in 100ns units to UUID
364 * time
365 * - the clock sequence is a 14-bit counter to avoid duplicate times
366 */
367struct afs_uuid {
368 u32 time_low; /* low part of timestamp */
369 u16 time_mid; /* mid part of timestamp */
370 u16 time_hi_and_version; /* high part of timestamp and version */
371#define AFS_UUID_TO_UNIX_TIME 0x01b21dd213814000
372#define AFS_UUID_TIMEHI_MASK 0x0fff
373#define AFS_UUID_VERSION_TIME 0x1000 /* time-based UUID */
374#define AFS_UUID_VERSION_NAME 0x3000 /* name-based UUID */
375#define AFS_UUID_VERSION_RANDOM 0x4000 /* (pseudo-)random generated UUID */
376 u8 clock_seq_hi_and_reserved; /* clock seq hi and variant */
377#define AFS_UUID_CLOCKHI_MASK 0x3f
378#define AFS_UUID_VARIANT_STD 0x80
379 u8 clock_seq_low; /* clock seq low */
380 u8 node[6]; /* spatially unique node ID (MAC addr) */
381};
382
349/*****************************************************************************/ 383/*****************************************************************************/
350/* 384/*
351 * callback.c 385 * callback.c
@@ -430,6 +464,7 @@ extern void afs_clear_inode(struct inode *);
430/* 464/*
431 * main.c 465 * main.c
432 */ 466 */
467extern struct afs_uuid afs_uuid;
433#ifdef AFS_CACHING_SUPPORT 468#ifdef AFS_CACHING_SUPPORT
434extern struct cachefs_netfs afs_cache_netfs; 469extern struct cachefs_netfs afs_cache_netfs;
435#endif 470#endif
@@ -470,6 +505,7 @@ extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *,
470extern void afs_flat_call_destructor(struct afs_call *); 505extern void afs_flat_call_destructor(struct afs_call *);
471extern void afs_transfer_reply(struct afs_call *, struct sk_buff *); 506extern void afs_transfer_reply(struct afs_call *, struct sk_buff *);
472extern void afs_send_empty_reply(struct afs_call *); 507extern void afs_send_empty_reply(struct afs_call *);
508extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
473extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *, 509extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *,
474 size_t); 510 size_t);
475 511
@@ -501,6 +537,12 @@ extern int afs_fs_init(void);
501extern void afs_fs_exit(void); 537extern void afs_fs_exit(void);
502 538
503/* 539/*
540 * use-rtnetlink.c
541 */
542extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool);
543extern int afs_get_MAC_address(u8 [6]);
544
545/*
504 * vlclient.c 546 * vlclient.c
505 */ 547 */
506#ifdef AFS_CACHING_SUPPORT 548#ifdef AFS_CACHING_SUPPORT
diff --git a/fs/afs/main.c b/fs/afs/main.c
index 0cf1b021ad54..40c2704e7557 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -40,6 +40,51 @@ struct cachefs_netfs afs_cache_netfs = {
40}; 40};
41#endif 41#endif
42 42
43struct afs_uuid afs_uuid;
44
45/*
46 * get a client UUID
47 */
48static int __init afs_get_client_UUID(void)
49{
50 struct timespec ts;
51 u64 uuidtime;
52 u16 clockseq;
53 int ret;
54
55 /* read the MAC address of one of the external interfaces and construct
56 * a UUID from it */
57 ret = afs_get_MAC_address(afs_uuid.node);
58 if (ret < 0)
59 return ret;
60
61 getnstimeofday(&ts);
62 uuidtime = (u64) ts.tv_sec * 1000 * 1000 * 10;
63 uuidtime += ts.tv_nsec / 100;
64 uuidtime += AFS_UUID_TO_UNIX_TIME;
65 afs_uuid.time_low = uuidtime;
66 afs_uuid.time_mid = uuidtime >> 32;
67 afs_uuid.time_hi_and_version = (uuidtime >> 48) & AFS_UUID_TIMEHI_MASK;
68 afs_uuid.time_hi_and_version = AFS_UUID_VERSION_TIME;
69
70 get_random_bytes(&clockseq, 2);
71 afs_uuid.clock_seq_low = clockseq;
72 afs_uuid.clock_seq_hi_and_reserved =
73 (clockseq >> 8) & AFS_UUID_CLOCKHI_MASK;
74 afs_uuid.clock_seq_hi_and_reserved = AFS_UUID_VARIANT_STD;
75
76 _debug("AFS UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
77 afs_uuid.time_low,
78 afs_uuid.time_mid,
79 afs_uuid.time_hi_and_version,
80 afs_uuid.clock_seq_hi_and_reserved,
81 afs_uuid.clock_seq_low,
82 afs_uuid.node[0], afs_uuid.node[1], afs_uuid.node[2],
83 afs_uuid.node[3], afs_uuid.node[4], afs_uuid.node[5]);
84
85 return 0;
86}
87
43/* 88/*
44 * initialise the AFS client FS module 89 * initialise the AFS client FS module
45 */ 90 */
@@ -49,6 +94,10 @@ static int __init afs_init(void)
49 94
50 printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); 95 printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
51 96
97 ret = afs_get_client_UUID();
98 if (ret < 0)
99 return ret;
100
52 /* register the /proc stuff */ 101 /* register the /proc stuff */
53 ret = afs_proc_init(); 102 ret = afs_proc_init();
54 if (ret < 0) 103 if (ret < 0)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index e86c527d87a1..e7b047328a39 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -714,6 +714,45 @@ void afs_send_empty_reply(struct afs_call *call)
714} 714}
715 715
716/* 716/*
717 * send a simple reply
718 */
719void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
720{
721 struct msghdr msg;
722 struct iovec iov[1];
723
724 _enter("");
725
726 iov[0].iov_base = (void *) buf;
727 iov[0].iov_len = len;
728 msg.msg_name = NULL;
729 msg.msg_namelen = 0;
730 msg.msg_iov = iov;
731 msg.msg_iovlen = 1;
732 msg.msg_control = NULL;
733 msg.msg_controllen = 0;
734 msg.msg_flags = 0;
735
736 call->state = AFS_CALL_AWAIT_ACK;
737 switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) {
738 case 0:
739 _leave(" [replied]");
740 return;
741
742 case -ENOMEM:
743 _debug("oom");
744 rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
745 default:
746 rxrpc_kernel_end_call(call->rxcall);
747 call->rxcall = NULL;
748 call->type->destructor(call);
749 afs_free_call(call);
750 _leave(" [error]");
751 return;
752 }
753}
754
755/*
717 * extract a piece of data from the received data socket buffers 756 * extract a piece of data from the received data socket buffers
718 */ 757 */
719int afs_extract_data(struct afs_call *call, struct sk_buff *skb, 758int afs_extract_data(struct afs_call *call, struct sk_buff *skb,
diff --git a/fs/afs/use-rtnetlink.c b/fs/afs/use-rtnetlink.c
new file mode 100644
index 000000000000..82f0daa28970
--- /dev/null
+++ b/fs/afs/use-rtnetlink.c
@@ -0,0 +1,473 @@
1/* RTNETLINK client
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
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.
10 */
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>
17#include "internal.h"
18
19struct afs_rtm_desc {
20 struct socket *nlsock;
21 struct afs_interface *bufs;
22 u8 *mac;
23 size_t nbufs;
24 size_t maxbufs;
25 void *data;
26 ssize_t datalen;
27 size_t datamax;
28 int msg_seq;
29 unsigned mac_index;
30 bool wantloopback;
31 int (*parse)(struct afs_rtm_desc *, struct nlmsghdr *);
32};
33
34/*
35 * parse an RTM_GETADDR response
36 */
37static int afs_rtm_getaddr_parse(struct afs_rtm_desc *desc,
38 struct nlmsghdr *nlhdr)
39{
40 struct afs_interface *this;
41 struct ifaddrmsg *ifa;
42 struct rtattr *rtattr;
43 const char *name;
44 size_t len;
45
46 ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
47
48 _enter("{ix=%d,af=%d}", ifa->ifa_index, ifa->ifa_family);
49
50 if (ifa->ifa_family != AF_INET) {
51 _leave(" = 0 [family %d]", ifa->ifa_family);
52 return 0;
53 }
54 if (desc->nbufs >= desc->maxbufs) {
55 _leave(" = 0 [max %zu/%zu]", desc->nbufs, desc->maxbufs);
56 return 0;
57 }
58
59 this = &desc->bufs[desc->nbufs];
60
61 this->index = ifa->ifa_index;
62 this->netmask.s_addr = inet_make_mask(ifa->ifa_prefixlen);
63 this->mtu = 0;
64
65 rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifaddrmsg));
66 len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifaddrmsg));
67
68 name = "unknown";
69 for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
70 switch (rtattr->rta_type) {
71 case IFA_ADDRESS:
72 memcpy(&this->address, RTA_DATA(rtattr), 4);
73 break;
74 case IFA_LABEL:
75 name = RTA_DATA(rtattr);
76 break;
77 }
78 }
79
80 _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT,
81 name, NIPQUAD(this->address), NIPQUAD(this->netmask));
82
83 desc->nbufs++;
84 _leave(" = 0");
85 return 0;
86}
87
88/*
89 * parse an RTM_GETLINK response for MTUs
90 */
91static int afs_rtm_getlink_if_parse(struct afs_rtm_desc *desc,
92 struct nlmsghdr *nlhdr)
93{
94 struct afs_interface *this;
95 struct ifinfomsg *ifi;
96 struct rtattr *rtattr;
97 const char *name;
98 size_t len, loop;
99
100 ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
101
102 _enter("{ix=%d}", ifi->ifi_index);
103
104 for (loop = 0; loop < desc->nbufs; loop++) {
105 this = &desc->bufs[loop];
106 if (this->index == ifi->ifi_index)
107 goto found;
108 }
109
110 _leave(" = 0 [no match]");
111 return 0;
112
113found:
114 if (ifi->ifi_type == ARPHRD_LOOPBACK && !desc->wantloopback) {
115 _leave(" = 0 [loopback]");
116 return 0;
117 }
118
119 rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg));
120 len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg));
121
122 name = "unknown";
123 for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
124 switch (rtattr->rta_type) {
125 case IFLA_MTU:
126 memcpy(&this->mtu, RTA_DATA(rtattr), 4);
127 break;
128 case IFLA_IFNAME:
129 name = RTA_DATA(rtattr);
130 break;
131 }
132 }
133
134 _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u",
135 name, NIPQUAD(this->address), NIPQUAD(this->netmask),
136 this->mtu);
137
138 _leave(" = 0");
139 return 0;
140}
141
142/*
143 * parse an RTM_GETLINK response for the MAC address belonging to the lowest
144 * non-internal interface
145 */
146static int afs_rtm_getlink_mac_parse(struct afs_rtm_desc *desc,
147 struct nlmsghdr *nlhdr)
148{
149 struct ifinfomsg *ifi;
150 struct rtattr *rtattr;
151 const char *name;
152 size_t remain, len;
153 bool set;
154
155 ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
156
157 _enter("{ix=%d}", ifi->ifi_index);
158
159 if (ifi->ifi_index >= desc->mac_index) {
160 _leave(" = 0 [high]");
161 return 0;
162 }
163 if (ifi->ifi_type == ARPHRD_LOOPBACK) {
164 _leave(" = 0 [loopback]");
165 return 0;
166 }
167
168 rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg));
169 remain = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg));
170
171 name = "unknown";
172 set = false;
173 for (; RTA_OK(rtattr, remain); rtattr = RTA_NEXT(rtattr, remain)) {
174 switch (rtattr->rta_type) {
175 case IFLA_ADDRESS:
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;
180 set = true;
181 break;
182 case IFLA_IFNAME:
183 name = RTA_DATA(rtattr);
184 break;
185 }
186 }
187
188 if (set)
189 _debug("%s: %02x:%02x:%02x:%02x:%02x:%02x",
190 name,
191 desc->mac[0], desc->mac[1], desc->mac[2],
192 desc->mac[3], desc->mac[4], desc->mac[5]);
193
194 _leave(" = 0");
195 return 0;
196}
197
198/*
199 * read the rtnetlink response and pass to parsing routine
200 */
201static int afs_read_rtm(struct afs_rtm_desc *desc)
202{
203 struct nlmsghdr *nlhdr, tmphdr;
204 struct msghdr msg;
205 struct kvec iov[1];
206 void *data;
207 bool last = false;
208 int len, ret, remain;
209
210 _enter("");
211
212 do {
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);
219 if (len < 0) {
220 _leave(" = %d [peek]", len);
221 return len;
222 }
223 if (len == 0)
224 continue;
225 if (len < sizeof(tmphdr) || len < NLMSG_PAYLOAD(&tmphdr, 0)) {
226 _leave(" = -EMSGSIZE");
227 return -EMSGSIZE;
228 }
229
230 if (desc->datamax < len) {
231 kfree(desc->data);
232 desc->data = NULL;
233 data = kmalloc(len, GFP_KERNEL);
234 if (!data)
235 return -ENOMEM;
236 desc->data = data;
237 }
238 desc->datamax = len;
239
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,
244 desc->datamax, 0);
245 if (desc->datalen < 0) {
246 _leave(" = %ld [recv]", desc->datalen);
247 return desc->datalen;
248 }
249
250 nlhdr = desc->data;
251
252 /* check if the header is valid */
253 if (!NLMSG_OK(nlhdr, desc->datalen) ||
254 nlhdr->nlmsg_type == NLMSG_ERROR) {
255 _leave(" = -EIO");
256 return -EIO;
257 }
258
259 /* see if this is the last message */
260 if (nlhdr->nlmsg_type == NLMSG_DONE ||
261 !(nlhdr->nlmsg_flags & NLM_F_MULTI))
262 last = true;
263
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);
267 if (ret < 0) {
268 _leave(" = %d [parse]", ret);
269 return ret;
270 }
271 }
272
273 } while (!last);
274
275 _leave(" = 0");
276 return 0;
277}
278
279/*
280 * list the interface bound addresses to get the address and netmask
281 */
282static int afs_rtm_getaddr(struct afs_rtm_desc *desc)
283{
284 struct msghdr msg;
285 struct kvec iov[1];
286 int ret;
287
288 struct {
289 struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO)));
290 struct ifaddrmsg addr_msg __attribute__((aligned(NLMSG_ALIGNTO)));
291 } request;
292
293 _enter("");
294
295 memset(&request, 0, sizeof(request));
296
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;
302
303 memset(&msg, 0, sizeof(msg));
304 iov[0].iov_base = &request;
305 iov[0].iov_len = sizeof(request);
306
307 ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len);
308 _leave(" = %d", ret);
309 return ret;
310}
311
312/*
313 * list the interface link statuses to get the MTUs
314 */
315static int afs_rtm_getlink(struct afs_rtm_desc *desc)
316{
317 struct msghdr msg;
318 struct kvec iov[1];
319 int ret;
320
321 struct {
322 struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO)));
323 struct ifinfomsg link_msg __attribute__((aligned(NLMSG_ALIGNTO)));
324 } request;
325
326 _enter("");
327
328 memset(&request, 0, sizeof(request));
329
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;
335
336 memset(&msg, 0, sizeof(msg));
337 iov[0].iov_base = &request;
338 iov[0].iov_len = sizeof(request);
339
340 ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len);
341 _leave(" = %d", ret);
342 return ret;
343}
344
345/*
346 * cull any interface records for which there isn't an MTU value
347 */
348static void afs_cull_interfaces(struct afs_rtm_desc *desc)
349{
350 struct afs_interface *bufs = desc->bufs;
351 size_t nbufs = desc->nbufs;
352 int loop, point = 0;
353
354 _enter("{%zu}", nbufs);
355
356 for (loop = 0; loop < nbufs; loop++) {
357 if (desc->bufs[loop].mtu != 0) {
358 if (loop != point) {
359 ASSERTCMP(loop, >, point);
360 bufs[point] = bufs[loop];
361 }
362 point++;
363 }
364 }
365
366 desc->nbufs = point;
367 _leave(" [%zu/%zu]", desc->nbufs, nbufs);
368}
369
370/*
371 * get a list of this system's interface IPv4 addresses, netmasks and MTUs
372 * - returns the number of interface records in the buffer
373 */
374int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
375 bool wantloopback)
376{
377 struct afs_rtm_desc desc;
378 int ret, loop;
379
380 _enter("");
381
382 memset(&desc, 0, sizeof(desc));
383 desc.bufs = bufs;
384 desc.maxbufs = maxbufs;
385 desc.wantloopback = wantloopback;
386
387 ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
388 &desc.nlsock);
389 if (ret < 0) {
390 _leave(" = %d [sock]", ret);
391 return ret;
392 }
393
394 /* issue RTM_GETADDR */
395 desc.parse = afs_rtm_getaddr_parse;
396 ret = afs_rtm_getaddr(&desc);
397 if (ret < 0)
398 goto error;
399 ret = afs_read_rtm(&desc);
400 if (ret < 0)
401 goto error;
402
403 /* issue RTM_GETLINK */
404 desc.parse = afs_rtm_getlink_if_parse;
405 ret = afs_rtm_getlink(&desc);
406 if (ret < 0)
407 goto error;
408 ret = afs_read_rtm(&desc);
409 if (ret < 0)
410 goto error;
411
412 afs_cull_interfaces(&desc);
413 ret = desc.nbufs;
414
415 for (loop = 0; loop < ret; loop++)
416 _debug("[%d] "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u",
417 bufs[loop].index,
418 NIPQUAD(bufs[loop].address),
419 NIPQUAD(bufs[loop].netmask),
420 bufs[loop].mtu);
421
422error:
423 kfree(desc.data);
424 sock_release(desc.nlsock);
425 _leave(" = %d", ret);
426 return ret;
427}
428
429/*
430 * get a MAC address from a random ethernet interface that has a real one
431 * - the buffer should be 6 bytes in size
432 */
433int afs_get_MAC_address(u8 mac[6])
434{
435 struct afs_rtm_desc desc;
436 int ret;
437
438 _enter("");
439
440 memset(&desc, 0, sizeof(desc));
441 desc.mac = mac;
442 desc.mac_index = UINT_MAX;
443
444 ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
445 &desc.nlsock);
446 if (ret < 0) {
447 _leave(" = %d [sock]", ret);
448 return ret;
449 }
450
451 /* issue RTM_GETLINK */
452 desc.parse = afs_rtm_getlink_mac_parse;
453 ret = afs_rtm_getlink(&desc);
454 if (ret < 0)
455 goto error;
456 ret = afs_read_rtm(&desc);
457 if (ret < 0)
458 goto error;
459
460 if (desc.mac_index < UINT_MAX) {
461 /* got a MAC address */
462 _debug("[%d] %02x:%02x:%02x:%02x:%02x:%02x",
463 desc.mac_index,
464 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
465 } else {
466 ret = -ENONET;
467 }
468
469error:
470 sock_release(desc.nlsock);
471 _leave(" = %d", ret);
472 return ret;
473}