1 /* 2 * linux/fs/lockd/mon.c 3 * 4 * The kernel statd client. 5 * 6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 7 */ 8 9 #include <linux/types.h> 10 #include <linux/utsname.h> 11 #include <linux/kernel.h> 12 #include <linux/sunrpc/clnt.h> 13 #include <linux/sunrpc/xprtsock.h> 14 #include <linux/sunrpc/svc.h> 15 #include <linux/lockd/lockd.h> 16 #include <linux/lockd/sm_inter.h> 17 18 19 #define NLMDBG_FACILITY NLMDBG_MONITOR 20 21 #define XDR_ADDRBUF_LEN (20) 22 23 static struct rpc_clnt * nsm_create(void); 24 25 static struct rpc_program nsm_program; 26 27 /* 28 * Local NSM state 29 */ 30 int nsm_local_state; 31 32 /* 33 * Common procedure for SM_MON/SM_UNMON calls 34 */ 35 static int 36 nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 37 { 38 struct rpc_clnt *clnt; 39 int status; 40 struct nsm_args args; 41 struct rpc_message msg = { 42 .rpc_argp = &args, 43 .rpc_resp = res, 44 }; 45 46 clnt = nsm_create(); 47 if (IS_ERR(clnt)) { 48 status = PTR_ERR(clnt); 49 goto out; 50 } 51 52 memset(&args, 0, sizeof(args)); 53 args.mon_name = nsm->sm_name; 54 args.addr = nsm_addr_in(nsm)->sin_addr.s_addr; 55 args.prog = NLM_PROGRAM; 56 args.vers = 3; 57 args.proc = NLMPROC_NSM_NOTIFY; 58 memset(res, 0, sizeof(*res)); 59 60 msg.rpc_proc = &clnt->cl_procinfo[proc]; 61 status = rpc_call_sync(clnt, &msg, 0); 62 if (status < 0) 63 printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n", 64 status); 65 else 66 status = 0; 67 rpc_shutdown_client(clnt); 68 out: 69 return status; 70 } 71 72 /* 73 * Set up monitoring of a remote host 74 */ 75 int 76 nsm_monitor(struct nlm_host *host) 77 { 78 struct nsm_handle *nsm = host->h_nsmhandle; 79 struct nsm_res res; 80 int status; 81 82 dprintk("lockd: nsm_monitor(%s)\n", host->h_name); 83 BUG_ON(nsm == NULL); 84 85 if (nsm->sm_monitored) 86 return 0; 87 88 status = nsm_mon_unmon(nsm, SM_MON, &res); 89 90 if (status < 0 || res.status != 0) 91 printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); 92 else 93 nsm->sm_monitored = 1; 94 return status; 95 } 96 97 /* 98 * Cease to monitor remote host 99 */ 100 int 101 nsm_unmonitor(struct nlm_host *host) 102 { 103 struct nsm_handle *nsm = host->h_nsmhandle; 104 struct nsm_res res; 105 int status = 0; 106 107 if (nsm == NULL) 108 return 0; 109 host->h_nsmhandle = NULL; 110 111 if (atomic_read(&nsm->sm_count) == 1 112 && nsm->sm_monitored && !nsm->sm_sticky) { 113 dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); 114 115 status = nsm_mon_unmon(nsm, SM_UNMON, &res); 116 if (status < 0) 117 printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 118 host->h_name); 119 else 120 nsm->sm_monitored = 0; 121 } 122 nsm_release(nsm); 123 return status; 124 } 125 126 /* 127 * Create NSM client for the local host 128 */ 129 static struct rpc_clnt * 130 nsm_create(void) 131 { 132 struct sockaddr_in sin = { 133 .sin_family = AF_INET, 134 .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 135 .sin_port = 0, 136 }; 137 struct rpc_create_args args = { 138 .protocol = XPRT_TRANSPORT_UDP, 139 .address = (struct sockaddr *)&sin, 140 .addrsize = sizeof(sin), 141 .servername = "localhost", 142 .program = &nsm_program, 143 .version = SM_VERSION, 144 .authflavor = RPC_AUTH_NULL, 145 }; 146 147 return rpc_create(&args); 148 } 149 150 /* 151 * XDR functions for NSM. 152 * 153 * See http://www.opengroup.org/ for details on the Network 154 * Status Monitor wire protocol. 155 */ 156 157 static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) 158 { 159 size_t len = strlen(string); 160 161 if (len > SM_MAXSTRLEN) 162 len = SM_MAXSTRLEN; 163 return xdr_encode_opaque(p, string, len); 164 } 165 166 /* 167 * "mon_name" specifies the host to be monitored. 168 * 169 * Linux uses a text version of the IP address of the remote 170 * host as the host identifier (the "mon_name" argument). 171 * 172 * Linux statd always looks up the canonical hostname first for 173 * whatever remote hostname it receives, so this works alright. 174 */ 175 static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) 176 { 177 char buffer[XDR_ADDRBUF_LEN + 1]; 178 char *name = argp->mon_name; 179 180 if (!nsm_use_hostnames) { 181 snprintf(buffer, XDR_ADDRBUF_LEN, 182 NIPQUAD_FMT, NIPQUAD(argp->addr)); 183 name = buffer; 184 } 185 186 return xdr_encode_nsm_string(p, name); 187 } 188 189 /* 190 * The "my_id" argument specifies the hostname and RPC procedure 191 * to be called when the status manager receives notification 192 * (via the SM_NOTIFY call) that the state of host "mon_name" 193 * has changed. 194 */ 195 static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) 196 { 197 p = xdr_encode_nsm_string(p, utsname()->nodename); 198 if (!p) 199 return ERR_PTR(-EIO); 200 201 *p++ = htonl(argp->prog); 202 *p++ = htonl(argp->vers); 203 *p++ = htonl(argp->proc); 204 205 return p; 206 } 207 208 /* 209 * The "mon_id" argument specifies the non-private arguments 210 * of an SM_MON or SM_UNMON call. 211 */ 212 static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) 213 { 214 p = xdr_encode_mon_name(p, argp); 215 if (!p) 216 return ERR_PTR(-EIO); 217 218 return xdr_encode_my_id(p, argp); 219 } 220 221 /* 222 * The "priv" argument may contain private information required 223 * by the SM_MON call. This information will be supplied in the 224 * SM_NOTIFY call. 225 * 226 * Linux provides the raw IP address of the monitored host, 227 * left in network byte order. 228 */ 229 static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) 230 { 231 *p++ = argp->addr; 232 *p++ = 0; 233 *p++ = 0; 234 *p++ = 0; 235 236 return p; 237 } 238 239 static int 240 xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 241 { 242 p = xdr_encode_mon_id(p, argp); 243 if (IS_ERR(p)) 244 return PTR_ERR(p); 245 246 p = xdr_encode_priv(p, argp); 247 if (IS_ERR(p)) 248 return PTR_ERR(p); 249 250 rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 251 return 0; 252 } 253 254 static int 255 xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 256 { 257 p = xdr_encode_mon_id(p, argp); 258 if (IS_ERR(p)) 259 return PTR_ERR(p); 260 rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 261 return 0; 262 } 263 264 static int 265 xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 266 { 267 resp->status = ntohl(*p++); 268 resp->state = ntohl(*p++); 269 dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 270 resp->status, resp->state); 271 return 0; 272 } 273 274 static int 275 xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 276 { 277 resp->state = ntohl(*p++); 278 return 0; 279 } 280 281 #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 282 #define SM_my_id_sz (SM_my_name_sz+3) 283 #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 284 #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) 285 #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) 286 #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) 287 #define SM_monres_sz 2 288 #define SM_unmonres_sz 1 289 290 static struct rpc_procinfo nsm_procedures[] = { 291 [SM_MON] = { 292 .p_proc = SM_MON, 293 .p_encode = (kxdrproc_t) xdr_encode_mon, 294 .p_decode = (kxdrproc_t) xdr_decode_stat_res, 295 .p_arglen = SM_mon_sz, 296 .p_replen = SM_monres_sz, 297 .p_statidx = SM_MON, 298 .p_name = "MONITOR", 299 }, 300 [SM_UNMON] = { 301 .p_proc = SM_UNMON, 302 .p_encode = (kxdrproc_t) xdr_encode_unmon, 303 .p_decode = (kxdrproc_t) xdr_decode_stat, 304 .p_arglen = SM_mon_id_sz, 305 .p_replen = SM_unmonres_sz, 306 .p_statidx = SM_UNMON, 307 .p_name = "UNMONITOR", 308 }, 309 }; 310 311 static struct rpc_version nsm_version1 = { 312 .number = 1, 313 .nrprocs = ARRAY_SIZE(nsm_procedures), 314 .procs = nsm_procedures 315 }; 316 317 static struct rpc_version * nsm_version[] = { 318 [1] = &nsm_version1, 319 }; 320 321 static struct rpc_stat nsm_stats; 322 323 static struct rpc_program nsm_program = { 324 .name = "statd", 325 .number = SM_PROGRAM, 326 .nrvers = ARRAY_SIZE(nsm_version), 327 .version = nsm_version, 328 .stats = &nsm_stats 329 }; 330