1*38c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0
2*38c8a9a5SSteve French /*
3*38c8a9a5SSteve French * Witness Service client for CIFS
4*38c8a9a5SSteve French *
5*38c8a9a5SSteve French * Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
6*38c8a9a5SSteve French */
7*38c8a9a5SSteve French
8*38c8a9a5SSteve French #include <linux/kref.h>
9*38c8a9a5SSteve French #include <net/genetlink.h>
10*38c8a9a5SSteve French #include <uapi/linux/cifs/cifs_netlink.h>
11*38c8a9a5SSteve French
12*38c8a9a5SSteve French #include "cifs_swn.h"
13*38c8a9a5SSteve French #include "cifsglob.h"
14*38c8a9a5SSteve French #include "cifsproto.h"
15*38c8a9a5SSteve French #include "fscache.h"
16*38c8a9a5SSteve French #include "cifs_debug.h"
17*38c8a9a5SSteve French #include "netlink.h"
18*38c8a9a5SSteve French
19*38c8a9a5SSteve French static DEFINE_IDR(cifs_swnreg_idr);
20*38c8a9a5SSteve French static DEFINE_MUTEX(cifs_swnreg_idr_mutex);
21*38c8a9a5SSteve French
22*38c8a9a5SSteve French struct cifs_swn_reg {
23*38c8a9a5SSteve French int id;
24*38c8a9a5SSteve French struct kref ref_count;
25*38c8a9a5SSteve French
26*38c8a9a5SSteve French const char *net_name;
27*38c8a9a5SSteve French const char *share_name;
28*38c8a9a5SSteve French bool net_name_notify;
29*38c8a9a5SSteve French bool share_name_notify;
30*38c8a9a5SSteve French bool ip_notify;
31*38c8a9a5SSteve French
32*38c8a9a5SSteve French struct cifs_tcon *tcon;
33*38c8a9a5SSteve French };
34*38c8a9a5SSteve French
cifs_swn_auth_info_krb(struct cifs_tcon * tcon,struct sk_buff * skb)35*38c8a9a5SSteve French static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb)
36*38c8a9a5SSteve French {
37*38c8a9a5SSteve French int ret;
38*38c8a9a5SSteve French
39*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH);
40*38c8a9a5SSteve French if (ret < 0)
41*38c8a9a5SSteve French return ret;
42*38c8a9a5SSteve French
43*38c8a9a5SSteve French return 0;
44*38c8a9a5SSteve French }
45*38c8a9a5SSteve French
cifs_swn_auth_info_ntlm(struct cifs_tcon * tcon,struct sk_buff * skb)46*38c8a9a5SSteve French static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb)
47*38c8a9a5SSteve French {
48*38c8a9a5SSteve French int ret;
49*38c8a9a5SSteve French
50*38c8a9a5SSteve French if (tcon->ses->user_name != NULL) {
51*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name);
52*38c8a9a5SSteve French if (ret < 0)
53*38c8a9a5SSteve French return ret;
54*38c8a9a5SSteve French }
55*38c8a9a5SSteve French
56*38c8a9a5SSteve French if (tcon->ses->password != NULL) {
57*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password);
58*38c8a9a5SSteve French if (ret < 0)
59*38c8a9a5SSteve French return ret;
60*38c8a9a5SSteve French }
61*38c8a9a5SSteve French
62*38c8a9a5SSteve French if (tcon->ses->domainName != NULL) {
63*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName);
64*38c8a9a5SSteve French if (ret < 0)
65*38c8a9a5SSteve French return ret;
66*38c8a9a5SSteve French }
67*38c8a9a5SSteve French
68*38c8a9a5SSteve French return 0;
69*38c8a9a5SSteve French }
70*38c8a9a5SSteve French
71*38c8a9a5SSteve French /*
72*38c8a9a5SSteve French * Sends a register message to the userspace daemon based on the registration.
73*38c8a9a5SSteve French * The authentication information to connect to the witness service is bundled
74*38c8a9a5SSteve French * into the message.
75*38c8a9a5SSteve French */
cifs_swn_send_register_message(struct cifs_swn_reg * swnreg)76*38c8a9a5SSteve French static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
77*38c8a9a5SSteve French {
78*38c8a9a5SSteve French struct sk_buff *skb;
79*38c8a9a5SSteve French struct genlmsghdr *hdr;
80*38c8a9a5SSteve French enum securityEnum authtype;
81*38c8a9a5SSteve French struct sockaddr_storage *addr;
82*38c8a9a5SSteve French int ret;
83*38c8a9a5SSteve French
84*38c8a9a5SSteve French skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
85*38c8a9a5SSteve French if (skb == NULL) {
86*38c8a9a5SSteve French ret = -ENOMEM;
87*38c8a9a5SSteve French goto fail;
88*38c8a9a5SSteve French }
89*38c8a9a5SSteve French
90*38c8a9a5SSteve French hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER);
91*38c8a9a5SSteve French if (hdr == NULL) {
92*38c8a9a5SSteve French ret = -ENOMEM;
93*38c8a9a5SSteve French goto nlmsg_fail;
94*38c8a9a5SSteve French }
95*38c8a9a5SSteve French
96*38c8a9a5SSteve French ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id);
97*38c8a9a5SSteve French if (ret < 0)
98*38c8a9a5SSteve French goto nlmsg_fail;
99*38c8a9a5SSteve French
100*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name);
101*38c8a9a5SSteve French if (ret < 0)
102*38c8a9a5SSteve French goto nlmsg_fail;
103*38c8a9a5SSteve French
104*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name);
105*38c8a9a5SSteve French if (ret < 0)
106*38c8a9a5SSteve French goto nlmsg_fail;
107*38c8a9a5SSteve French
108*38c8a9a5SSteve French /*
109*38c8a9a5SSteve French * If there is an address stored use it instead of the server address, because we are
110*38c8a9a5SSteve French * in the process of reconnecting to it after a share has been moved or we have been
111*38c8a9a5SSteve French * told to switch to it (client move message). In these cases we unregister from the
112*38c8a9a5SSteve French * server address and register to the new address when we receive the notification.
113*38c8a9a5SSteve French */
114*38c8a9a5SSteve French if (swnreg->tcon->ses->server->use_swn_dstaddr)
115*38c8a9a5SSteve French addr = &swnreg->tcon->ses->server->swn_dstaddr;
116*38c8a9a5SSteve French else
117*38c8a9a5SSteve French addr = &swnreg->tcon->ses->server->dstaddr;
118*38c8a9a5SSteve French
119*38c8a9a5SSteve French ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr);
120*38c8a9a5SSteve French if (ret < 0)
121*38c8a9a5SSteve French goto nlmsg_fail;
122*38c8a9a5SSteve French
123*38c8a9a5SSteve French if (swnreg->net_name_notify) {
124*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY);
125*38c8a9a5SSteve French if (ret < 0)
126*38c8a9a5SSteve French goto nlmsg_fail;
127*38c8a9a5SSteve French }
128*38c8a9a5SSteve French
129*38c8a9a5SSteve French if (swnreg->share_name_notify) {
130*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY);
131*38c8a9a5SSteve French if (ret < 0)
132*38c8a9a5SSteve French goto nlmsg_fail;
133*38c8a9a5SSteve French }
134*38c8a9a5SSteve French
135*38c8a9a5SSteve French if (swnreg->ip_notify) {
136*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY);
137*38c8a9a5SSteve French if (ret < 0)
138*38c8a9a5SSteve French goto nlmsg_fail;
139*38c8a9a5SSteve French }
140*38c8a9a5SSteve French
141*38c8a9a5SSteve French authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype);
142*38c8a9a5SSteve French switch (authtype) {
143*38c8a9a5SSteve French case Kerberos:
144*38c8a9a5SSteve French ret = cifs_swn_auth_info_krb(swnreg->tcon, skb);
145*38c8a9a5SSteve French if (ret < 0) {
146*38c8a9a5SSteve French cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret);
147*38c8a9a5SSteve French goto nlmsg_fail;
148*38c8a9a5SSteve French }
149*38c8a9a5SSteve French break;
150*38c8a9a5SSteve French case NTLMv2:
151*38c8a9a5SSteve French case RawNTLMSSP:
152*38c8a9a5SSteve French ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb);
153*38c8a9a5SSteve French if (ret < 0) {
154*38c8a9a5SSteve French cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret);
155*38c8a9a5SSteve French goto nlmsg_fail;
156*38c8a9a5SSteve French }
157*38c8a9a5SSteve French break;
158*38c8a9a5SSteve French default:
159*38c8a9a5SSteve French cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype);
160*38c8a9a5SSteve French ret = -EINVAL;
161*38c8a9a5SSteve French goto nlmsg_fail;
162*38c8a9a5SSteve French }
163*38c8a9a5SSteve French
164*38c8a9a5SSteve French genlmsg_end(skb, hdr);
165*38c8a9a5SSteve French genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC);
166*38c8a9a5SSteve French
167*38c8a9a5SSteve French cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__,
168*38c8a9a5SSteve French swnreg->net_name, swnreg->id);
169*38c8a9a5SSteve French
170*38c8a9a5SSteve French return 0;
171*38c8a9a5SSteve French
172*38c8a9a5SSteve French nlmsg_fail:
173*38c8a9a5SSteve French genlmsg_cancel(skb, hdr);
174*38c8a9a5SSteve French nlmsg_free(skb);
175*38c8a9a5SSteve French fail:
176*38c8a9a5SSteve French return ret;
177*38c8a9a5SSteve French }
178*38c8a9a5SSteve French
179*38c8a9a5SSteve French /*
180*38c8a9a5SSteve French * Sends an uregister message to the userspace daemon based on the registration
181*38c8a9a5SSteve French */
cifs_swn_send_unregister_message(struct cifs_swn_reg * swnreg)182*38c8a9a5SSteve French static int cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg)
183*38c8a9a5SSteve French {
184*38c8a9a5SSteve French struct sk_buff *skb;
185*38c8a9a5SSteve French struct genlmsghdr *hdr;
186*38c8a9a5SSteve French int ret;
187*38c8a9a5SSteve French
188*38c8a9a5SSteve French skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
189*38c8a9a5SSteve French if (skb == NULL)
190*38c8a9a5SSteve French return -ENOMEM;
191*38c8a9a5SSteve French
192*38c8a9a5SSteve French hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER);
193*38c8a9a5SSteve French if (hdr == NULL) {
194*38c8a9a5SSteve French ret = -ENOMEM;
195*38c8a9a5SSteve French goto nlmsg_fail;
196*38c8a9a5SSteve French }
197*38c8a9a5SSteve French
198*38c8a9a5SSteve French ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id);
199*38c8a9a5SSteve French if (ret < 0)
200*38c8a9a5SSteve French goto nlmsg_fail;
201*38c8a9a5SSteve French
202*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name);
203*38c8a9a5SSteve French if (ret < 0)
204*38c8a9a5SSteve French goto nlmsg_fail;
205*38c8a9a5SSteve French
206*38c8a9a5SSteve French ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name);
207*38c8a9a5SSteve French if (ret < 0)
208*38c8a9a5SSteve French goto nlmsg_fail;
209*38c8a9a5SSteve French
210*38c8a9a5SSteve French ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage),
211*38c8a9a5SSteve French &swnreg->tcon->ses->server->dstaddr);
212*38c8a9a5SSteve French if (ret < 0)
213*38c8a9a5SSteve French goto nlmsg_fail;
214*38c8a9a5SSteve French
215*38c8a9a5SSteve French if (swnreg->net_name_notify) {
216*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY);
217*38c8a9a5SSteve French if (ret < 0)
218*38c8a9a5SSteve French goto nlmsg_fail;
219*38c8a9a5SSteve French }
220*38c8a9a5SSteve French
221*38c8a9a5SSteve French if (swnreg->share_name_notify) {
222*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY);
223*38c8a9a5SSteve French if (ret < 0)
224*38c8a9a5SSteve French goto nlmsg_fail;
225*38c8a9a5SSteve French }
226*38c8a9a5SSteve French
227*38c8a9a5SSteve French if (swnreg->ip_notify) {
228*38c8a9a5SSteve French ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY);
229*38c8a9a5SSteve French if (ret < 0)
230*38c8a9a5SSteve French goto nlmsg_fail;
231*38c8a9a5SSteve French }
232*38c8a9a5SSteve French
233*38c8a9a5SSteve French genlmsg_end(skb, hdr);
234*38c8a9a5SSteve French genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC);
235*38c8a9a5SSteve French
236*38c8a9a5SSteve French cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__,
237*38c8a9a5SSteve French swnreg->net_name, swnreg->id);
238*38c8a9a5SSteve French
239*38c8a9a5SSteve French return 0;
240*38c8a9a5SSteve French
241*38c8a9a5SSteve French nlmsg_fail:
242*38c8a9a5SSteve French genlmsg_cancel(skb, hdr);
243*38c8a9a5SSteve French nlmsg_free(skb);
244*38c8a9a5SSteve French return ret;
245*38c8a9a5SSteve French }
246*38c8a9a5SSteve French
247*38c8a9a5SSteve French /*
248*38c8a9a5SSteve French * Try to find a matching registration for the tcon's server name and share name.
249*38c8a9a5SSteve French * Calls to this function must be protected by cifs_swnreg_idr_mutex.
250*38c8a9a5SSteve French * TODO Try to avoid memory allocations
251*38c8a9a5SSteve French */
cifs_find_swn_reg(struct cifs_tcon * tcon)252*38c8a9a5SSteve French static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
253*38c8a9a5SSteve French {
254*38c8a9a5SSteve French struct cifs_swn_reg *swnreg;
255*38c8a9a5SSteve French int id;
256*38c8a9a5SSteve French const char *share_name;
257*38c8a9a5SSteve French const char *net_name;
258*38c8a9a5SSteve French
259*38c8a9a5SSteve French net_name = extract_hostname(tcon->tree_name);
260*38c8a9a5SSteve French if (IS_ERR(net_name)) {
261*38c8a9a5SSteve French int ret;
262*38c8a9a5SSteve French
263*38c8a9a5SSteve French ret = PTR_ERR(net_name);
264*38c8a9a5SSteve French cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n",
265*38c8a9a5SSteve French __func__, tcon->tree_name, ret);
266*38c8a9a5SSteve French return ERR_PTR(-EINVAL);
267*38c8a9a5SSteve French }
268*38c8a9a5SSteve French
269*38c8a9a5SSteve French share_name = extract_sharename(tcon->tree_name);
270*38c8a9a5SSteve French if (IS_ERR(share_name)) {
271*38c8a9a5SSteve French int ret;
272*38c8a9a5SSteve French
273*38c8a9a5SSteve French ret = PTR_ERR(share_name);
274*38c8a9a5SSteve French cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n",
275*38c8a9a5SSteve French __func__, tcon->tree_name, ret);
276*38c8a9a5SSteve French kfree(net_name);
277*38c8a9a5SSteve French return ERR_PTR(-EINVAL);
278*38c8a9a5SSteve French }
279*38c8a9a5SSteve French
280*38c8a9a5SSteve French idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
281*38c8a9a5SSteve French if (strcasecmp(swnreg->net_name, net_name) != 0
282*38c8a9a5SSteve French || strcasecmp(swnreg->share_name, share_name) != 0) {
283*38c8a9a5SSteve French continue;
284*38c8a9a5SSteve French }
285*38c8a9a5SSteve French
286*38c8a9a5SSteve French cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name,
287*38c8a9a5SSteve French swnreg->share_name);
288*38c8a9a5SSteve French
289*38c8a9a5SSteve French kfree(net_name);
290*38c8a9a5SSteve French kfree(share_name);
291*38c8a9a5SSteve French
292*38c8a9a5SSteve French return swnreg;
293*38c8a9a5SSteve French }
294*38c8a9a5SSteve French
295*38c8a9a5SSteve French kfree(net_name);
296*38c8a9a5SSteve French kfree(share_name);
297*38c8a9a5SSteve French
298*38c8a9a5SSteve French return ERR_PTR(-EEXIST);
299*38c8a9a5SSteve French }
300*38c8a9a5SSteve French
301*38c8a9a5SSteve French /*
302*38c8a9a5SSteve French * Get a registration for the tcon's server and share name, allocating a new one if it does not
303*38c8a9a5SSteve French * exists
304*38c8a9a5SSteve French */
cifs_get_swn_reg(struct cifs_tcon * tcon)305*38c8a9a5SSteve French static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
306*38c8a9a5SSteve French {
307*38c8a9a5SSteve French struct cifs_swn_reg *reg = NULL;
308*38c8a9a5SSteve French int ret;
309*38c8a9a5SSteve French
310*38c8a9a5SSteve French mutex_lock(&cifs_swnreg_idr_mutex);
311*38c8a9a5SSteve French
312*38c8a9a5SSteve French /* Check if we are already registered for this network and share names */
313*38c8a9a5SSteve French reg = cifs_find_swn_reg(tcon);
314*38c8a9a5SSteve French if (!IS_ERR(reg)) {
315*38c8a9a5SSteve French kref_get(®->ref_count);
316*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
317*38c8a9a5SSteve French return reg;
318*38c8a9a5SSteve French } else if (PTR_ERR(reg) != -EEXIST) {
319*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
320*38c8a9a5SSteve French return reg;
321*38c8a9a5SSteve French }
322*38c8a9a5SSteve French
323*38c8a9a5SSteve French reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC);
324*38c8a9a5SSteve French if (reg == NULL) {
325*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
326*38c8a9a5SSteve French return ERR_PTR(-ENOMEM);
327*38c8a9a5SSteve French }
328*38c8a9a5SSteve French
329*38c8a9a5SSteve French kref_init(®->ref_count);
330*38c8a9a5SSteve French
331*38c8a9a5SSteve French reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC);
332*38c8a9a5SSteve French if (reg->id < 0) {
333*38c8a9a5SSteve French cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__);
334*38c8a9a5SSteve French ret = reg->id;
335*38c8a9a5SSteve French goto fail;
336*38c8a9a5SSteve French }
337*38c8a9a5SSteve French
338*38c8a9a5SSteve French reg->net_name = extract_hostname(tcon->tree_name);
339*38c8a9a5SSteve French if (IS_ERR(reg->net_name)) {
340*38c8a9a5SSteve French ret = PTR_ERR(reg->net_name);
341*38c8a9a5SSteve French cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret);
342*38c8a9a5SSteve French goto fail_idr;
343*38c8a9a5SSteve French }
344*38c8a9a5SSteve French
345*38c8a9a5SSteve French reg->share_name = extract_sharename(tcon->tree_name);
346*38c8a9a5SSteve French if (IS_ERR(reg->share_name)) {
347*38c8a9a5SSteve French ret = PTR_ERR(reg->share_name);
348*38c8a9a5SSteve French cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret);
349*38c8a9a5SSteve French goto fail_net_name;
350*38c8a9a5SSteve French }
351*38c8a9a5SSteve French
352*38c8a9a5SSteve French reg->net_name_notify = true;
353*38c8a9a5SSteve French reg->share_name_notify = true;
354*38c8a9a5SSteve French reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT);
355*38c8a9a5SSteve French
356*38c8a9a5SSteve French reg->tcon = tcon;
357*38c8a9a5SSteve French
358*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
359*38c8a9a5SSteve French
360*38c8a9a5SSteve French return reg;
361*38c8a9a5SSteve French
362*38c8a9a5SSteve French fail_net_name:
363*38c8a9a5SSteve French kfree(reg->net_name);
364*38c8a9a5SSteve French fail_idr:
365*38c8a9a5SSteve French idr_remove(&cifs_swnreg_idr, reg->id);
366*38c8a9a5SSteve French fail:
367*38c8a9a5SSteve French kfree(reg);
368*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
369*38c8a9a5SSteve French return ERR_PTR(ret);
370*38c8a9a5SSteve French }
371*38c8a9a5SSteve French
cifs_swn_reg_release(struct kref * ref)372*38c8a9a5SSteve French static void cifs_swn_reg_release(struct kref *ref)
373*38c8a9a5SSteve French {
374*38c8a9a5SSteve French struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count);
375*38c8a9a5SSteve French int ret;
376*38c8a9a5SSteve French
377*38c8a9a5SSteve French ret = cifs_swn_send_unregister_message(swnreg);
378*38c8a9a5SSteve French if (ret < 0)
379*38c8a9a5SSteve French cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", __func__, ret);
380*38c8a9a5SSteve French
381*38c8a9a5SSteve French idr_remove(&cifs_swnreg_idr, swnreg->id);
382*38c8a9a5SSteve French kfree(swnreg->net_name);
383*38c8a9a5SSteve French kfree(swnreg->share_name);
384*38c8a9a5SSteve French kfree(swnreg);
385*38c8a9a5SSteve French }
386*38c8a9a5SSteve French
cifs_put_swn_reg(struct cifs_swn_reg * swnreg)387*38c8a9a5SSteve French static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg)
388*38c8a9a5SSteve French {
389*38c8a9a5SSteve French mutex_lock(&cifs_swnreg_idr_mutex);
390*38c8a9a5SSteve French kref_put(&swnreg->ref_count, cifs_swn_reg_release);
391*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
392*38c8a9a5SSteve French }
393*38c8a9a5SSteve French
cifs_swn_resource_state_changed(struct cifs_swn_reg * swnreg,const char * name,int state)394*38c8a9a5SSteve French static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const char *name, int state)
395*38c8a9a5SSteve French {
396*38c8a9a5SSteve French switch (state) {
397*38c8a9a5SSteve French case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
398*38c8a9a5SSteve French cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
399*38c8a9a5SSteve French cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true);
400*38c8a9a5SSteve French break;
401*38c8a9a5SSteve French case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
402*38c8a9a5SSteve French cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
403*38c8a9a5SSteve French cifs_signal_cifsd_for_reconnect(swnreg->tcon->ses->server, true);
404*38c8a9a5SSteve French break;
405*38c8a9a5SSteve French case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
406*38c8a9a5SSteve French cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
407*38c8a9a5SSteve French break;
408*38c8a9a5SSteve French }
409*38c8a9a5SSteve French return 0;
410*38c8a9a5SSteve French }
411*38c8a9a5SSteve French
cifs_sockaddr_equal(struct sockaddr_storage * addr1,struct sockaddr_storage * addr2)412*38c8a9a5SSteve French static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2)
413*38c8a9a5SSteve French {
414*38c8a9a5SSteve French if (addr1->ss_family != addr2->ss_family)
415*38c8a9a5SSteve French return false;
416*38c8a9a5SSteve French
417*38c8a9a5SSteve French if (addr1->ss_family == AF_INET) {
418*38c8a9a5SSteve French return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr,
419*38c8a9a5SSteve French &((const struct sockaddr_in *)addr2)->sin_addr,
420*38c8a9a5SSteve French sizeof(struct in_addr)) == 0);
421*38c8a9a5SSteve French }
422*38c8a9a5SSteve French
423*38c8a9a5SSteve French if (addr1->ss_family == AF_INET6) {
424*38c8a9a5SSteve French return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr,
425*38c8a9a5SSteve French &((const struct sockaddr_in6 *)addr2)->sin6_addr,
426*38c8a9a5SSteve French sizeof(struct in6_addr)) == 0);
427*38c8a9a5SSteve French }
428*38c8a9a5SSteve French
429*38c8a9a5SSteve French return false;
430*38c8a9a5SSteve French }
431*38c8a9a5SSteve French
cifs_swn_store_swn_addr(const struct sockaddr_storage * new,const struct sockaddr_storage * old,struct sockaddr_storage * dst)432*38c8a9a5SSteve French static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new,
433*38c8a9a5SSteve French const struct sockaddr_storage *old,
434*38c8a9a5SSteve French struct sockaddr_storage *dst)
435*38c8a9a5SSteve French {
436*38c8a9a5SSteve French __be16 port = cpu_to_be16(CIFS_PORT);
437*38c8a9a5SSteve French
438*38c8a9a5SSteve French if (old->ss_family == AF_INET) {
439*38c8a9a5SSteve French struct sockaddr_in *ipv4 = (struct sockaddr_in *)old;
440*38c8a9a5SSteve French
441*38c8a9a5SSteve French port = ipv4->sin_port;
442*38c8a9a5SSteve French } else if (old->ss_family == AF_INET6) {
443*38c8a9a5SSteve French struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old;
444*38c8a9a5SSteve French
445*38c8a9a5SSteve French port = ipv6->sin6_port;
446*38c8a9a5SSteve French }
447*38c8a9a5SSteve French
448*38c8a9a5SSteve French if (new->ss_family == AF_INET) {
449*38c8a9a5SSteve French struct sockaddr_in *ipv4 = (struct sockaddr_in *)new;
450*38c8a9a5SSteve French
451*38c8a9a5SSteve French ipv4->sin_port = port;
452*38c8a9a5SSteve French } else if (new->ss_family == AF_INET6) {
453*38c8a9a5SSteve French struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new;
454*38c8a9a5SSteve French
455*38c8a9a5SSteve French ipv6->sin6_port = port;
456*38c8a9a5SSteve French }
457*38c8a9a5SSteve French
458*38c8a9a5SSteve French *dst = *new;
459*38c8a9a5SSteve French
460*38c8a9a5SSteve French return 0;
461*38c8a9a5SSteve French }
462*38c8a9a5SSteve French
cifs_swn_reconnect(struct cifs_tcon * tcon,struct sockaddr_storage * addr)463*38c8a9a5SSteve French static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
464*38c8a9a5SSteve French {
465*38c8a9a5SSteve French int ret = 0;
466*38c8a9a5SSteve French
467*38c8a9a5SSteve French /* Store the reconnect address */
468*38c8a9a5SSteve French cifs_server_lock(tcon->ses->server);
469*38c8a9a5SSteve French if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr))
470*38c8a9a5SSteve French goto unlock;
471*38c8a9a5SSteve French
472*38c8a9a5SSteve French ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr,
473*38c8a9a5SSteve French &tcon->ses->server->swn_dstaddr);
474*38c8a9a5SSteve French if (ret < 0) {
475*38c8a9a5SSteve French cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret);
476*38c8a9a5SSteve French goto unlock;
477*38c8a9a5SSteve French }
478*38c8a9a5SSteve French tcon->ses->server->use_swn_dstaddr = true;
479*38c8a9a5SSteve French
480*38c8a9a5SSteve French /*
481*38c8a9a5SSteve French * Unregister to stop receiving notifications for the old IP address.
482*38c8a9a5SSteve French */
483*38c8a9a5SSteve French ret = cifs_swn_unregister(tcon);
484*38c8a9a5SSteve French if (ret < 0) {
485*38c8a9a5SSteve French cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
486*38c8a9a5SSteve French __func__, ret);
487*38c8a9a5SSteve French goto unlock;
488*38c8a9a5SSteve French }
489*38c8a9a5SSteve French
490*38c8a9a5SSteve French /*
491*38c8a9a5SSteve French * And register to receive notifications for the new IP address now that we have
492*38c8a9a5SSteve French * stored the new address.
493*38c8a9a5SSteve French */
494*38c8a9a5SSteve French ret = cifs_swn_register(tcon);
495*38c8a9a5SSteve French if (ret < 0) {
496*38c8a9a5SSteve French cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n",
497*38c8a9a5SSteve French __func__, ret);
498*38c8a9a5SSteve French goto unlock;
499*38c8a9a5SSteve French }
500*38c8a9a5SSteve French
501*38c8a9a5SSteve French cifs_signal_cifsd_for_reconnect(tcon->ses->server, false);
502*38c8a9a5SSteve French
503*38c8a9a5SSteve French unlock:
504*38c8a9a5SSteve French cifs_server_unlock(tcon->ses->server);
505*38c8a9a5SSteve French
506*38c8a9a5SSteve French return ret;
507*38c8a9a5SSteve French }
508*38c8a9a5SSteve French
cifs_swn_client_move(struct cifs_swn_reg * swnreg,struct sockaddr_storage * addr)509*38c8a9a5SSteve French static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr)
510*38c8a9a5SSteve French {
511*38c8a9a5SSteve French struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr;
512*38c8a9a5SSteve French struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr;
513*38c8a9a5SSteve French
514*38c8a9a5SSteve French if (addr->ss_family == AF_INET)
515*38c8a9a5SSteve French cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr);
516*38c8a9a5SSteve French else if (addr->ss_family == AF_INET6)
517*38c8a9a5SSteve French cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr);
518*38c8a9a5SSteve French
519*38c8a9a5SSteve French return cifs_swn_reconnect(swnreg->tcon, addr);
520*38c8a9a5SSteve French }
521*38c8a9a5SSteve French
cifs_swn_notify(struct sk_buff * skb,struct genl_info * info)522*38c8a9a5SSteve French int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info)
523*38c8a9a5SSteve French {
524*38c8a9a5SSteve French struct cifs_swn_reg *swnreg;
525*38c8a9a5SSteve French char name[256];
526*38c8a9a5SSteve French int type;
527*38c8a9a5SSteve French
528*38c8a9a5SSteve French if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) {
529*38c8a9a5SSteve French int swnreg_id;
530*38c8a9a5SSteve French
531*38c8a9a5SSteve French swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]);
532*38c8a9a5SSteve French mutex_lock(&cifs_swnreg_idr_mutex);
533*38c8a9a5SSteve French swnreg = idr_find(&cifs_swnreg_idr, swnreg_id);
534*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
535*38c8a9a5SSteve French if (swnreg == NULL) {
536*38c8a9a5SSteve French cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id);
537*38c8a9a5SSteve French return -EINVAL;
538*38c8a9a5SSteve French }
539*38c8a9a5SSteve French } else {
540*38c8a9a5SSteve French cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__);
541*38c8a9a5SSteve French return -EINVAL;
542*38c8a9a5SSteve French }
543*38c8a9a5SSteve French
544*38c8a9a5SSteve French if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) {
545*38c8a9a5SSteve French type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]);
546*38c8a9a5SSteve French } else {
547*38c8a9a5SSteve French cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__);
548*38c8a9a5SSteve French return -EINVAL;
549*38c8a9a5SSteve French }
550*38c8a9a5SSteve French
551*38c8a9a5SSteve French switch (type) {
552*38c8a9a5SSteve French case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: {
553*38c8a9a5SSteve French int state;
554*38c8a9a5SSteve French
555*38c8a9a5SSteve French if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) {
556*38c8a9a5SSteve French nla_strscpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME],
557*38c8a9a5SSteve French sizeof(name));
558*38c8a9a5SSteve French } else {
559*38c8a9a5SSteve French cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__);
560*38c8a9a5SSteve French return -EINVAL;
561*38c8a9a5SSteve French }
562*38c8a9a5SSteve French if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) {
563*38c8a9a5SSteve French state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]);
564*38c8a9a5SSteve French } else {
565*38c8a9a5SSteve French cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__);
566*38c8a9a5SSteve French return -EINVAL;
567*38c8a9a5SSteve French }
568*38c8a9a5SSteve French return cifs_swn_resource_state_changed(swnreg, name, state);
569*38c8a9a5SSteve French }
570*38c8a9a5SSteve French case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: {
571*38c8a9a5SSteve French struct sockaddr_storage addr;
572*38c8a9a5SSteve French
573*38c8a9a5SSteve French if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) {
574*38c8a9a5SSteve French nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr));
575*38c8a9a5SSteve French } else {
576*38c8a9a5SSteve French cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__);
577*38c8a9a5SSteve French return -EINVAL;
578*38c8a9a5SSteve French }
579*38c8a9a5SSteve French return cifs_swn_client_move(swnreg, &addr);
580*38c8a9a5SSteve French }
581*38c8a9a5SSteve French default:
582*38c8a9a5SSteve French cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type);
583*38c8a9a5SSteve French break;
584*38c8a9a5SSteve French }
585*38c8a9a5SSteve French
586*38c8a9a5SSteve French return 0;
587*38c8a9a5SSteve French }
588*38c8a9a5SSteve French
cifs_swn_register(struct cifs_tcon * tcon)589*38c8a9a5SSteve French int cifs_swn_register(struct cifs_tcon *tcon)
590*38c8a9a5SSteve French {
591*38c8a9a5SSteve French struct cifs_swn_reg *swnreg;
592*38c8a9a5SSteve French int ret;
593*38c8a9a5SSteve French
594*38c8a9a5SSteve French swnreg = cifs_get_swn_reg(tcon);
595*38c8a9a5SSteve French if (IS_ERR(swnreg))
596*38c8a9a5SSteve French return PTR_ERR(swnreg);
597*38c8a9a5SSteve French
598*38c8a9a5SSteve French ret = cifs_swn_send_register_message(swnreg);
599*38c8a9a5SSteve French if (ret < 0) {
600*38c8a9a5SSteve French cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret);
601*38c8a9a5SSteve French /* Do not put the swnreg or return error, the echo task will retry */
602*38c8a9a5SSteve French }
603*38c8a9a5SSteve French
604*38c8a9a5SSteve French return 0;
605*38c8a9a5SSteve French }
606*38c8a9a5SSteve French
cifs_swn_unregister(struct cifs_tcon * tcon)607*38c8a9a5SSteve French int cifs_swn_unregister(struct cifs_tcon *tcon)
608*38c8a9a5SSteve French {
609*38c8a9a5SSteve French struct cifs_swn_reg *swnreg;
610*38c8a9a5SSteve French
611*38c8a9a5SSteve French mutex_lock(&cifs_swnreg_idr_mutex);
612*38c8a9a5SSteve French
613*38c8a9a5SSteve French swnreg = cifs_find_swn_reg(tcon);
614*38c8a9a5SSteve French if (IS_ERR(swnreg)) {
615*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
616*38c8a9a5SSteve French return PTR_ERR(swnreg);
617*38c8a9a5SSteve French }
618*38c8a9a5SSteve French
619*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
620*38c8a9a5SSteve French
621*38c8a9a5SSteve French cifs_put_swn_reg(swnreg);
622*38c8a9a5SSteve French
623*38c8a9a5SSteve French return 0;
624*38c8a9a5SSteve French }
625*38c8a9a5SSteve French
cifs_swn_dump(struct seq_file * m)626*38c8a9a5SSteve French void cifs_swn_dump(struct seq_file *m)
627*38c8a9a5SSteve French {
628*38c8a9a5SSteve French struct cifs_swn_reg *swnreg;
629*38c8a9a5SSteve French struct sockaddr_in *sa;
630*38c8a9a5SSteve French struct sockaddr_in6 *sa6;
631*38c8a9a5SSteve French int id;
632*38c8a9a5SSteve French
633*38c8a9a5SSteve French seq_puts(m, "Witness registrations:");
634*38c8a9a5SSteve French
635*38c8a9a5SSteve French mutex_lock(&cifs_swnreg_idr_mutex);
636*38c8a9a5SSteve French idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
637*38c8a9a5SSteve French seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ",
638*38c8a9a5SSteve French id, kref_read(&swnreg->ref_count),
639*38c8a9a5SSteve French swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)",
640*38c8a9a5SSteve French swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)");
641*38c8a9a5SSteve French switch (swnreg->tcon->ses->server->dstaddr.ss_family) {
642*38c8a9a5SSteve French case AF_INET:
643*38c8a9a5SSteve French sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr;
644*38c8a9a5SSteve French seq_printf(m, "%pI4", &sa->sin_addr.s_addr);
645*38c8a9a5SSteve French break;
646*38c8a9a5SSteve French case AF_INET6:
647*38c8a9a5SSteve French sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr;
648*38c8a9a5SSteve French seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr);
649*38c8a9a5SSteve French if (sa6->sin6_scope_id)
650*38c8a9a5SSteve French seq_printf(m, "%%%u", sa6->sin6_scope_id);
651*38c8a9a5SSteve French break;
652*38c8a9a5SSteve French default:
653*38c8a9a5SSteve French seq_puts(m, "(unknown)");
654*38c8a9a5SSteve French }
655*38c8a9a5SSteve French seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)");
656*38c8a9a5SSteve French }
657*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
658*38c8a9a5SSteve French seq_puts(m, "\n");
659*38c8a9a5SSteve French }
660*38c8a9a5SSteve French
cifs_swn_check(void)661*38c8a9a5SSteve French void cifs_swn_check(void)
662*38c8a9a5SSteve French {
663*38c8a9a5SSteve French struct cifs_swn_reg *swnreg;
664*38c8a9a5SSteve French int id;
665*38c8a9a5SSteve French int ret;
666*38c8a9a5SSteve French
667*38c8a9a5SSteve French mutex_lock(&cifs_swnreg_idr_mutex);
668*38c8a9a5SSteve French idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) {
669*38c8a9a5SSteve French ret = cifs_swn_send_register_message(swnreg);
670*38c8a9a5SSteve French if (ret < 0)
671*38c8a9a5SSteve French cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret);
672*38c8a9a5SSteve French }
673*38c8a9a5SSteve French mutex_unlock(&cifs_swnreg_idr_mutex);
674*38c8a9a5SSteve French }
675