#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <nfs/rpcv2.h>
#include "stand.h"
#include "net.h"
#include "netif.h"
#include "rpc.h"
#include "bootparam.h"
#ifdef DEBUG_RPC
#define RPC_PRINTF(a) printf a
#else
#define RPC_PRINTF(a)
#endif
struct in_addr bp_server_addr;
u_int16_t bp_server_port;
#define BOOTPARAM_PROG 100026
#define BOOTPARAM_VERS 1
#define BOOTPARAM_WHOAMI 1
#define BOOTPARAM_GETFILE 2
struct xdr_inaddr {
u_int32_t atype;
int32_t addr[4];
};
int xdr_inaddr_encode(char **p, struct in_addr ia);
int xdr_inaddr_decode(char **p, struct in_addr *ia);
int xdr_string_encode(char **p, char *str, int len);
int xdr_string_decode(char **p, char *str, int *len_p);
int
bp_whoami(int sockfd)
{
struct args {
u_int32_t prog;
u_int32_t vers;
u_int32_t proc;
u_int32_t arglen;
struct xdr_inaddr xina;
} *args;
struct repl {
u_int16_t _pad;
u_int16_t port;
u_int32_t encap_len;
u_int32_t capsule[64];
} *repl;
struct {
u_int32_t h[RPC_HEADER_WORDS];
struct args d;
} sdata;
struct {
u_int32_t h[RPC_HEADER_WORDS];
struct repl d;
} rdata;
char *send_tail, *recv_head;
struct iodesc *d;
int len, x;
RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
return (-1);
}
args = &sdata.d;
repl = &rdata.d;
args->prog = htonl(BOOTPARAM_PROG);
args->vers = htonl(BOOTPARAM_VERS);
args->proc = htonl(BOOTPARAM_WHOAMI);
args->arglen = htonl(sizeof(struct xdr_inaddr));
send_tail = (char *)&args->xina;
if (xdr_inaddr_encode(&send_tail, myip))
return (-1);
d->myport = htons(--rpc_port);
d->destip.s_addr = INADDR_BROADCAST;
len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
args, send_tail - (char *)args,
repl, sizeof(*repl));
if (len < 8) {
printf("bootparamd: 'whoami' call failed\n");
return (-1);
}
rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
bp_server_port = repl->port;
RPC_PRINTF(("bp_whoami: server at %s:%d\n",
inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
rpc_pmap_putcache(bp_server_addr, BOOTPARAM_PROG, BOOTPARAM_VERS,
(int)ntohs(bp_server_port));
x = ntohl(repl->encap_len);
if (len < x) {
printf("bp_whoami: short reply, %d < %d\n", len, x);
return (-1);
}
recv_head = (char *)repl->capsule;
hostnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
RPC_PRINTF(("bp_whoami: bad hostname\n"));
return (-1);
}
domainnamelen = MAXHOSTNAMELEN-1;
if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
RPC_PRINTF(("bp_whoami: bad domainname\n"));
return (-1);
}
if (xdr_inaddr_decode(&recv_head, &gateip)) {
RPC_PRINTF(("bp_whoami: bad gateway\n"));
return (-1);
}
return(0);
}
int
bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
{
struct {
u_int32_t h[RPC_HEADER_WORDS];
u_int32_t d[64];
} sdata;
struct {
u_int32_t h[RPC_HEADER_WORDS];
u_int32_t d[128];
} rdata;
char serv_name[FNAME_SIZE];
char *send_tail, *recv_head;
struct iodesc *d;
int sn_len, path_len, rlen;
if (!(d = socktodesc(sockfd))) {
RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
return (-1);
}
send_tail = (char *)sdata.d;
recv_head = (char *)rdata.d;
if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
RPC_PRINTF(("bp_getfile: bad client\n"));
return (-1);
}
if (xdr_string_encode(&send_tail, key, strlen(key))) {
RPC_PRINTF(("bp_getfile: bad key\n"));
return (-1);
}
d->myport = htons(--rpc_port);
d->destip = bp_server_addr;
rlen = rpc_call(d,
BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
sdata.d, send_tail - (char *)sdata.d,
rdata.d, sizeof(rdata.d));
if (rlen < 4) {
RPC_PRINTF(("bp_getfile: short reply\n"));
errno = EBADRPC;
return (-1);
}
recv_head = (char *)rdata.d;
sn_len = FNAME_SIZE-1;
if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
RPC_PRINTF(("bp_getfile: bad server name\n"));
return (-1);
}
if (xdr_inaddr_decode(&recv_head, serv_addr)) {
RPC_PRINTF(("bp_getfile: bad server addr\n"));
return (-1);
}
path_len = MAXPATHLEN-1;
if (xdr_string_decode(&recv_head, pathname, &path_len)) {
RPC_PRINTF(("bp_getfile: bad server path\n"));
return (-1);
}
return(0);
}
int
xdr_string_encode(char **pkt, char *str, int len)
{
u_int32_t *lenp;
char *datap;
int padlen = (len + 3) & ~3;
lenp = (u_int32_t*) *pkt;
*pkt += sizeof(*lenp);
*lenp = htonl(len);
datap = *pkt;
*pkt += padlen;
bcopy(str, datap, len);
return (0);
}
int
xdr_string_decode(char **pkt, char *str, int *len_p)
{
u_int32_t *lenp;
char *datap;
int slen;
int plen;
lenp = (u_int32_t*) *pkt;
*pkt += sizeof(*lenp);
slen = ntohl(*lenp);
plen = (slen + 3) & ~3;
if (slen > *len_p)
slen = *len_p;
datap = *pkt;
*pkt += plen;
bcopy(datap, str, slen);
str[slen] = '\0';
*len_p = slen;
return (0);
}
int
xdr_inaddr_encode(char **pkt, struct in_addr ia)
{
struct xdr_inaddr *xi;
u_char *cp;
int32_t *ip;
union {
u_int32_t l;
u_char c[4];
} uia;
xi = (struct xdr_inaddr *) *pkt;
*pkt += sizeof(*xi);
xi->atype = htonl(1);
uia.l = ia.s_addr;
cp = uia.c;
ip = xi->addr;
*ip++ = htonl((unsigned int)*cp++);
*ip++ = htonl((unsigned int)*cp++);
*ip++ = htonl((unsigned int)*cp++);
*ip++ = htonl((unsigned int)*cp++);
return (0);
}
int
xdr_inaddr_decode(char **pkt, struct in_addr *ia)
{
struct xdr_inaddr *xi;
u_char *cp;
int32_t *ip;
union {
u_int32_t l;
u_char c[4];
} uia;
xi = (struct xdr_inaddr *) *pkt;
*pkt += sizeof(*xi);
if (xi->atype != htonl(1)) {
RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
ntohl(xi->atype)));
return(-1);
}
cp = uia.c;
ip = xi->addr;
*cp++ = ntohl(*ip++);
*cp++ = ntohl(*ip++);
*cp++ = ntohl(*ip++);
*cp++ = ntohl(*ip++);
ia->s_addr = uia.l;
return (0);
}