/* -*- Mode:C; Tab-width:4 -*- */
/*                                                                       */
/*                                                                       */
/*                      RESTRICTED RIGHTS LEGEND                         */
/*                                                                       */
/* Use, duplication, or disclosure by the Government is subject to       */
/* restrictions as set forth in subdivision (c)(1)(ii) of the Rights in  */
/* Technical Data and Computer Software clause at 252.227-7013.          */
/*                                                                       */
/*                    TEXAS INSTRUMENTS INCORPORATED.                    */
/*                            P.O. BOX 149149                            */
/*                         AUSTIN, TEXAS 78714-9149                      */
/*                              MS 2151                                  */
/*                                                                       */
/*  Copyright (C)   1987,1988,1989,1990 Texas Instruments Incorporated.  */
/*  All rights reserved.                                                 */
/*                                                                       */
/*
 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
 * unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify Sun RPC without charge, but are not authorized
 * to license or distribute it to anyone else except as part of a product or
 * program developed by the user.
 * 
 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 * 
 * Sun RPC is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 * 
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
 * OR ANY PART THEREOF.
 * 
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 * 
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */
#ifndef lint
static char sccsid[] = "@(#)svc_mac.c 1.1 86/02/03 Copyr 1987 Texas Instr";
#endif
	 
	 /*
	  * svc_mac.c,
	  * Server side for MAC based RPC.  (Does some caching in the hopes of
	  * achieving execute-at-most-once semantics.)
	  *
	  * Copyright (C) 1987, Texas Instruments, Inc.
	  */
	 
#include <stdio.h>
#include "rpc-types.h"
#include "::bsd:netinet:bsd-in.h"
#include "::bsd:sys:socket.h"
#include "::bsd:errno.h"
#include "xdr.h"
#include "auth.h"
#include "clnt.h"
#include "rpc_msg.h"
#include "svc.h"
#include <pmap_prot.h>
#include <addincomm.h>
#include <strings.h>
	 
	 char *malloc();
	 
#define MAX(a, b)     ((a > b) ? a : b)
	 
	 static bool_t		svcmac_recv();
	 static bool_t		svcmac_reply();
	 static int	svcmac_stat();  /* clm 10/16/89 - changed the enum xprt_stat to int */
	 static bool_t		svcmac_getargs();
	 static bool_t		svcmac_freeargs();
	 static void		svcmac_destroy();
	 
	 static struct xp_ops svcmac_op =
{
	svcmac_recv,
	svcmac_stat,
	svcmac_getargs,
	svcmac_reply,
	svcmac_freeargs,
	svcmac_destroy
  };

extern int errno;

/*
 * kept in xprt->xp_p1
 */

struct svcmac_data
{
	acb     *pkt;           /* Acb to be freed when done.    */
	char    *buf;           /* xdr buffer. A pointer into acb. */
	u_int   su_iosz;	    /* byte size of send.recv buffer */
	u_long	su_xid;		    /* transaction id */
	XDR	su_xdrs;	        /* XDR handle */
	char	su_verfbody[MAX_AUTH_BYTES];	/* verifier body */
};

#define	su_data(xprt)	((struct svcmac_data *)(xprt->xp_p1))

/*
 * Usage:
 *	xprt = svcmac_create(sock);
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svcmac_create
 * binds it to an arbitrary port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 * Once *xprt is initialized, it is registered as a transporter;
 * see (svc.h, xprt_register).
 * The routines returns NULL if a problem occurred.
 */
SVCXPRT *
  svcmac_bufcreate(sock, sendsz, recvsz)
int sock;
u_int sendsz, recvsz;
{
	bool_t madesock = FALSE;
	SVCXPRT *xprt;
	struct svcmac_data *su;
	struct sockaddr_in addr;
	int len = sizeof(struct sockaddr_in);
	
	if (sock == RPC_ANYSOCK)
	  {
		  if ((sock = socket(AF_MAC, SOCK_DGRAM, PF_MAC)) < 0)
			{
				printf("svcmac_bufcreate: socket creation problem\n");
				return ((SVCXPRT *)NULL);
			}
		  madesock = TRUE;
	  }
	
	addr.sin_addr.s_addr = 0;
	addr.sin_family = AF_MAC;
	addr.sin_port = 0;
	
	bind(sock, (struct sockaddr *)&addr, len);
	if (getsockname(sock, (caddr_t)&addr, &len) != 0)
	  {
		  printf("svcmac_bufcreate - cannot getsockname\n");
		  if (madesock)
			sockclose(sock);
		  return ((SVCXPRT *)NULL);
	  }
	
	
	xprt = (SVCXPRT *)malloc(sizeof(SVCXPRT));
	if (xprt == NULL)
	  {
		  printf("svcmac_bufcreate: out of memory\n");
		  return (NULL);
	  }
	su = (struct svcmac_data *)malloc(sizeof(*su));
	if (su == NULL)
	  {
		  printf("svcmac_bufcreate: out of memory\n");
		  return (NULL);
	  }
	
	su->pkt = 0;   
	su->buf = 0;
	su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
	
	xprt->xp_p1 = (caddr_t)su;
	xprt->xp_verf.oa_base = su->su_verfbody;
	xprt->xp_ops = &svcmac_op;
	xprt->xp_port = ntohs(addr.sin_port);
	xprt->xp_sock = sock;
	xprt_register(xprt);
	return (xprt);
}

SVCXPRT *
  svcmac_create(sock, sendsz, recvsz)
int sock;
{
#pragma unused (sendsz, recvsz)		/* 11/22/89 sbw */
	
	return(svcmac_bufcreate(sock, MACMSGSIZE, MACMSGSIZE));
}

/* clm 10/16/89 - changed the enum xprt_stat return type to int */
static int
  svcmac_stat(xprt)
SVCXPRT *xprt;
{
#pragma unused (xprt)		/* 11/22/89 sbw */
	
	return (XPRT_IDLE); 
}

static bool_t
  svcmac_recv(xprt, msg)
SVCXPRT *xprt;
struct rpc_msg *msg;
{
	struct svcmac_data *su = su_data(xprt);
	XDR *xdrs = &(su->su_xdrs);
	int rlen;
	
	xprt->xp_addrlen = sizeof(struct sockaddr_in);
	
	do
	  {
		  /* Just in case we missed releasing the previous packet we will do it now. */
		  if(su->pkt) 
		    {
			    recvfrom_acb_return(su->pkt);
			    su->pkt = 0;   
				su->buf = 0;  
		    }
		  
		  rlen = recvfrom_acb(xprt->xp_sock, &(su->pkt), &(su->buf), 0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
		  
	  } while(rlen == -1 && errno == EINTR);
	
	
	if (rlen < 4*sizeof(u_long))
	  return (FALSE);
	
	/* Create the xdr memory stream now that you have the acb. */
	xdrmem_create(&(su->su_xdrs), su->buf, su->su_iosz, XDR_DECODE);
	
	xdrs->x_op = XDR_DECODE;
	XDR_SETPOS(xdrs, 0);
	if (! xdr_callmsg(xdrs, msg))
	  return (FALSE);
	su->su_xid = msg->rm_xid;
	return (TRUE);
}

static bool_t
  svcmac_reply(xprt, msg)
SVCXPRT *xprt; 
struct rpc_msg *msg; 
{
	struct svcmac_data *su = su_data(xprt);
	XDR *xdrs = &(su->su_xdrs);
	int slen;
	bool_t stat = FALSE;
	
	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, 0);
	msg->rm_xid = su->su_xid;
	
	if (xdr_replymsg(xdrs, msg))
	  {
		  
		  /* Note that we are reusing the same acb that the call came in with. This assumes */
		  /* that we always get an 8k acb from lisp. */
		  if(!su->pkt)
		    DebugStr("\pNo packet available in svcmac_reply.");
		  
		  slen = (int)XDR_GETPOS(xdrs);
		  if(sendto_acb(xprt->xp_sock, su->pkt, slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) == slen)
		    stat = TRUE;
		  
		  su->pkt = 0;   
		  su->buf = 0;
	  }
	
	/* Return the packet if we do not send a reply. */
	if(su->pkt) 
	  {
		  recvfrom_acb_return(su->pkt);
		  su->pkt = 0;    
		  su->buf = 0;
	  }
	
	return (stat);
}

static bool_t
  svcmac_getargs(xprt, xdr_args, args_ptr)
SVCXPRT *xprt;
xdrproc_t xdr_args;
caddr_t args_ptr;
{
	
	return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr));
}

static bool_t
  svcmac_freeargs(xprt, xdr_args, args_ptr)
SVCXPRT *xprt;
xdrproc_t xdr_args;
caddr_t args_ptr;
{
	XDR *xdrs = &(su_data(xprt)->su_xdrs);
	struct svcmac_data *su = su_data(xprt);
	
	xdrs->x_op = XDR_FREE;
	return ((*xdr_args)(xdrs, args_ptr));
}

static void
  svcmac_destroy(xprt)
SVCXPRT *xprt;
{
	struct svcmac_data *su = su_data(xprt);
	
	xprt_unregister(xprt);
	sockclose(xprt->xp_sock);
	
	XDR_DESTROY(&(su->su_xdrs));
	free((caddr_t)su, sizeof(struct svcmac_data));
	free((caddr_t)xprt, sizeof(SVCXPRT));
}
