]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/libsa/bootparam.c
ping: use the monotonic clock to measure durations
[FreeBSD/FreeBSD.git] / stand / libsa / bootparam.c
1 /*      $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $  */
2
3 /*
4  * Copyright (c) 1995 Gordon W. Ross
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  * 4. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gordon W. Ross
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 /*
37  * RPC/bootparams
38  */
39
40 #include <sys/param.h>
41 #include <sys/socket.h>
42
43 #include <net/if.h>
44
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47
48 #include <string.h>
49
50 #include "rpcv2.h"
51
52 #include "stand.h"
53 #include "net.h"
54 #include "netif.h"
55 #include "rpc.h"
56 #include "bootparam.h"
57
58 #ifdef DEBUG_RPC
59 #define RPC_PRINTF(a)   printf a
60 #else
61 #define RPC_PRINTF(a)
62 #endif
63
64 struct in_addr  bp_server_addr; /* net order */
65 n_short         bp_server_port; /* net order */
66
67 /*
68  * RPC definitions for bootparamd
69  */
70 #define BOOTPARAM_PROG          100026
71 #define BOOTPARAM_VERS          1
72 #define BOOTPARAM_WHOAMI        1
73 #define BOOTPARAM_GETFILE       2
74
75 /*
76  * Inet address in RPC messages
77  * (Note, really four ints, NOT chars.  Blech.)
78  */
79 struct xdr_inaddr {
80         uint32_t  atype;
81         int32_t addr[4];
82 };
83
84 int xdr_inaddr_encode(char **p, struct in_addr ia);
85 int xdr_inaddr_decode(char **p, struct in_addr *ia);
86
87 int xdr_string_encode(char **p, char *str, int len);
88 int xdr_string_decode(char **p, char *str, int *len_p);
89
90
91 /*
92  * RPC: bootparam/whoami
93  * Given client IP address, get:
94  *      client name     (hostname)
95  *      domain name (domainname)
96  *      gateway address
97  *
98  * The hostname and domainname are set here for convenience.
99  *
100  * Note - bpsin is initialized to the broadcast address,
101  * and will be replaced with the bootparam server address
102  * after this call is complete.  Have to use PMAP_PROC_CALL
103  * to make sure we get responses only from a servers that
104  * know about us (don't want to broadcast a getport call).
105  */
106 int
107 bp_whoami(int sockfd)
108 {
109         /* RPC structures for PMAPPROC_CALLIT */
110         struct args {
111                 uint32_t prog;
112                 uint32_t vers;
113                 uint32_t proc;
114                 uint32_t arglen;
115                 struct xdr_inaddr xina;
116         } *args;
117         struct repl {
118                 uint16_t _pad;
119                 uint16_t port;
120                 uint32_t encap_len;
121                 /* encapsulated data here */
122                 n_long  capsule[64];
123         } *repl;
124         struct {
125                 n_long  h[RPC_HEADER_WORDS];
126                 struct args d;
127         } sdata;
128         char *send_tail, *recv_head;
129         struct iodesc *d;
130         void *pkt;
131         int len, x, rc;
132
133         RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
134
135         rc = -1;
136         if (!(d = socktodesc(sockfd))) {
137                 RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
138                 return (rc);
139         }
140         args = &sdata.d;
141
142         /*
143          * Build request args for PMAPPROC_CALLIT.
144          */
145         args->prog = htonl(BOOTPARAM_PROG);
146         args->vers = htonl(BOOTPARAM_VERS);
147         args->proc = htonl(BOOTPARAM_WHOAMI);
148         args->arglen = htonl(sizeof(struct xdr_inaddr));
149         send_tail = (char*) &args->xina;
150
151         /*
152          * append encapsulated data (client IP address)
153          */
154         if (xdr_inaddr_encode(&send_tail, myip))
155                 return (rc);
156
157         /* RPC: portmap/callit */
158         d->myport = htons(--rpc_port);
159         d->destip.s_addr = INADDR_BROADCAST;    /* XXX: subnet bcast? */
160         /* rpc_call will set d->destport */
161
162         pkt = NULL;
163         len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
164             args, send_tail - (char*)args, (void **)&repl, &pkt);
165         if (len < 8) {
166                 printf("bootparamd: 'whoami' call failed\n");
167                 goto done;
168         }
169
170         /* Save bootparam server address (from IP header). */
171         rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
172
173         /*
174          * Note that bp_server_port is now 111 due to the
175          * indirect call (using PMAPPROC_CALLIT), so get the
176          * actual port number from the reply data.
177          */
178         bp_server_port = repl->port;
179
180         RPC_PRINTF(("bp_whoami: server at %s:%d\n",
181             inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
182
183         /* We have just done a portmap call, so cache the portnum. */
184         rpc_pmap_putcache(bp_server_addr,
185                           BOOTPARAM_PROG,
186                           BOOTPARAM_VERS,
187                           (int)ntohs(bp_server_port));
188
189         /*
190          * Parse the encapsulated results from bootparam/whoami
191          */
192         x = ntohl(repl->encap_len);
193         if (len < x) {
194                 printf("bp_whoami: short reply, %d < %d\n", len, x);
195                 goto done;
196         }
197         recv_head = (char*) repl->capsule;
198
199         /* client name */
200         hostnamelen = MAXHOSTNAMELEN-1;
201         if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
202                 RPC_PRINTF(("bp_whoami: bad hostname\n"));
203                 goto done;
204         }
205
206         /* domain name */
207         domainnamelen = MAXHOSTNAMELEN-1;
208         if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
209                 RPC_PRINTF(("bp_whoami: bad domainname\n"));
210                 goto done;
211         }
212
213         /* gateway address */
214         if (xdr_inaddr_decode(&recv_head, &gateip)) {
215                 RPC_PRINTF(("bp_whoami: bad gateway\n"));
216                 goto done;
217         }
218
219         /* success */
220         rc = 0;
221 done:
222         free(pkt);
223         return (rc);
224 }
225
226
227 /*
228  * RPC: bootparam/getfile
229  * Given client name and file "key", get:
230  *      server name
231  *      server IP address
232  *      server pathname
233  */
234 int
235 bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
236 {
237         struct {
238                 n_long  h[RPC_HEADER_WORDS];
239                 n_long  d[64];
240         } sdata;
241         void *pkt;
242         char serv_name[FNAME_SIZE];
243         char *rdata, *send_tail;
244         /* misc... */
245         struct iodesc *d;
246         int rc = -1, sn_len, path_len, rlen;
247
248         if (!(d = socktodesc(sockfd))) {
249                 RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
250                 return (-1);
251         }
252
253         send_tail = (char*) sdata.d;
254
255         /*
256          * Build request message.
257          */
258
259         /* client name (hostname) */
260         if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
261                 RPC_PRINTF(("bp_getfile: bad client\n"));
262                 return (-1);
263         }
264
265         /* key name (root or swap) */
266         if (xdr_string_encode(&send_tail, key, strlen(key))) {
267                 RPC_PRINTF(("bp_getfile: bad key\n"));
268                 return (-1);
269         }
270
271         /* RPC: bootparam/getfile */
272         d->myport = htons(--rpc_port);
273         d->destip   = bp_server_addr;
274         /* rpc_call will set d->destport */
275         pkt = NULL;
276         rlen = rpc_call(d,
277                 BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
278                 sdata.d, send_tail - (char*)sdata.d,
279                 (void **)&rdata, &pkt);
280         if (rlen < 4) {
281                 RPC_PRINTF(("bp_getfile: short reply\n"));
282                 errno = EBADRPC;
283                 goto done;
284         }
285
286         /*
287          * Parse result message.
288          */
289
290         /* server name */
291         sn_len = FNAME_SIZE-1;
292         if (xdr_string_decode(&rdata, serv_name, &sn_len)) {
293                 RPC_PRINTF(("bp_getfile: bad server name\n"));
294                 goto done;
295         }
296
297         /* server IP address (mountd/NFS) */
298         if (xdr_inaddr_decode(&rdata, serv_addr)) {
299                 RPC_PRINTF(("bp_getfile: bad server addr\n"));
300                 goto done;
301         }
302
303         /* server pathname */
304         path_len = MAXPATHLEN-1;
305         if (xdr_string_decode(&rdata, pathname, &path_len)) {
306                 RPC_PRINTF(("bp_getfile: bad server path\n"));
307                 goto done;
308         }
309
310         /* success */
311         rc = 0;
312 done:
313         free(pkt);
314         return (rc);
315 }
316
317
318 /*
319  * eXternal Data Representation routines.
320  * (but with non-standard args...)
321  */
322
323
324 int
325 xdr_string_encode(char **pkt, char *str, int len)
326 {
327         uint32_t *lenp;
328         char *datap;
329         int padlen = (len + 3) & ~3;    /* padded length */
330
331         /* The data will be int aligned. */
332         lenp = (uint32_t *) *pkt;
333         *pkt += sizeof(*lenp);
334         *lenp = htonl(len);
335
336         datap = *pkt;
337         *pkt += padlen;
338         bcopy(str, datap, len);
339
340         return (0);
341 }
342
343 int
344 xdr_string_decode(char **pkt, char *str, int *len_p)
345 {
346         uint32_t *lenp;
347         char *datap;
348         int slen;       /* string length */
349         int plen;       /* padded length */
350
351         /* The data will be int aligned. */
352         lenp = (uint32_t *) *pkt;
353         *pkt += sizeof(*lenp);
354         slen = ntohl(*lenp);
355         plen = (slen + 3) & ~3;
356
357         if (slen > *len_p)
358                 slen = *len_p;
359         datap = *pkt;
360         *pkt += plen;
361         bcopy(datap, str, slen);
362
363         str[slen] = '\0';
364         *len_p = slen;
365
366         return (0);
367 }
368
369
370 int
371 xdr_inaddr_encode(char **pkt, struct in_addr ia)
372 {
373         struct xdr_inaddr *xi;
374         u_char *cp;
375         int32_t *ip;
376         union {
377                 n_long l;       /* network order */
378                 u_char c[4];
379         } uia;
380
381         /* The data will be int aligned. */
382         xi = (struct xdr_inaddr *) *pkt;
383         *pkt += sizeof(*xi);
384         xi->atype = htonl(1);
385         uia.l = ia.s_addr;
386         cp = uia.c;
387         ip = xi->addr;
388         /*
389          * Note: the htonl() calls below DO NOT
390          * imply that uia.l is in host order.
391          * In fact this needs it in net order.
392          */
393         *ip++ = htonl((unsigned int)*cp++);
394         *ip++ = htonl((unsigned int)*cp++);
395         *ip++ = htonl((unsigned int)*cp++);
396         *ip++ = htonl((unsigned int)*cp++);
397
398         return (0);
399 }
400
401 int
402 xdr_inaddr_decode(char **pkt, struct in_addr *ia)
403 {
404         struct xdr_inaddr *xi;
405         u_char *cp;
406         int32_t *ip;
407         union {
408                 n_long l;       /* network order */
409                 u_char c[4];
410         } uia;
411
412         /* The data will be int aligned. */
413         xi = (struct xdr_inaddr *) *pkt;
414         *pkt += sizeof(*xi);
415         if (xi->atype != htonl(1)) {
416                 RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
417                     ntohl(xi->atype)));
418                 return(-1);
419         }
420
421         cp = uia.c;
422         ip = xi->addr;
423         /*
424          * Note: the ntohl() calls below DO NOT
425          * imply that uia.l is in host order.
426          * In fact this needs it in net order.
427          */
428         *cp++ = ntohl(*ip++);
429         *cp++ = ntohl(*ip++);
430         *cp++ = ntohl(*ip++);
431         *cp++ = ntohl(*ip++);
432         ia->s_addr = uia.l;
433
434         return (0);
435 }