Patch #:	none yet
Type:		operational change
Priority:	none
Modification:	add support for AppleShareIP (AFP via TCP/IP)
Submitted:	  David Hornsby <djh@munnari.OZ.AU>
IMPORTANT:
IMPORTANT:	This patch assumes CAP at patch level 198
IMPORTANT:	This is an interim patch only. You will need to keep this
IMPORTANT:	patch file in order to reverse the code changes before patch
IMPORTANT:	199 can be applied without error. When reversing this patch,
IMPORTANT:	you also need to manually remove the following files:
IMPORTANT:	  rm cap60/applications/aufs/afpdsi.h
IMPORTANT:	  rm cap60/applications/aufs/afpdsi.c
IMPORTANT:	  rm cap60/etc/aufsIPFilter
IMPORTANT:
IMPORTANT:	To use the TCP/IP functionality, you will require AppleShare
IMPORTANT:	Client version 3.7 or later, obtainable from Apple web sites
IMPORTANT:
IMPORTANT:	http://appleshareip.apple.com/appleshareip/text/downloads.html
IMPORTANT:
File:		cap60/applications/aufs/afpdsi.h
File:		cap60/applications/aufs/afpdsi.c
File:		cap60/applications/aufs/afpdt.c
File:		cap60/applications/aufs/afpfork.c
File:		cap60/applications/aufs/afpos.c
File:		cap60/applications/aufs/afps.h
File:		cap60/applications/aufs/afpserver.c
File:		cap60/applications/aufs/aufs.c
File:		cap60/applications/aufs/Makefile.m4
File:		cap60/lib/afp/afppacks.c
File:		cap60/lib/cap/abasp.c
File:		cap60/lib/cap/absched.c
File:		cap60/etc/aufsIPFilter
File:		cap60/samples/ash.c
File:		cap60/man/AUFS.8
File:		cap60/netat/afp.h
File:		cap60/netat/afpcmd.h


*** applications/aufs/afpdsi.h.orig	Mon Jul 14 12:20:23 1997
--- applications/aufs/afpdsi.h		Fri Jul 11 20:07:07 1997
***************
*** 0 ****
--- 1,108 ----
+ /*
+  * $Author: djh $ $Date: 91/03/14 13:45:20 $
+  * $Header: afpdsi.h,v 2.2 91/03/14 13:45:20 djh Exp $
+  * $Revision: 2.2 $
+  *
+  */
+ 
+ /*
+  * afpdsi.h - Data Stream Interface Includes
+  *
+  * AFP via a Transport Protocol (eg: TCP/IP)
+  *
+  * AppleTalk package for UNIX
+  *
+  * The following routines implement a lightweight extra
+  * layer between AFP (as embodied in the AUFS code), the
+  * original ASP via ATP layer, and delivery via other
+  * Transport Protocol layers, currently only TCP/IP.
+  *
+  * Refer: "AppleTalk Filing Protocol 2.2 &
+  *         AFP over TCP/IP Specification"
+  * 
+  * SSS == Server Session Socket
+  * SLS == Session Listening Socket
+  * WSS == Workstation Session Socket
+  *
+  * Copyright (c) 1997 The University of Melbourne
+  * David Hornsby <djh@munnari.OZ.AU>
+  *
+  */
+ 
+ /*
+  * options
+  *
+  */
+ #define DSI_OPT_REQQ	0x00
+ #define DSI_OPT_ATTQ	0x01
+ 
+ #define DSI_OPT_REQLEN	4
+ #define DSI_OPT_ATTLEN	4
+ 
+ /*
+  * quantum sizes
+  *
+  */
+ #define DSI_ATTN_SIZ	2
+ #define DSI_SRVR_CMD	1500
+ #define DSI_SRVR_MAX	64*1024
+ 
+ /*
+  * the DSI header will be inserted in front of
+  * every AFP request or reply packet
+  *
+  */
+ 
+ struct dsi_hdr {
+   byte dsi_flags;		/* used to determine packet type */
+ #define DSI_REQ_FLAG	0x00
+ #define DSI_REP_FLAG	0x01
+   byte dsi_command;		/* similar to ASP commands, except WrtCont */
+ #define DSICloseSession	1
+ #define DSICommand	2
+ #define DSIGetStatus	3
+ #define DSIOpenSession	4
+ #define DSITickle	5
+ #define DSIWrite	6
+ #define DSIAttention	8
+   word dsi_requestID;		/* req ID on per-session basis, wraps */
+   dword dsi_err_offset;		/* error for reply, offset for write, else 0 */
+   dword dsi_data_len;		/* total data length following dsi_hdr */
+   dword dsi_reserved;		/* reserved for future, should be zero */
+ };
+ 
+ /*
+  * per-session demux info
+  *
+  */
+ struct dsi_sess {
+   int sesstype;
+ #define DSI_SESSION_ATALK	0x01
+ #define DSI_SESSION_TCPIP	0x02
+   int state;			/* type of DSI data expected */
+ #define DSI_STATE_HDR		0x01
+ #define DSI_STATE_AFP		0x02
+ #define DSI_STATE_DAT		0x03
+ #define DSI_STATE_REP		0x04
+   char *ptr;			/* where we have to put incoming data */
+   int lenleft;			/* amount of data expected to arrive */
+   int timeout;			/* per-session tickle timer */
+ #define DSI_TIMEOUT		5*4
+   word sess_id_out;		/* outgoing session ID (0-65535) */
+   word sess_id_in;		/* incoming session ID (0-65535) */
+   struct dsi_hdr hdr;		/* current incoming header (for reply) */
+   ASPQE *aspqe;			/* callback data for GetRequest etc. */
+ };
+ 
+ /*
+  * IP filter list
+  *
+  */
+ #define MAXIPFILTERS	100
+ #define MAXIPFILTSIZ	sizeof(struct ipFilter)
+ 
+ struct ipFilter {
+   sword perm;
+   dword mask;
+   dword addr;
+ };
*** applications/aufs/afpdsi.c.orig	Mon Jul 14 14:04:28 1997
--- applications/aufs/afpdsi.c		Sun Apr 19 19:21:07 1998
***************
*** 0 ****
--- 1,2029 ----
+ /*
+  * $Author: djh $ $Date: 91/03/14 13:45:20 $
+  * $Header: afpdsi.c,v 2.2 91/03/14 13:45:20 djh Exp $
+  * $Revision: 2.2 $
+  *
+  */
+ 
+ /*
+  * afpdsi.c - Data Stream Interface
+  *
+  * AFP via a Transport Protocol (eg: TCP/IP)
+  *
+  * AppleTalk package for UNIX
+  *
+  * The following routines implement a lightweight extra
+  * layer between AFP (as embodied in the AUFS code), the
+  * original ASP via ATP layer, and delivery via other
+  * Transport Protocol layers, currently only TCP/IP.
+  *
+  * Refer: "AppleTalk Filing Protocol 2.2 &
+  *         AFP over TCP/IP Specification"
+  * 
+  * SSS == Server Session Socket
+  * SLS == Session Listening Socket
+  * WSS == Workstation Session Socket
+  *
+  * Copyright (c) 1997 The University of Melbourne
+  * David Hornsby <djh@munnari.OZ.AU>
+  *
+  */
+ 
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <netinet/tcp.h>
+ #include <netdb.h>
+ #include <netat/appletalk.h>
+ #include "../../lib/cap/abasp.h"	/* urk */
+ #include "afpdsi.h"
+ 
+ #ifdef HAVE_WRITEV
+ #include <sys/uio.h>
+ #endif /* HAVE_WRITEV */
+ 
+ /*
+  * aufs AFP routines
+  *
+  */
+ int dsiInit();
+ int dsiGetSession();
+ int dsiFork();
+ int dsiTickleUserRoutine();
+ int dsiGetRequest();
+ int dsiWrtContinue();
+ int dsiWrtReply();
+ int dsiCmdReply();
+ int dsiAttention();
+ int dsiGetNetworkInfo();
+ int dsiGetParms();
+ int dsiCloseSession();
+ int dsiShutdown();
+ int dsiTCPIPCloseSLS();
+ 
+ /*
+  * AppleTalk Session Protocol routines
+  * (including some formerly 'private')
+  *
+  */
+ int SPInit();
+ int SPGetSession();
+ int SPFork();
+ int SPTickleUserRoutine();
+ int SPGetRequest();
+ int SPWrtContinue();
+ int SPWrtReply();
+ int SPCmdReply();
+ int SPAttention();
+ int SPGetNetworkInfo();
+ int SPGetParms();
+ int SPCloseSession();
+ int SPShutdown();
+ 
+ ASPSSkt *aspsskt_find_slsrefnum();
+ ASPSkt *aspskt_find_sessrefnum();
+ ASPSkt *aspskt_find_active();
+ ASPQE *create_aq();
+ 
+ void stopasptickle();
+ void stop_ttimer();
+ void delete_aq();
+ void Timeout();
+ 
+ /*
+  * local TCP/IP routines
+  *
+  */
+ int dsiTCPIPInit();
+ int dsiTCPIPFork();
+ int dsiTCPIPGetRequest();
+ int dsiTCPWrtContinue();
+ int dsiTCPIPWrtReply();
+ int dsiTCPIPCmdReply();
+ int dsiTCPIPReply();
+ int dsiTCPIPTickleUserRoutine();
+ int dsiTCPIPCloseSession();
+ int dsiTCPIPAttention();
+ int dsiTCPIPGetNetworkInfo();
+ int dsiTCPIPWrite();
+ int dsiTCPIPCloseSLS();
+ 
+ /*
+  * globals
+  *
+  */
+ #ifdef DEBUG_AFP_CMD
+ extern FILE *dbg;
+ #endif /* DEBUG_AFP_CMD */
+ 
+ extern int errno;
+ extern int asip_enable;
+ extern char *dsiTCPIPFilter;
+ private struct dsi_sess *dsi_session = NULL;
+ 
+ /*
+  * DSI transport-layer demultiplexing
+  *
+  */
+ 
+ /*
+  * Set up a Server Listening Socket (SLS) for both
+  * ASP/ATP and TCP/IP.
+  *
+  * SLSEntityIdentifier - server AppleTalk address
+  * ServiceStatusBlock - pointer to ServerInfo data
+  * ServiceStatusBlockSize - ServerInfo data size
+  * SLSRefNum - return a session RefNum
+  *
+  */
+ 
+ int
+ dsiInit(SLSEntityIdentifier, ServiceStatusBlock,
+  ServiceStatusBlockSize, SLSRefNum)
+ AddrBlock *SLSEntityIdentifier; /* SLS Net id */
+ char *ServiceStatusBlock;       /* block with status info */
+ int ServiceStatusBlockSize;     /* size of status info */
+ int *SLSRefNum;                 /* sls ref num return place */
+ {
+   int result;
+   extern int numasp;
+ 
+   /*
+    * allocate & initialise space for DSI session data
+    *
+    */
+   if (numasp <= 0)
+     return(-1);
+ 
+   if ((dsi_session = (struct dsi_sess *)
+    malloc(sizeof(struct dsi_sess)*numasp)) == NULL)
+     return(-1);
+ 
+   bzero((char *)dsi_session, sizeof(struct dsi_sess)*numasp);
+ 
+   /*
+    * allocate SLSRefNum, initialise AppleTalk Session Protocol SLS
+    *
+    */
+   result = SPInit(SLSEntityIdentifier, ServiceStatusBlock,
+             ServiceStatusBlockSize, SLSRefNum);
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     fprintf(dbg, "** SPInit(): (PID %d)\n", getpid());
+     fprintf(dbg, "\tSLSRefNum: %d\n", *SLSRefNum);
+     fprintf(dbg, "\tServiceStatusBlockSize: %d\n", ServiceStatusBlockSize);
+     fprintf(dbg, "\tresult: %d\n", result);
+     fprintf(dbg, "\n\n");
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   if (result != noErr)
+     return(result);
+ 
+   /*
+    * if enabled, setup TCP/IP SLS (uses same SLSRefNum)
+    *
+    */
+   if (asip_enable)
+     if (dsiTCPIPInit(SLSEntityIdentifier, ServiceStatusBlock,
+      ServiceStatusBlockSize, SLSRefNum) != noErr)
+       asip_enable = 0;
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * set up to wait for a new session to start
+  *
+  * SLSRefNum - Session Listening Socket RefNum
+  * SessRefNum - returns new session reference number
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiGetSession(SLSRefNum, SessRefNum, comp)
+ int SLSRefNum;
+ int *SessRefNum;
+ int *comp;
+ {
+   int result;
+ 
+   /*
+    * get a session reference number,
+    *
+    */
+   result = SPGetSession(SLSRefNum, SessRefNum, comp);
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     fprintf(dbg, "** SPGetSession(): (PID %d)\n", getpid());
+     fprintf(dbg, "\tSLSRefNum: %d\n", SLSRefNum);
+     fprintf(dbg, "\tSessRefNum: %d\n", *SessRefNum);
+     fprintf(dbg, "\tcomp: %d\n", *comp);
+     fprintf(dbg, "\tresult: %d\n", result);
+     fprintf(dbg, "\n\n");
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   if (result != noErr)
+     return(result);
+ 
+   /*
+    * assume that this session is going to be
+    * AppleTalk, until we find out otherwise
+    * (this depends on what type of OpenSession
+    * packet actually arrives)
+    *
+    */
+   dsi_session[*SessRefNum].sesstype = DSI_SESSION_ATALK;
+ 
+   /*
+    * initialise data structure for DSI state
+    *
+    */
+   dsi_session[*SessRefNum].timeout = 0;
+   dsi_session[*SessRefNum].aspqe = NULL;
+   dsi_session[*SessRefNum].sess_id_in = 0;
+   dsi_session[*SessRefNum].sess_id_out = 0;
+   dsi_session[*SessRefNum].state = DSI_STATE_HDR;
+   dsi_session[*SessRefNum].lenleft = sizeof(struct dsi_hdr);
+   dsi_session[*SessRefNum].ptr = (char *)&dsi_session[*SessRefNum].hdr;
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * fork and create new process to handle session
+  *
+  * SessRefNum - session reference number
+  * stickle - want server tickle
+  * ctickle - want client tickle
+  *
+  */
+ 
+ int
+ dsiFork(SessRefNum, stickle, ctickle)
+ int SessRefNum;
+ int stickle;
+ int ctickle;
+ {
+   /*
+    * if AppleTalk, hand off to Session Protocol
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPFork(SessRefNum, stickle, ctickle));
+ 
+   /*
+    * handle locally for TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPFork(SessRefNum, stickle, ctickle));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * set the user-timeout routine and argument
+  *
+  * this needs to be handled in the parent
+  * process for AppleTalk connections and in
+  * the child process for TCP/IP connections
+  *
+  * 'pid' was obtained from the approriate fork()
+  *
+  */
+ 
+ int
+ dsiTickleUserRoutine(SessRefNum, routine, pid)
+ int SessRefNum;
+ int (*routine)();
+ int pid;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (pid)
+     if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+       return(SPTickleUserRoutine(SessRefNum, routine, pid));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (!pid)
+     if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+       return(dsiTCPIPTickleUserRoutine(SessRefNum, routine, getpid()));
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * set up to wait for a request on SSS
+  *
+  * SessRefNum - session reference number
+  * ReqBuff - request command buffer
+  * ReqBuffSize - request command buffer size
+  * ReqRefNum - pointer to a special command block
+  * SPReqType - returns command request type
+  * ActRcvdReqLen - returns command length
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiGetRequest(SessRefNum, ReqBuff, ReqBuffSize,
+  ReqRefNum, SPReqType, ActRcvdReqLen, comp)
+ int SessRefNum;
+ char *ReqBuff;
+ int ReqBuffSize;
+ ASPQE **ReqRefNum;
+ int *SPReqType;
+ int *ActRcvdReqLen;
+ int *comp;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPGetRequest(SessRefNum, ReqBuff, ReqBuffSize,
+      ReqRefNum, SPReqType, ActRcvdReqLen, comp));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPGetRequest(SessRefNum, ReqBuff, ReqBuffSize,
+      ReqRefNum, SPReqType, ActRcvdReqLen, comp));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * 'read' data sent by client
+  *
+  * SessRefNum - session reference number
+  * ReqRefNum - client connection details (addr, TID)
+  * Buffer - final location for data
+  * BufferSize - maximum amount of data we can handle
+  * ActLenRcvd - actual amount of date received
+  * atptimeout - ATP get data timeout
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiWrtContinue(SessRefNum, ReqRefNum, Buffer, BufferSize,
+  ActLenRcvd, atptimeout, comp)
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ char *Buffer;
+ int BufferSize;
+ int *ActLenRcvd;
+ int atptimeout;
+ int *comp;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPWrtContinue(SessRefNum, ReqRefNum, Buffer,
+      BufferSize, ActLenRcvd, atptimeout, comp));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPWrtContinue(SessRefNum, ReqRefNum, Buffer,
+      BufferSize, ActLenRcvd, atptimeout, comp));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * reply to a write request sent to our SSS
+  *
+  * SessRefNum - session reference number
+  * ReqRefNum - client connection details (addr, TID)
+  * CmdResult - return result
+  * CmdReplyData - return data
+  * CmdReplyDataSize - return data size
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiWrtReply(SessRefNum, ReqRefNum, CmdResult,
+  CmdReplyData, CmdReplyDataSize, comp)
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ dword CmdResult;
+ char *CmdReplyData;
+ int CmdReplyDataSize;
+ int *comp;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPWrtReply(SessRefNum, ReqRefNum, CmdResult,
+      CmdReplyData, CmdReplyDataSize, comp));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPWrtReply(SessRefNum, ReqRefNum, CmdResult,
+      CmdReplyData, CmdReplyDataSize, comp));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * Reply to a command request sent to our SSS
+  *
+  * SessRefNum - session reference number
+  * ReqRefNum - client connection details (addr, TID)
+  * CmdResult - return result
+  * CmdReplyData - return data
+  * CmdReplyDataSize - return data size
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiCmdReply(SessRefNum, ReqRefNum, CmdResult,
+  CmdReplyData, CmdReplyDataSize, comp)
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ dword CmdResult;
+ char *CmdReplyData;
+ int CmdReplyDataSize;
+ int *comp;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPCmdReply(SessRefNum, ReqRefNum, CmdResult,
+      CmdReplyData, CmdReplyDataSize, comp));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPCmdReply(SessRefNum, ReqRefNum, CmdResult,
+      CmdReplyData, CmdReplyDataSize, comp));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * send an Attention signal to WSS
+  *
+  * SessRefNum - session reference number
+  * AttentionCode - attention message
+  * atpretries - ATP Retries
+  * atptimeout - ATP Timeout
+  * comp - completion falg/error
+  *
+  */
+ 
+ int
+ dsiAttention(SessRefNum, AttentionCode, atpretries, atptimeout, comp)
+ int SessRefNum;
+ word AttentionCode;
+ int atpretries;
+ int *comp;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPAttention(SessRefNum, AttentionCode,
+      atpretries, atptimeout, comp));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPAttention(SessRefNum, AttentionCode,
+      atpretries, atptimeout, comp));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * return remote address of session client
+  *
+  */
+ 
+ int
+ dsiGetNetworkInfo(SessRefNum, addr)
+ int SessRefNum;
+ AddrBlock *addr;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPGetNetworkInfo(SessRefNum, addr));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPGetNetworkInfo(SessRefNum, addr));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * Get server operating parameters (these numbers are used
+  * to malloc() the appropriate amount of buffer space).
+  *
+  * MaxCmdSize - maximum single packet size
+  * QuantumSize - maximum outstanding data
+  *
+  * For ASP/ATP:
+  *	MaxCmdSize = atpMaxData (578)
+  *	QuantumSize = atpMaxData*atpMaxNum (578*8)
+  *
+  * For TCP/IP:
+  *	MaxCmdSize = AFP Command Size (1500)
+  *	QuantumSize = Data Chunk Size (65536)
+  *
+  */
+ 
+ int
+ dsiGetParms(MaxCmdSize, QuantumSize)
+ int *MaxCmdSize;
+ int *QuantumSize;
+ {
+   if (asip_enable) {
+     *MaxCmdSize = DSI_SRVR_CMD;
+     *QuantumSize = DSI_SRVR_MAX;
+     return(noErr);
+   }
+ 
+   return(SPGetParms(MaxCmdSize, QuantumSize));
+ }
+ 
+ /*
+  * Close down a SSS
+  *
+  * SessRefNum - Session reference number
+  * atpretries - ATP Retries
+  * atptimeout - ATP Timeout
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiCloseSession(SessRefNum, atpretries, atptimeout, comp)
+ int SessRefNum;
+ int atpretries;
+ int atptimeout;
+ int *comp;
+ {
+   /*
+    * AppleTalk
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_ATALK)
+     return(SPCloseSession(SessRefNum, atpretries, atptimeout, comp));
+ 
+   /*
+    * TCP/IP
+    *
+    */
+   if (dsi_session[SessRefNum].sesstype == DSI_SESSION_TCPIP)
+     return(dsiTCPIPCloseSession(SessRefNum, atpretries, atptimeout, comp));
+ 
+   return(ParamErr);
+ }
+ 
+ /*
+  * shutdown session
+  * 
+  * SessRefNum - session reference number
+  *
+  */
+ 
+ int
+ dsiShutdown(SessRefNum)
+ int SessRefNum;
+ {
+   /*
+    * clean up our session data
+    *
+    */
+   if (dsi_session[SessRefNum].aspqe != NULL)
+     delete_aspaqe(dsi_session[SessRefNum].aspqe);
+ 
+   dsi_session[SessRefNum].timeout = 0;
+   dsi_session[SessRefNum].aspqe = NULL;
+   dsi_session[SessRefNum].sess_id_in = 0;
+   dsi_session[SessRefNum].sess_id_out = 0;
+   dsi_session[SessRefNum].state = DSI_STATE_HDR;
+   dsi_session[SessRefNum].sesstype = DSI_SESSION_ATALK;
+   dsi_session[SessRefNum].lenleft = sizeof(struct dsi_hdr);
+   dsi_session[SessRefNum].ptr = (char *)&dsi_session[SessRefNum].hdr;
+ 
+   /*
+    * then clean up the ASP stuff
+    *
+    */
+   return(SPShutdown(SessRefNum));
+ }
+ 
+ #ifdef DEBUG_AFP_CMD
+ /*
+  * return descriptive command name string
+  *
+  */
+ char *
+ dsi_cmd(cmd)
+ int cmd;
+ {
+   switch (cmd) {
+     case DSIGetStatus:
+       return("DSIGetStatus");
+       break;
+     case DSIOpenSession:
+       return("DSIOpenSession");
+       break;
+     case DSICommand:
+       return("DSICommand");
+       break;
+     case DSIWrite:
+       return("DSIWrite");
+       break;
+     case DSIAttention:
+       return("DSIAttention");
+       break;
+     case DSITickle:
+       return("DSITickle");
+       break;
+     case DSICloseSession:
+       return("DSICloseSession");
+       break;
+   }
+   return("UNKNOWN");
+ }
+ #endif /* DEBUG_AFP_CMD */
+ 
+ /*
+  * TCP/IP related routines
+  *
+  */
+ 
+ /*
+  * open and initialise TCP/IP SLS port
+  *
+  *  "The interface will register the AFP server on a well-known
+  *   (static) data stream port. In case of TCP, it will be TCP
+  *   port number 548".
+  *
+  */
+ 
+ private int slsskt = -1;
+ private struct sockaddr_in lsin;
+ 
+ int
+ dsiTCPIPInit(SLSEntityIdentifier, ServiceStatusBlock,
+  ServiceStatusBlockSize, SLSRefNum)
+ AddrBlock *SLSEntityIdentifier; /* SLS Net id */
+ char *ServiceStatusBlock;       /* block with status info */
+ int ServiceStatusBlockSize;     /* size of status info */
+ int *SLSRefNum;                 /* sls ref num return place */
+ {
+   int aport, len;
+   extern u_int asip_addr;
+   extern u_short asip_port;
+   private int dsiTCPIPSLSListener();
+   struct protoent *t, *getprotobyname();
+ 
+   /*
+    * open a stream socket
+    *
+    */
+   if ((slsskt = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+     return(slsskt);
+ 
+   bzero((char *)&lsin, sizeof(lsin));
+ 
+   lsin.sin_family = AF_INET;
+   lsin.sin_port = htons(asip_port);
+   lsin.sin_addr.s_addr = htonl(asip_addr);
+ 
+   /*
+    * want to send data as it becomes available
+    *
+    */
+   len = 1;
+   t = getprotobyname("tcp");
+   aport = (t == NULL) ? IPPROTO_TCP : t->p_proto;
+   setsockopt(slsskt, aport, TCP_NODELAY, (char *)&len, sizeof(int));
+ 
+   /*
+    * bind to ipaddr:port selected by AUFS -B option
+    * (defaults to INADDR_ANY:548)
+    *
+    */
+   if (bind(slsskt, (struct sockaddr *)&lsin, sizeof(lsin)) != 0) {
+     close(slsskt);
+     return(-1);
+   }
+ 
+   /*
+    * start listening for connection attempts
+    *
+    */
+   if (listen(slsskt, 5) != 0) {
+     close(slsskt);
+     return(-1);
+   }
+ 
+   /*
+    * register a callback routine to handle SLS connection requests
+    *
+    */
+   fdlistener(slsskt, dsiTCPIPSLSListener, NULL, *SLSRefNum);
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * fdlistener() callback routine for TCP/IP connection attempts
+  *
+  * accept() the connection and register a data listener for
+  * incoming connection/getstatus packets.
+  *
+  */
+ 
+ private int
+ dsiTCPIPSLSListener(fd, none, SLSRefNum)
+ int fd;
+ caddr_t none;
+ int SLSRefNum;
+ {
+   int len, acc;
+   int illegal = 0;
+   struct sockaddr_in rsin;
+   extern u_short asip_port;
+   private int dsiTCPIPIllegalIP();
+   private int dsiTCPIPSSSListener();
+ 
+   len = sizeof(struct sockaddr_in);
+   if ((acc = accept(fd, (struct sockaddr *)&rsin, &len)) < 0)
+     return(acc);
+ 
+   /*
+    * check our IP address filter for
+    * a disallowed source IP address
+    *
+    */
+   if (!dsiTCPIPIllegalIP(&rsin))
+     fdlistener(acc, dsiTCPIPSSSListener, NULL, SLSRefNum);
+   else
+     close(acc), illegal = 1;
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     fprintf(dbg,
+      "** AppleShareIP connection attempt to port %d from %s:%d (PID %d)\n",
+      asip_port, inet_ntoa(rsin.sin_addr), ntohs(rsin.sin_port), getpid());
+     if (illegal)
+       fprintf(dbg, "** Rejected by IP address filter (%s)\n", dsiTCPIPFilter);
+     fprintf(dbg, "\n\n");
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * fdlistener() callback routine for incoming DSI requests
+  *
+  *  "An AFP server expects two command types, that is, DSIOpenSession
+  *   or DSIGetStatus after the data stream connection establishment.
+  *   DSIOpenSession command confirms the clients commitment to open an
+  *   actual DSI session. There is a 1-to-1 mapping between the data
+  *   stream connection and a DSI session. DSIGetSTatus command replies
+  *   the server status followed by the connection tear down by an AFP
+  *   server".
+  *
+  * This handler is interested only in DSIGetStatus or DSIOpenSession
+  * requests. Once the session is open, we unregister the fd with this
+  * handler and re-register it with the generic session handler.
+  *
+  */
+ 
+ private int
+ dsiTCPIPSSSListener(fd, none, SLSRefNum)
+ int fd;
+ caddr_t none;
+ int SLSRefNum;
+ {
+   int len;
+   int optlen;
+   ASPSkt *as;
+   ASPSSkt *sas;
+   int SessRefNum;
+   char reply_opt[8];
+   struct dsi_hdr hdr;
+   char *optptr, *reqst_opt;
+   private int dsiTCPIPSessListener();
+ 
+   /*
+    * hopefully there are at least sizeof(hdr) bytes available to read
+    * (of course, there may not be, but the extra trouble of keeping a
+    * per stream partial header for just DSIGetStatus and DSIOpenSession
+    * isn't really worth it).
+    *
+    */
+   if ((len = read(fd, (char *)&hdr, sizeof(hdr))) != sizeof(hdr)) {
+     fdunlisten(fd);
+     close(fd);
+     return(-1);
+   }
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     char *dsi_cmd();
+     fprintf(dbg, "<< AppleShareIP DSI header (PID %d, session startup):\n",
+      getpid());
+     fprintf(dbg, "\tFlags: %02x (%s)\n", hdr.dsi_flags,
+      (hdr.dsi_flags == DSI_REQ_FLAG) ? "Request" : "REPLY!!");
+     fprintf(dbg, "\tCommand: %02x (%s)\n", hdr.dsi_command,
+      dsi_cmd(hdr.dsi_command));
+     fprintf(dbg, "\tRequestID: %d\n", ntohs(hdr.dsi_requestID));
+     fprintf(dbg, "\tErrCode/DataOffset: %d\n", ntohl(hdr.dsi_err_offset));
+     fprintf(dbg, "\tDataLength: %d\n", ntohl(hdr.dsi_data_len));
+     fprintf(dbg, "\tReserved: %d\n\n\n", ntohl(hdr.dsi_reserved));
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   /*
+    * not interested in Replies
+    * (should be none)
+    *
+    */
+   if (hdr.dsi_flags != DSI_REQ_FLAG)
+     return(noErr);
+ 
+   /*
+    * process the request
+    *
+    */
+   switch (hdr.dsi_command) {
+     case DSIGetStatus:
+       /* dig out saved server status info for this SLS */
+       if ((sas = aspsskt_find_slsrefnum(SLSRefNum)) != NULL) {
+         hdr.dsi_flags = DSI_REP_FLAG;
+         hdr.dsi_err_offset = htonl(noErr);
+         hdr.dsi_data_len = htonl(sas->ssbl);
+         hdr.dsi_reserved = htonl(0x00000000);
+         /* send server status information */
+         dsiTCPIPWrite(fd, &hdr, (char *)sas->ssb, sas->ssbl);
+       }
+       /* fall through */
+     default: /* tear down connection */
+       fdunlisten(fd);
+       close(fd);
+       break;
+     case DSIOpenSession:
+       /* search for SLS next waiting session */
+       if ((as = aspskt_find_active(SLSRefNum)) == NULL) {
+         hdr.dsi_flags = DSI_REP_FLAG;
+         hdr.dsi_err_offset = htonl(ServerBusy);
+         hdr.dsi_data_len = htonl(0x00000000);
+         hdr.dsi_reserved = htonl(0x00000000);
+         dsiTCPIPWrite(fd, &hdr, NULL, 0);
+         fdunlisten(fd);
+         close(fd);
+         break;
+       }
+       /* check for incoming OpenSession options */
+       if ((optlen = ntohl(hdr.dsi_data_len)) > 0) {
+         if ((reqst_opt = (char *)malloc(optlen)) != NULL) {
+           optptr = reqst_opt;
+           while (optlen > 0) {
+             if ((len = read(fd, optptr, optlen)) < 0) {
+               fdunlisten(fd);
+               close(fd);
+               break;
+             }
+             optlen -= len;
+             optptr += len;
+           }
+           /*
+            * one day we might actually care
+            *
+            dsi_parse_option(optptr);
+            *
+            */
+           free(reqst_opt);
+         }
+       }
+       /* start session */
+       as->ss = fd;
+       as->state = SP_STARTED;
+       SessRefNum = as->SessRefNum;
+       /* mark this session as type TCP/IP */
+       dsi_session[SessRefNum].sesstype = DSI_SESSION_TCPIP;
+       /* set up state for this session */
+       dsi_session[SessRefNum].state = DSI_STATE_HDR;
+       dsi_session[SessRefNum].lenleft = sizeof(struct dsi_hdr);
+       dsi_session[SessRefNum].ptr = (char *)&dsi_session[SessRefNum].hdr;
+       dsi_session[SessRefNum].sess_id_in = ntohs(hdr.dsi_requestID)+1;
+       dsi_session[SessRefNum].sess_id_out = 0;
+       dsi_session[SessRefNum].aspqe = NULL;
+       dsi_session[SessRefNum].timeout = 0;
+       /* set OpenSession reply option */
+       optlen = DSI_OPT_REQLEN+2;
+       reply_opt[0] = DSI_OPT_REQQ;
+       reply_opt[1] = DSI_OPT_REQLEN;
+       reply_opt[2] = (DSI_SRVR_MAX >> 24) & 0xff;
+       reply_opt[3] = (DSI_SRVR_MAX >> 16) & 0xff;
+       reply_opt[4] = (DSI_SRVR_MAX >>  8) & 0xff;
+       reply_opt[5] = (DSI_SRVR_MAX) & 0xff;
+       /* setup response header */
+       hdr.dsi_flags = DSI_REP_FLAG;
+       hdr.dsi_err_offset = htonl(noErr);
+       hdr.dsi_data_len = htonl(optlen);
+       hdr.dsi_reserved = htonl(0x00000000);
+       /* send OpenSession Reply */
+       dsiTCPIPWrite(fd, &hdr, reply_opt, optlen);
+       /* move fd to session handler */
+       fdunlisten(fd);
+       fdlistener(fd, dsiTCPIPSessListener, (caddr_t)as, SessRefNum);
+       *as->comp = noErr;
+       return(noErr);
+       break;
+   }
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * data listener for opened sessions
+  *
+  * At any time the data listener can be in one of four states,
+  * waiting until the expected amount of data has arrived, or a
+  * reply has been sent, freeing the header for re-use:
+  *
+  *	DSI_STATE_HDR - reading the 16-byte DSI header
+  *	DSI_STATE_AFP - reading the AFP command data
+  *	DSI_STATE_DAT - reading the DSIWrite data
+  *	DSI_STATE_REP - waiting until reply is sent
+  *
+  */
+ 
+ private int
+ dsiTCPIPSessListener(fd, as, SessRefNum)
+ int fd;
+ ASPSkt *as;
+ int SessRefNum;
+ {
+   int len;
+   int comp;
+   char *ptr;
+   ASPQE *aspqe;
+   atpProto *ap;
+   struct dsi_hdr *hdr;
+ 
+   /*
+    * better have a waiting request
+    *
+    */
+   if ((aspqe = dsi_session[SessRefNum].aspqe) == NULL) {
+     logit(0, "Incoming TCP/IP data but no pending request");
+     dsiTCPIPCloseSession(SessRefNum, 0, 0, &comp);
+     return(-1);
+   }
+ 
+   /*
+    * ignore available data until reply is sent
+    * (reply uses the sessionID in DSI header) or
+    * dsiTCPIPWrtContinue() changes the state to
+    * DSI_STATE_DAT
+    *
+    */
+   if (dsi_session[SessRefNum].state == DSI_STATE_REP)
+     return(noErr);
+ 
+   /*
+    * read DSI header or data from the
+    * tcp/ip stream as it comes in
+    *
+    */
+   len = dsi_session[SessRefNum].lenleft;
+   ptr = dsi_session[SessRefNum].ptr;
+ 
+   if ((len = read(fd, ptr, len)) < 0) {
+     logit(0, "TCP/IP read() returned %d (errno %d)", len, errno);
+     dsiTCPIPCloseSession(SessRefNum, 0, 0, &comp);
+     *aspqe->comp = SessClosed;
+     return(len);
+   }
+ 
+   dsi_session[SessRefNum].lenleft -= len;
+   dsi_session[SessRefNum].ptr += len;
+ 
+   if (dsi_session[SessRefNum].lenleft > 0)
+     return(noErr);
+ 
+   /*
+    * sanity check
+    *
+    */
+   if (dsi_session[SessRefNum].lenleft < 0) {
+     logit(0, "mismatch in expected amount of read data");
+     dsiTCPIPCloseSession(SessRefNum, 0, 0, &comp);
+     *aspqe->comp = SessClosed;
+     return(-1);
+   }
+ 
+   hdr = &dsi_session[SessRefNum].hdr;
+ 
+   /*
+    * finished reading something, deal with it
+    *
+    */
+   switch (dsi_session[SessRefNum].state) {
+     case DSI_STATE_HDR:
+       /* now have a complete DSI hdr */
+       if (ntohl(hdr->dsi_data_len) > 0) {
+         /* and AFP hdr to follow */
+         ap = &aspqe->abr.proto.atp;
+         dsi_session[SessRefNum].ptr = ap->atpDataPtr;
+         if (hdr->dsi_command == DSIWrite && ntohl(hdr->dsi_err_offset) != 0)
+           dsi_session[SessRefNum].lenleft = ntohl(hdr->dsi_err_offset);
+         else
+           dsi_session[SessRefNum].lenleft = ntohl(hdr->dsi_data_len);
+         dsi_session[SessRefNum].state = DSI_STATE_AFP;
+         return(noErr);
+         break;
+       }
+       /* fall through */
+     case DSI_STATE_AFP:
+       /* have DSI hdr and optional AFP header */
+       dsi_session[SessRefNum].ptr = (char *)hdr;
+       dsi_session[SessRefNum].lenleft = sizeof(struct dsi_hdr);
+       if (hdr->dsi_flags == DSI_REQ_FLAG)
+         dsi_session[SessRefNum].state = DSI_STATE_REP;
+       else
+         dsi_session[SessRefNum].state = DSI_STATE_HDR;
+       break;
+     case DSI_STATE_DAT:
+       /* have all DSIWrite data, reset state, tell client */
+       dsi_session[SessRefNum].aspqe = NULL;
+       dsi_session[SessRefNum].ptr = (char *)hdr;
+       dsi_session[SessRefNum].lenleft = sizeof(struct dsi_hdr);
+       dsi_session[SessRefNum].state = DSI_STATE_REP;
+       *aspqe->ActRcvdReqLen = ntohl(hdr->dsi_data_len);
+       *aspqe->ActRcvdReqLen -= ntohl(hdr->dsi_err_offset);
+       *aspqe->comp = noErr;
+       delete_aspaqe(aspqe);
+       return(noErr);
+       break;
+     default:
+       /* huh ? */
+       break;
+   }
+ 
+   /*
+    * process DSI header and optional AFP data
+    *
+    */
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     char *dsi_cmd();
+     fprintf(dbg, "<< AppleShareIP DSI header (PID %d, session #%d):\n",
+      getpid(), SessRefNum);
+     fprintf(dbg, "\tFlags: %02x (%s)\n", hdr->dsi_flags,
+      (hdr->dsi_flags == DSI_REQ_FLAG) ? "Request" : "Reply");
+     fprintf(dbg, "\tCommand: %02x (%s)\n", hdr->dsi_command,
+      dsi_cmd(hdr->dsi_command));
+     fprintf(dbg, "\tRequestID: %d\n", ntohs(hdr->dsi_requestID));
+     fprintf(dbg, "\tErrCode/DataOffset: %d\n", ntohl(hdr->dsi_err_offset));
+     fprintf(dbg, "\tDataLength: %d\n", ntohl(hdr->dsi_data_len));
+     fprintf(dbg, "\tReserved: %d\n\n\n", ntohl(hdr->dsi_reserved));
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   /*
+    * reset tickle timer
+    *
+    */
+   dsi_session[SessRefNum].timeout = 0;
+ 
+   /*
+    * ignore packet replies, rely on TCP to
+    * deliver in-order, that's what it's for.
+    *
+    */
+   if (hdr->dsi_flags == DSI_REP_FLAG)
+     return(noErr);
+ 
+   /*
+    * must be request, check if incoming
+    * session ID is what we are expecting
+    *
+    */
+   if (ntohs(hdr->dsi_requestID) != dsi_session[SessRefNum].sess_id_in) {
+     logit(0, "unexpected incoming TCP/IP session ID");
+     *aspqe->comp = ParamErr;
+     return(-1);
+   }
+   dsi_session[SessRefNum].sess_id_in++;
+ 
+   /*
+    * only 3 valid commands to pass on to client
+    * handle DSITickle locally, 'cause it's simple
+    *
+    */
+   switch (hdr->dsi_command) {
+     case DSICommand:
+     case DSIWrite:
+      *aspqe->comp = noErr;
+       break;
+     case DSICloseSession:
+      *aspqe->comp = SessClosed;
+       break;
+     case DSITickle:
+       hdr->dsi_flags = DSI_REP_FLAG;
+       dsiTCPIPWrite(fd, hdr, NULL, 0);
+       dsi_session[SessRefNum].state = DSI_STATE_HDR;
+       return(noErr);
+       break;
+     default:
+       logit(0, "unexpected incoming DSI cond (%d)", hdr->dsi_command);
+       *aspqe->comp = ParamErr;
+       break;
+   }
+ 
+   /*
+    * tell the client how much data
+    * came in and the command type
+    *
+    */
+   if (hdr->dsi_command == DSIWrite && ntohl(hdr->dsi_err_offset) != 0)
+     *aspqe->ActRcvdReqLen = ntohl(hdr->dsi_err_offset);
+   else
+     *aspqe->ActRcvdReqLen = ntohl(hdr->dsi_data_len);
+   *aspqe->SPReqType = hdr->dsi_command;
+   *aspqe->ReqRefNum = aspqe;
+ 
+   /*
+    * free previous GetRequest aspqe
+    *
+    */
+   delete_aspaqe(aspqe);
+   dsi_session[SessRefNum].aspqe = NULL;
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * fork and create new process to handle TCP/IP session
+  *
+  * SessRefNum - session reference number
+  * stickle - want server tickle
+  * ctickle - want client tickle
+  *
+  * In the server code (parent) close all but SLS
+  * In the child code forget about SLS, just listen
+  * for SSS requests
+  *
+  */
+ 
+ int
+ dsiTCPIPFork(SessRefNum, stickle, ctickle)
+ int SessRefNum;
+ int stickle;
+ int ctickle;
+ {
+   int i, pid;
+   ASPSSkt *sas;
+   extern int sqs;
+   ASPSkt *as, *bs;
+   extern int numasp;
+   private void dsiTCPIPTimer();
+ 
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL)
+     return(-1);
+ 
+   if (as->state != SP_STARTED)
+     return(-1);
+ 
+   /*
+    * make a new process
+    *
+    */
+   if ((pid = fork()) < 0)
+     return(pid);
+ 
+   /*
+    * if in parent process:
+    *   close SSS
+    *
+    * if in child process:
+    *   close both SLS (AppleTalk and TCP/IP)
+    *   start tickle timer for our client session
+    *   stop tickle timers for sibling ATALK sessions
+    *
+    */
+   if (pid) {
+     /* close SSS */
+     if (as->ss != -1) {
+       fdunlisten(as->ss);
+       close(as->ss);
+       as->ss = -1;
+     }
+     as->state = SP_HALFCLOSED;
+   } else { /* in child */
+     if (as->type != SP_SERVER)
+       return(noErr);
+     /* close TCP/IP SLS */
+     dsiTCPIPCloseSLS();
+     /* kill sibling AT timeouts */
+     for (i = 0; i < numasp; i++) {
+       if (i != SessRefNum) {
+         if ((bs = aspskt_find_sessrefnum(i)) != NULL) {
+           if (bs->tickling)
+             stopasptickle(bs);
+           stop_ttimer(bs);
+         }
+       }
+     }
+     /* close AppleTalk SLS */
+     if ((sas = aspsskt_find_slsrefnum(as->SLSRefNum)) != NULL)
+       ATPCloseSocket(sas->addr.skt);
+     /* set a new read quantum */
+     sqs = DSI_SRVR_MAX;
+     /* start our tickle timer */
+     Timeout(dsiTCPIPTimer, numasp, DSI_TIMEOUT);
+   }
+ 
+   return(pid);
+ }
+ 
+ /*
+  * set up to wait for a request on TCP/IP SSS
+  *
+  * SessRefNum - session reference number
+  * ReqBuff - request command buffer
+  * ReqBuffSize - request command buffer size
+  * ReqRefNum - pointer to a special command block
+  * SPReqType - returns command request type
+  * ActRcvdReqLen - returns command length
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiTCPIPGetRequest(SessRefNum, ReqBuff, ReqBuffSize,
+  ReqRefNum, SPReqType, ActRcvdReqLen, comp)
+ int SessRefNum;
+ char *ReqBuff;
+ int ReqBuffSize;
+ ASPQE **ReqRefNum;
+ int *SPReqType;
+ int *ActRcvdReqLen;
+ int *comp;
+ {
+   ASPSkt *as;
+   atpProto *ap;
+   ASPQE *aspqe;
+ 
+   /*
+    * check state of connection
+    * and validity of descriptor
+    *
+    */
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if (as->state != SP_STARTED) {
+     *comp = SessClosed;
+     return(SessClosed);
+   }
+   if (as->ss == -1) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   /*
+    * subsequent GetRequests from TREL_TIMEOUT code
+    * on this SessRefNum will never get a callback
+    * (because we don't need them for TCP/IP use)
+    *
+    */
+   if (dsi_session[SessRefNum].aspqe != NULL) {
+     *comp = 1;
+     return(noErr);
+   }
+ 
+   /*
+    * save GetRequest args for data arrival
+    *
+    */
+   aspqe = create_aspaqe();
+ 
+   aspqe->type = tSPGetRequest;
+   aspqe->SessRefNum = SessRefNum;
+   aspqe->ReqRefNum = ReqRefNum;
+   aspqe->SPReqType = SPReqType;
+   aspqe->ActRcvdReqLen = ActRcvdReqLen;
+   aspqe->comp = comp;
+ 
+   ap = &aspqe->abr.proto.atp;
+   ap->atpReqCount = ReqBuffSize;
+   ap->atpDataPtr = ReqBuff;
+ 
+   dsi_session[SessRefNum].aspqe = aspqe;
+ 
+   *comp = 1;
+   return(noErr);
+ }
+ 
+ /*
+  * arrange to put the 'read' data into Buffer
+  *
+  * SessRefNum - session reference number
+  * ReqRefNum - client connection details (addr, TID)
+  * Buffer - final location for data
+  * BufferSize - maximum amount of data we can handle
+  * ActLenRcvd - actual amount of date received
+  * atptimeout - ATP get data timeout
+  * comp - completion flag/error
+  *
+  */
+ 
+ dsiTCPIPWrtContinue(SessRefNum, ReqRefNum, Buffer,
+  BufferSize, ActLenRcvd, atptimeout, comp)
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ char *Buffer;
+ int BufferSize;
+ int *ActLenRcvd;
+ int atptimeout;
+ int *comp;
+ {
+   ASPSkt *as;
+   ASPQE *aspqe;
+   struct dsi_hdr *hdr;
+ 
+   /*
+    * sanity checks
+    *
+    */
+   if (BufferSize < 0) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if (as->state != SP_STARTED) {
+     *comp = SessClosed;
+     return(SessClosed);
+   }
+   if (as->ss == -1) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   /*
+    * save WrtContinue args for
+    * completion of data arrival
+    *
+    */
+   aspqe = create_aspaqe();
+ 
+   aspqe->type = tSPWrtContinue;
+   aspqe->SessRefNum = SessRefNum;
+   aspqe->ActRcvdReqLen = ActLenRcvd;
+   aspqe->comp = comp;
+ 
+   /*
+    * reset state & continue data reads
+    *
+    */
+   hdr = &dsi_session[SessRefNum].hdr;
+   dsi_session[SessRefNum].aspqe = aspqe;
+   dsi_session[SessRefNum].state = DSI_STATE_DAT;
+   dsi_session[SessRefNum].lenleft = ntohl(hdr->dsi_data_len);
+   dsi_session[SessRefNum].lenleft -= ntohl(hdr->dsi_err_offset);
+   dsi_session[SessRefNum].ptr = Buffer;
+ 
+   *comp = 1;
+   return(noErr);
+ }
+ 
+ /*
+  * reply to a write request sent to our TCP/IP SSS
+  *
+  * SessRefNum - session reference number
+  * ReqRefNum - client connection details (addr, TID)
+  * CmdResult - return result
+  * CmdReplyData - return data
+  * CmdReplyDataSize - return data size
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiTCPIPWrtReply(SessRefNum, ReqRefNum, CmdResult,
+  CmdReplyData, CmdReplyDataSize, comp)
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ dword CmdResult;
+ char *CmdReplyData;
+ int CmdReplyDataSize;
+ int *comp;
+ {
+   return(dsiTCPIPReply(DSIWrite, SessRefNum, ReqRefNum,
+    CmdResult, CmdReplyData, CmdReplyDataSize, comp));
+ }
+ 
+ /*
+  * Reply to a command request sent to our TCP/IP SSS
+  *
+  * SessRefNum - session reference number
+  * ReqRefNum - client connection details (addr, TID)
+  * CmdResult - return result
+  * CmdReplyData - return data
+  * CmdReplyDataSize - return data size
+  * comp - completion flag/error
+  *
+  */
+ 
+ int
+ dsiTCPIPCmdReply(SessRefNum, ReqRefNum, CmdResult,
+  CmdReplyData, CmdReplyDataSize, comp)
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ dword CmdResult;
+ char *CmdReplyData;
+ int CmdReplyDataSize;
+ int *comp;
+ {
+   return(dsiTCPIPReply(DSICommand, SessRefNum, ReqRefNum,
+    CmdResult, CmdReplyData, CmdReplyDataSize, comp));
+ }
+ 
+ /*
+  * common reply code
+  *
+  */
+ 
+ int
+ dsiTCPIPReply(dsiType, SessRefNum, ReqRefNum, CmdResult,
+  CmdReplyData, CmdReplyDataSize, comp)
+ int dsiType;
+ int SessRefNum;
+ ASPQE *ReqRefNum;
+ dword CmdResult;
+ char *CmdReplyData;
+ int CmdReplyDataSize;
+ int *comp;
+ {
+   ASPSkt *as;
+   struct dsi_hdr hdr;
+ 
+   /*
+    * some sanity checking
+    *
+    */
+   if (CmdReplyDataSize < 0) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if (CmdReplyDataSize > DSI_SRVR_MAX) {
+     *comp = SizeErr;
+     return(SizeErr);
+   }
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if (as->state != SP_STARTED) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if (as->ss == -1) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   /*
+    * setup DSI response header
+    * (the requestID is already
+    * in network byte order)
+    *
+    */
+   hdr.dsi_flags = DSI_REP_FLAG;
+   hdr.dsi_command = dsiType;
+   hdr.dsi_requestID = dsi_session[SessRefNum].hdr.dsi_requestID;
+   hdr.dsi_err_offset = htonl(CmdResult);
+   hdr.dsi_data_len = htonl(CmdReplyDataSize);
+   hdr.dsi_reserved = htonl(0x00000000);
+ 
+   /*
+    * session hdr can be re-used now
+    *
+    */
+   dsi_session[SessRefNum].state = DSI_STATE_HDR;
+ 
+   /*
+    * send it ...
+    *
+    */
+   if (dsiTCPIPWrite(as->ss, &hdr, CmdReplyData, CmdReplyDataSize) < 0) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   *comp = noErr;
+   return(noErr);
+ }
+ 
+ /*
+  * setup tickle timeout callback
+  *
+  */
+ 
+ int
+ dsiTCPIPTickleUserRoutine(SessRefNum, routine, arg)
+ int SessRefNum;
+ int (*routine)();
+ int arg;
+ {
+   ASPSkt *as;
+ 
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL)
+     return(ParamErr);
+ 
+   as->tickle_timeout_user = routine;
+   as->ttu_arg = arg;
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * Close down a TCP/IP Service Socket socket
+  *
+  * SessRefNum - Session reference number
+  * atpretries - ATP Retries
+  * atptimeout - ATP Timeout
+  * comp - completion flag/error
+  *
+  */
+ 
+ private struct dsi_hdr shut_hdr;
+ 
+ int
+ dsiTCPIPCloseSession(SessRefNum, atpretries, atptimeout, comp)
+ int SessRefNum;
+ int atpretries;
+ int atptimeout;
+ int *comp;
+ {
+   ASPSkt *as;
+ 
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   switch (as->state) {
+     case SP_STARTED:
+       break;
+     case SP_HALFCLOSED:
+       break;
+     default:
+       as->active = FALSE;	/* aspskt_free(as); */
+       return(noErr);
+       break;
+   }
+ 
+   /*
+    * set up the DSI header
+    *
+    */
+   shut_hdr.dsi_flags = DSI_REQ_FLAG;
+   shut_hdr.dsi_command = DSICloseSession;
+   shut_hdr.dsi_requestID = htons(dsi_session[SessRefNum].sess_id_out++);
+   shut_hdr.dsi_err_offset = htonl(0x00000000);
+   shut_hdr.dsi_data_len = htonl(0x00000000);
+   shut_hdr.dsi_reserved = htonl(0x00000000);
+ 
+   /*
+    * and send it ...
+    *
+    */
+   if (dsiTCPIPWrite(as->ss, &shut_hdr, NULL, 0) < 0) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   as->state = SP_INACTIVE;
+   as->active = FALSE;		/* aspskt_free(as); */
+ 
+   if (as->ss != -1) {
+     fdunlisten(as->ss);
+     close(as->ss);
+     as->ss = -1;
+   }
+ 
+   *comp = noErr;
+   return(noErr);
+ }
+ 
+ /*
+  * send a TCP/IP Attention signal to WSS
+  *
+  * SessRefNum - session reference number
+  * AttentionCode - attention message
+  * atpretries - ATP Retries
+  * atptimeout - ATP Timeout
+  * comp - completion falg/error
+  *
+  */
+ 
+ private struct dsi_hdr attn_hdr;
+ 
+ int
+ dsiTCPIPAttention(SessRefNum, AttentionCode, atpretries, atptimeout, comp)
+ int SessRefNum;
+ word AttentionCode;
+ int atpretries;
+ int *comp;
+ {
+   ASPSkt *as;
+   char attn[2];
+ 
+   /*
+    * some sanity checking
+    *
+    */
+   if (AttentionCode == 0x00) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+   if (as->state == SP_STARTING) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   /*
+    * set up the DSI attention header,
+    *
+    */
+   attn_hdr.dsi_flags = DSI_REQ_FLAG;
+   attn_hdr.dsi_command = DSIAttention;
+   attn_hdr.dsi_requestID = htons(dsi_session[SessRefNum].sess_id_out++);
+   attn_hdr.dsi_err_offset = htonl(0x00000000);
+   attn_hdr.dsi_data_len = htonl(sizeof(attn));
+   attn_hdr.dsi_reserved = htonl(0x00000000);
+ 
+   /*
+    * the attention field
+    *
+    */
+   attn[0] = AttentionCode >> 8;
+   attn[1] = AttentionCode & 0xff;
+ 
+   /*
+    * and send it ...
+    *
+    */
+   if (dsiTCPIPWrite(as->ss, &attn_hdr, attn, sizeof(attn)) < 0) {
+     *comp = ParamErr;
+     return(ParamErr);
+   }
+ 
+   *comp = noErr;
+   return(noErr);
+ }
+ 
+ /*
+  * return peer name of session client
+  *
+  * (NB: function return value is positive TCP/IP port number,
+  * to distinguish this from a real AppleTalk GetNetworkInfo
+  * call which returns noErr. The IP address is returned in
+  * the four bytes of the AddrBlock)
+  *
+  */
+ 
+ int
+ dsiTCPIPGetNetworkInfo(SessRefNum, addr)
+ int SessRefNum;
+ AddrBlock *addr;
+ {
+   ASPSkt *as;
+   struct sockaddr_in name;
+   int len = sizeof(struct sockaddr);
+ 
+   if ((as = aspskt_find_sessrefnum(SessRefNum)) == NULL)
+     return(ParamErr);
+ 
+   if (as->ss == -1)
+     return(ParamErr);
+ 
+   if (getpeername(as->ss, (struct sockaddr *)&name, &len) != 0)
+     return(ParamErr);
+ 
+   if (name.sin_family != AF_INET)
+     return(ParamErr);
+ 
+   name.sin_addr.s_addr = ntohl(name.sin_addr.s_addr);
+   addr->net  = ((name.sin_addr.s_addr & 0xff000000) >> 16);
+   addr->net |= ((name.sin_addr.s_addr & 0x00ff0000) >> 16);
+   addr->node = ((name.sin_addr.s_addr & 0x0000ff00) >> 8);
+   addr->skt  =  (name.sin_addr.s_addr & 0x000000ff);
+ 
+   return(ntohs(name.sin_port));
+ }
+  
+ /*
+  * write data to client via TCP/IP stream
+  *
+  * We deliberately don't use non-blocking I/O
+  * because the majority of the large data transfers
+  * happen in a process dedicated to a single client.
+  *
+  */
+ 
+ int
+ dsiTCPIPWrite(fd, hdr, data, len)
+ int fd;
+ struct dsi_hdr *hdr;
+ char *data;
+ int len;
+ {
+   int cc, cd;
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     char *dsi_cmd();
+     fprintf(dbg, ">> AppleShareIP DSI header (PID %d)\n", getpid());
+     fprintf(dbg, "\tFlags: %02x (%s)\n", hdr->dsi_flags,
+      (hdr->dsi_flags == DSI_REQ_FLAG) ? "Request" : "Reply");
+     fprintf(dbg, "\tCommand: %02x (%s)\n", hdr->dsi_command,
+      dsi_cmd(hdr->dsi_command));
+     fprintf(dbg, "\tRequestID: %d\n", ntohs(hdr->dsi_requestID));
+     fprintf(dbg, "\tErrCode/DataOffset: %d\n", ntohl(hdr->dsi_err_offset));
+     fprintf(dbg, "\tDataLength: %d\n", ntohl(hdr->dsi_data_len));
+     fprintf(dbg, "\tReserved: %d\n", ntohl(hdr->dsi_reserved));
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   /*
+    * writev() is more efficient but
+    * is less portable than write()
+    *
+    */
+ #ifdef HAVE_WRITEV
+   { struct iovec iov[2];
+     iov[0].iov_base = (caddr_t)hdr;
+     iov[0].iov_len = sizeof(struct dsi_hdr);
+     iov[1].iov_base = (caddr_t)data;
+     iov[1].iov_len = len;
+     cc = writev(fd, iov, (data == NULL) ? 1 : 2);
+   }
+ #else  /* HAVE_WRITEV */
+   if ((cc = write(fd, (char *)hdr, sizeof(struct dsi_hdr))) >= 0) {
+     if (data != NULL) {
+       if ((cd = write(fd, data, len)) >= 0)
+         cc += cd;
+       else
+         cc = cd;
+     }
+   }
+ #endif /* HAVE_WRITEV */
+ 
+ #ifdef DEBUG_AFP_CMD
+   if (dbg != NULL) {
+     extern int errno;
+     if (cc < 0)
+       fprintf(dbg, "** dsiTCPIPWrite(): %d bytes returns %d (errno %d)",
+        len+sizeof(struct dsi_hdr), cc, errno);
+     fprintf(dbg, "\n\n\n");
+     fflush(dbg);
+   }
+ #endif /* DEBUG_AFP_CMD */
+ 
+   return(cc);
+ }
+ 
+ /*
+  * Tickle Timeout timer
+  *
+  */
+ 
+ private void
+ dsiTCPIPTimer(numsess)
+ int numsess;
+ {
+   int i;
+   ASPSkt *as;
+   static int inited = 0;
+   static struct dsi_hdr tick_hdr;
+   void Timeout();
+ 
+   /*
+    * set-up the invariant
+    * fields of the tickle hdr
+    *
+    */
+   if (!inited) {
+     tick_hdr.dsi_flags = DSI_REQ_FLAG;
+     tick_hdr.dsi_command = DSITickle;
+     tick_hdr.dsi_err_offset = htonl(0x00000000);
+     tick_hdr.dsi_data_len = htonl(0x00000000);
+     tick_hdr.dsi_reserved = htonl(0x00000000);
+     inited = 1;
+   }
+ 
+   /*
+    * check for idle TCP/IP sessions
+    *
+    */
+   for (i = 0; i < numsess; i++) {
+     if (dsi_session[i].sesstype == DSI_SESSION_TCPIP) {
+       dsi_session[i].timeout += DSI_TIMEOUT;
+       if (dsi_session[i].timeout >= ASPCONNECTIONTIMEOUT) {
+         if ((as = aspskt_find_sessrefnum(i)) != NULL) {
+           if (as->tickle_timeout_user != NULL)
+             (*as->tickle_timeout_user)(i, as->ttu_arg);
+           else { /* no user routine */
+             as->state = SP_INACTIVE;
+             as->active = FALSE;		/* aspskt_free(as); */
+             dsiShutdown(i);
+           }
+         }
+       } else { /* not timed out, but time to send a tickle ? */
+         if ((dsi_session[i].timeout % (ASPTICKLETIMEOUT)) == 0) {
+           if ((as = aspskt_find_sessrefnum(i)) != NULL) {
+             tick_hdr.dsi_requestID = htons(dsi_session[i].sess_id_out++);
+             dsiTCPIPWrite(as->ss, &tick_hdr, NULL, 0);
+           }
+         }
+       }
+     }
+   }
+ 
+   Timeout(dsiTCPIPTimer, numsess, DSI_TIMEOUT);
+ 
+   return;
+ }
+ 
+ /*
+  * close the SLS (called from either the
+  * AppleTalk or TCP/IP child processes)
+  *
+  */
+ 
+ int
+ dsiTCPIPCloseSLS()
+ {
+   if (slsskt != -1) {
+     fdunlisten(slsskt);
+     close(slsskt);
+     slsskt = -1;
+   }
+ 
+   return(noErr);
+ }
+ 
+ /*
+  * IP address filter
+  *
+  * compatible with, and stolen from,
+  * the ARNS remote access package
+  *
+  * http://www.cs.mu.OZ.AU/appletalk/atalk.html
+  *
+  */
+ 
+ private int ipFilters = 0;
+ private struct ipFilter *ipFilter = NULL;
+ 
+ /*
+  * read the specified IP address filter file
+  *
+  */
+ 
+ private void
+ dsiTCPIPBuildFilterList()
+ {
+   FILE *fp;
+   char line[160];
+   char *mask, *addr;
+   unsigned long inet_addr();
+ 
+   ipFilters = 0;
+ 
+   if (dsiTCPIPFilter != NULL) {
+     if (ipFilter == NULL)
+       if ((ipFilter =
+        (struct ipFilter *)malloc(MAXIPFILTSIZ*MAXIPFILTERS)) == NULL)
+         return;
+     if ((fp = fopen(dsiTCPIPFilter, "r")) != NULL) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
+         if (line[0] == '#')
+           continue;
+         if ((mask = (char *)index(line, '\n')) != NULL)
+           *mask = '\0';
+         mask = line+1;
+         while (*mask != '\0' && isspace(*mask))
+           mask++; /* skip spaces */
+         addr = mask;
+         while (*addr != '\0' && !isspace(*addr))
+           addr++; /* skip mask */
+         while (*addr != '\0' && isspace(*addr))
+           addr++; /* skip spaces */
+         if (line[0] == '+' || line[0] == '*' || line[0] == '-') {
+           ipFilter[ipFilters].perm = line[0];
+           ipFilter[ipFilters].addr = (*addr == '\0') ? 0L : inet_addr(addr);
+           ipFilter[ipFilters].mask = (*mask == '\0') ? 0L : inet_addr(mask);
+           if (++ipFilters >= MAXIPFILTERS)
+             break;
+         }
+       }
+       (void)fclose(fp);
+     }
+   }
+ 
+   return;
+ }
+ 
+ /*
+  * check the IP address filter, if any
+  *
+  */
+ 
+ private int
+ dsiTCPIPIllegalIP(from)
+ struct sockaddr_in *from;
+ {
+   int i;
+   u_long addr;
+ 
+   dsiTCPIPBuildFilterList();
+ 
+   if (ipFilters == 0
+    || ipFilter == NULL)
+     return(0);
+ 
+   addr = from->sin_addr.s_addr;
+ 
+   for (i = 0 ; i < ipFilters ; i++) {
+     if (ipFilter[i].addr != 0L) {
+       if ((addr & ipFilter[i].mask) == ipFilter[i].addr)
+         return(ipFilter[i].perm == '-');
+     } else {
+       if ((addr & ipFilter[i].mask) == addr)
+         return(ipFilter[i].perm == '-');
+     }
+   }
+ 
+   return(0);
+ }
*** applications/aufs/afpdt.c.orig	Wed Sep 25 00:10:20 1996
--- applications/aufs/afpdt.c		Mon Jul  7 17:01:14 1997
***************
*** 1170,1176 ****
      PrintIconInfo(adi.adi_fcreator,adi.adi_ftype);
    }
  
!   err = SPWrtContinue(cno,reqref,icon,adi.adi_iconsize,&rcvlen,-1,&comp);
    if (err != noErr) {
      free((char *)icon);
      return(err);
--- 1170,1176 ----
      PrintIconInfo(adi.adi_fcreator,adi.adi_ftype);
    }
  
!   err = dsiWrtContinue(cno,reqref,icon,adi.adi_iconsize,&rcvlen,-1,&comp);
    if (err != noErr) {
      free((char *)icon);
      return(err);
*** applications/aufs/afpfork.c.orig	Wed Sep 25 00:09:33 1996
--- applications/aufs/afpfork.c		Mon Jul  7 17:43:35 1997
***************
*** 585,591 ****
        return(aeAccessDenied);
    }
  
!   err = SPWrtContinue(cno,reqref,r,n_rrpkts*atpMaxData,&rcvlen,-1,&comp);
    if (err != noErr)
      return(err);
    do { abSleep(4,TRUE); } while (comp > 0);    
--- 585,591 ----
        return(aeAccessDenied);
    }
  
!   err = dsiWrtContinue(cno,reqref,r,n_rrpkts*atpMaxData,&rcvlen,-1,&comp);
    if (err != noErr)
      return(err);
    do { abSleep(4,TRUE); } while (comp > 0);    
*** applications/aufs/afpos.c.orig	Wed Sep 25 00:10:24 1996
--- applications/aufs/afpos.c		Wed Jul  9 11:39:02 1997
***************
*** 766,772 ****
--- 766,776 ----
  	  msg[i] = '\r';
      }
      close(fd);
+     return(noErr);
    }
+ 
+   sprintf(msg, "<no path to message file>");
+ 
    return(noErr);
  }
  
*** applications/aufs/afps.h.orig	Wed Sep 25 00:10:19 1996
--- applications/aufs/afps.h		Mon Mar  3 22:14:05 1997
***************
*** 247,252 ****
--- 247,253 ----
  #define AFPVersion1DOT1 110
  #define AFPVersion2DOT0 200
  #define AFPVersion2DOT1 210
+ #define AFPVersion2DOT2 220
  
  #ifdef APPLICATION_MANAGER
  struct flist {
*** applications/aufs/afpserver.c.orig	Wed Sep 25 00:10:23 1996
--- applications/aufs/afpserver.c	Wed Jul  9 10:44:28 1997
***************
*** 47,52 ****
--- 47,54 ----
   /* assume included by param.h */
  # include <sys/types.h>
  #endif
+ #include <sys/socket.h>
+ #include <netdb.h>
  #include <sys/time.h>
  #include <sys/resource.h>
  #include <netat/appletalk.h>
***************
*** 97,103 ****
  
  private char *afpmtyp = "Unix";
  
! #define AFPVERSZ (5*16)			/* room for IndStr hold all versions */
  /* define 1 more than needed just in case */
  struct afpversionstruct {
    char *version_name;
--- 99,105 ----
  
  private char *afpmtyp = "Unix";
  
! #define AFPVERSZ (6*16)			/* room for IndStr hold all versions */
  /* define 1 more than needed just in case */
  struct afpversionstruct {
    char *version_name;
***************
*** 107,112 ****
--- 109,115 ----
    {"AFPVersion 1.1", AFPVersion1DOT1},
    {"AFPVersion 2.0", AFPVersion2DOT0},
    {"AFPVersion 2.1", AFPVersion2DOT1},
+   {"AFP2.2", AFPVersion2DOT2},
    {NULL, AFPVersionUnknown}
  };
  
***************
*** 216,221 ****
--- 219,229 ----
  
  private DumpBuf(), clockstart(), clockend();
  
+ private struct sig {
+   byte filler[8];
+   struct timeval s_time;
+ } sig;
+ 
  #ifdef LOGIN_AUTH_PROG
  extern char *srvrname;		/* NBP registered name of server */
  extern char *login_auth_prog;	/* name of authorization program */
***************
*** 254,259 ****
--- 262,271 ----
  #ifdef STAT_CACHE
    OSStatInit();			/* init stat cache */
  #endif STAT_CACHE
+ 
+   /* init server signature */
+   bzero((char *)&sig, sizeof(struct sig));
+   gettimeofday(&sig.s_time, NULL);
  }
  
  /*
***************
*** 968,974 ****
      fprintf(dbg, "\tMsgTyp: %04x\t", smrp.msgr_typ);
      fprintf(dbg, "(%s)\n", (smrp.msgr_typ == 0) ? "Login" : "Server");
      fprintf(dbg, "\tMsgBMp: %04x\n", smrp.msgr_bitmap);
!     dbg_print_name("\tMsgStr:", smrp.msgr_data);
      fflush(dbg);
    }
  #endif /* DEBUG_AFP_CMD */
--- 980,986 ----
      fprintf(dbg, "\tMsgTyp: %04x\t", smrp.msgr_typ);
      fprintf(dbg, "(%s)\n", (smrp.msgr_typ == 0) ? "Login" : "Server");
      fprintf(dbg, "\tMsgBMp: %04x\n", smrp.msgr_bitmap);
!     fprintf(dbg, "\tMsgStr: %s\n", smrp.msgr_data);
      fflush(dbg);
    }
  #endif /* DEBUG_AFP_CMD */
***************
*** 1035,1040 ****
--- 1047,1055 ----
  }
  #endif
  
+ #define MAXNADSIZ	8		/* tag #2, IP addr & port */
+ #define NUMNAD		5		/* no more than 5 IP addr/host */
+ 
  int 
  GetSrvrInfo(r,sname,icon,iconsize)
  byte *r;
***************
*** 1042,1068 ****
  byte icon[];
  int iconsize;
  {
    int i,len;
    extern int nopwdsave;
    GetSrvrInfoReplyPkt sr;
    byte avobuf[AFPVERSZ],uamobuf[AFPUAMSZ];
!   OPTRType avo,uamo,vicono;
  
!   strcpy(sr.sr_machtype,afpmtyp);
!   cpyc2pstr(sr.sr_servername,sname);
!   /* set server capabilities */
    sr.sr_flags = SupportsFPCopyFile;
  #ifdef DISTRIB_PASSWDS
    sr.sr_flags |= SupportsChgPwd;
  #endif DISTRIB_PASSWDS
    sr.sr_flags |= SupportsServerMsgs;
    if (nopwdsave)
      sr.sr_flags |= DontAllowSavePwd;
  
    vicono.optr_loc = icon;
    vicono.optr_len = iconsize;
    sr.sr_vicono = (char *) &vicono;
  
    IniIndStr(avobuf);
    for (i = 0; afpversions[i].version_name != NULL; i++)
      AddIndStr(afpversions[i].version_name, avobuf);
--- 1057,1109 ----
  byte icon[];
  int iconsize;
  {
+   byte *q;
    int i,len;
    extern int nopwdsave;
    GetSrvrInfoReplyPkt sr;
+   OPTRType avo,uamo,vicono,sigo,nado;
    byte avobuf[AFPVERSZ],uamobuf[AFPUAMSZ];
!   byte nadbuf[MAXNADSIZ*NUMNAD+1];
!   extern u_short asip_port;
!   extern u_int asip_addr;
!   extern int asip_enable;
!   struct hostent *he;
!   char hostname[128];
  
!   /*
!    * set server capabilities
!    *
!    */
    sr.sr_flags = SupportsFPCopyFile;
  #ifdef DISTRIB_PASSWDS
    sr.sr_flags |= SupportsChgPwd;
  #endif DISTRIB_PASSWDS
    sr.sr_flags |= SupportsServerMsgs;
+   sr.sr_flags |= SupportsServerSig;
+   if (asip_enable)
+     sr.sr_flags |= SupportsTCPIP;
    if (nopwdsave)
      sr.sr_flags |= DontAllowSavePwd;
  
+   /*
+    * set Server Name & Machine Type
+    *
+    */
+   strcpy(sr.sr_machtype,afpmtyp);
+   cpyc2pstr(sr.sr_servername,sname);
+ 
+   /*
+    * set Volume Icon & Mask
+    *
+    */
    vicono.optr_loc = icon;
    vicono.optr_len = iconsize;
    sr.sr_vicono = (char *) &vicono;
  
+   /*
+    * set AFP Versions
+    *
+    */
    IniIndStr(avobuf);
    for (i = 0; afpversions[i].version_name != NULL; i++)
      AddIndStr(afpversions[i].version_name, avobuf);
***************
*** 1070,1075 ****
--- 1111,1120 ----
    avo.optr_loc = avobuf;
    sr.sr_avo = (byte *) &avo;
  
+   /*
+    * set UAMs
+    *
+    */
    IniIndStr(uamobuf);
    for (i=0 ; i < numuam; i++)
      AddIndStr(afpuams[i].uamname, uamobuf);
***************
*** 1077,1082 ****
--- 1122,1191 ----
    uamo.optr_loc = uamobuf;
    sr.sr_uamo = (byte *) &uamo;
  
+   /*
+    * set server signature
+    *
+    */
+   sigo.optr_len = 16;
+   sigo.optr_loc = (byte *)&sig;
+   sr.sr_sigo = (byte *)&sigo;
+ 
+   /*
+    * set network address(es)
+    * use single bound address (-B <addr:port>)
+    * or all known addresses for this machine
+    *
+    */
+   q = nadbuf+1;
+   nadbuf[0] = 0;
+   if (asip_enable) {
+     if (asip_addr) {
+       nadbuf[0] = 1;
+       q[2] = (asip_addr >> 24) & 0xff;
+       q[3] = (asip_addr >> 16) & 0xff;
+       q[4] = (asip_addr >>  8) & 0xff;
+       q[5] = (asip_addr & 0xff);
+       if (asip_port == ASIP_PORT) {
+         q[0] = 0x06; /* len */
+         q[1] = 0x01; /* tag */
+         q += 6;
+       } else {
+         q[0] = 0x08; /* len */
+         q[1] = 0x02; /* tag */
+         q[6] = asip_port >> 8;
+         q[7] = asip_port & 0xff;
+         q += 8;
+       }
+     } else { /* list all known addresses */
+       if (gethostname(hostname, sizeof(hostname)) == 0) {
+         if ((he = gethostbyname(hostname)) != NULL) {
+           for (i = 0; he->h_addr_list[i] && i < NUMNAD; i++) {
+ 	    bcopy(he->h_addr_list[i], q+2, 4); /* copy IP */
+ 	    if (asip_port == ASIP_PORT) {
+ 	      q[0] = 0x06; /* len */
+ 	      q[1] = 0x01; /* tag */
+ 	      q += 6;
+ 	    } else {
+ 	      q[0] = 0x08; /* len */
+ 	      q[1] = 0x02; /* tag */
+ 	      q[6] = asip_port >> 8;
+ 	      q[7] = asip_port & 0xff;
+ 	      q += 8;
+ 	    }
+           }
+           nadbuf[0] = i;
+         }
+       }
+     }
+   }
+   nado.optr_len = q-nadbuf;
+   nado.optr_loc = nadbuf;
+   sr.sr_naddro = (byte *)&nado;
+ 
+   /*
+    * pack data for sending
+    *
+    */
    len = htonPackX(ProtoSRP,(byte *) &sr,r);
  
  #ifdef DEBUG_AFP_CMD
***************
*** 1389,1395 ****
    int i;
    byte *q = r;
    u_short srvrflags;
!   short machoff, afpoff, uamoff, vicnoff;
    void dbg_print_name();
    void dbg_print_sflg();
    void dbg_print_icon();
--- 1498,1505 ----
    int i;
    byte *q = r;
    u_short srvrflags;
!   short machoff, afpoff, uamoff;
!   short vicnoff, sigoff, nadoff;
    void dbg_print_name();
    void dbg_print_sflg();
    void dbg_print_icon();
***************
*** 1402,1410 ****
    fprintf(dbg, "\tUAMOff: %d\n", uamoff);
    vicnoff = get2(q); q += 2;
    fprintf(dbg, "\tICNOff: %d\n", vicnoff);
!   fprintf(dbg, "\tVolFlg: %04x\t", (srvrflags = get2(q))); q += 2;
    dbg_print_sflg(srvrflags);
    dbg_print_name("\tSrvrNm:", q);
    if (machoff != 0)
      dbg_print_name("\tMchTyp:", r+machoff);
    if (afpoff != 0) {
--- 1512,1528 ----
    fprintf(dbg, "\tUAMOff: %d\n", uamoff);
    vicnoff = get2(q); q += 2;
    fprintf(dbg, "\tICNOff: %d\n", vicnoff);
!   srvrflags = get2(q); q += 2;
!   fprintf(dbg, "\tVolFlg: %04x\t", srvrflags);
    dbg_print_sflg(srvrflags);
    dbg_print_name("\tSrvrNm:", q);
+   q += ((*q)+1);
+   if ((u_long)q & 0x01)
+     q++; /* even */
+   sigoff = get2(q); q += 2;
+   fprintf(dbg, "\tSIGOff: %d\n", sigoff);
+   nadoff = get2(q); q += 2;
+   fprintf(dbg, "\tNADOff: %d\n", nadoff);
    if (machoff != 0)
      dbg_print_name("\tMchTyp:", r+machoff);
    if (afpoff != 0) {
***************
*** 1412,1418 ****
      fprintf(dbg, "\tVerCnt: %d\n", (int)(*q));
      for (i = *q++; i > 0; i--) {
        dbg_print_name("\tAFPVer:", q);
! 	q += ((*q) + 1);
      }
    } else
      fprintf(dbg, "\t<no AFP>\n");
--- 1530,1536 ----
      fprintf(dbg, "\tVerCnt: %d\n", (int)(*q));
      for (i = *q++; i > 0; i--) {
        dbg_print_name("\tAFPVer:", q);
!       q += ((*q) + 1);
      }
    } else
      fprintf(dbg, "\t<no AFP>\n");
***************
*** 1431,1436 ****
--- 1549,1588 ----
      fprintf(dbg, "\n");
    } else
      fprintf(dbg, "\t<no ICON>\n");
+   if (sigoff != 0) {
+     q = r + sigoff;
+     fprintf(dbg, "\tSrvSIG: ");
+     for (i = 0; i < 16; i++)
+       fprintf(dbg, "%02x ", *(q+i));
+     fprintf(dbg, "\n");
+   } else
+     fprintf(dbg, "\t<no SIG>\n");
+   if (nadoff != 0) {
+     q = r + nadoff;
+     fprintf(dbg, "\tNADCnt: %d\n", (int)(*q));
+     for (i = *q++; i > 0; i--) {
+       fprintf(dbg, "\tAFPNAD: len %d tag %d ", q[0], q[1]);
+       switch (q[1]) {
+ 	case 0x01:
+ 	  fprintf(dbg, "IP %d.%d.%d.%d\n",
+ 	    q[2], q[3], q[4], q[5]);
+ 	  break;
+ 	case 0x02:
+ 	  fprintf(dbg, "IP %d.%d.%d.%d Port %d\n",
+ 	    q[2], q[3], q[4], q[5], (q[6] << 8) | q[7]);
+ 	  break;
+ 	case 0x03:
+ 	  fprintf(dbg, "DDP net %d.%d node %d skt %d\n",
+ 	    q[2], q[3], q[4], q[5]);
+ 	  break;
+ 	default:
+ 	  fprintf(dbg, "<unknown>\n");
+ 	  break;
+       }
+       q += q[0];
+     }
+   } else
+     fprintf(dbg, "\t<no NAD>\n");
  
    return;
  }
***************
*** 1475,1485 ****
  	bmap &= ~(0x0001 << i);
  	switch (i) {
  	  case 0:
! 	    fprintf(dbg, "SuppCopyFile");
  	    j++;
  	    break;
  	  case 1:
! 	    fprintf(dbg, "SuppChngPass");
  	    j++;
              break;
  	  case 2:
--- 1627,1637 ----
  	bmap &= ~(0x0001 << i);
  	switch (i) {
  	  case 0:
! 	    fprintf(dbg, "CopyFile");
  	    j++;
  	    break;
  	  case 1:
! 	    fprintf(dbg, "ChngPass");
  	    j++;
              break;
  	  case 2:
***************
*** 1487,1497 ****
  	    j++;
  	    break;
  	  case 3:
! 	    fprintf(dbg, "SuppSrvrMesg");
  	    j++;
  	    break;
  	  case 15:
! 	    fprintf(dbg, "SuppMGetReqs");
  	    j++;
  	    break;
  	  default:
--- 1639,1661 ----
  	    j++;
  	    break;
  	  case 3:
! 	    fprintf(dbg, "SrvrMesg");
! 	    j++;
! 	    break;
! 	  case 4:
! 	    fprintf(dbg, "SrvrSig");
! 	    j++;
! 	    break;
! 	  case 5:
! 	    fprintf(dbg, "TCP/IP");
! 	    j++;
! 	    break;
! 	  case 6:
! 	    fprintf(dbg, "SrvrNotf");
  	    j++;
  	    break;
  	  case 15:
! 	    fprintf(dbg, "MGetReqs");
  	    j++;
  	    break;
  	  default:
*** applications/aufs/aufs.c.orig	Wed Sep 25 00:10:19 1996
--- applications/aufs/aufs.c		Fri Jul 11 19:29:43 1997
***************
*** 91,96 ****
--- 91,100 ----
  export u_char *srvrtype = (u_char *)AFSTYPE;	/* NBP registered type */
  export char *messagefile = NULL; /* AFP2.1 GetSrvrMsg srvr msg filename */
  export char *motdfile = NULL; /* AFP2.1 GetSrvrMsg login msg filename */
+ export char *dsiTCPIPFilter = NULL; /* AFP2.2 AppleShareIP address filter */
+ export u_int asip_addr = INADDR_ANY; /* AFP2.2 AppleShare over TCP/IP */
+ export u_short asip_port = ASIP_PORT; /* AFP2.2 AppleShare TCP/IP port */
+ export int asip_enable = FALSE; /* AFP2.2 AppleShare TCP/IP default off */
  
  private char *sysvolfile = NULL; /* system afpvols file */
  private char *passwdlookaside = NULL; /* local password file??? */
***************
*** 240,245 ****
--- 244,252 ----
    fprintf(stderr,"\t-V VolsFile for server wide afp volumes\n");
    fprintf(stderr,"\t-G <username> to set guest id for <anonymous> logins\n");
    fprintf(stderr,"\t-P LookAsidePasswordFile for scrambled transactions\n");
+   fprintf(stderr,"\t-T enable AFP connections via TCP/IP (default addr)\n");
+   fprintf(stderr,"\t-B <addr[:port]> enable AFP over TCP/IP & set address\n");
+   fprintf(stderr,"\t-f <filterfile> set the AFP over TCP-IP address filter\n");
    fprintf(stderr,"\t-U <number> to allow <number> sessions\n");
    fprintf(stderr,"\t-m|M <file> specifies login or server message file\n");
  #ifndef STAT_CACHE
***************
*** 297,307 ****
  char **argv;
  {
    int c;
    u_char *parsename();
    extern char *optarg;
    extern int optind;
    extern boolean dochecksum;
!   static char optlist[64] = "a:d:D:n:N:t:kpsuV:U:G:P:c:l:z:S:R:M:m:";
  #ifdef ISO_TRANSLATE
    void cISO2Mac();
  #endif ISO_TRANSLATE
--- 304,315 ----
  char **argv;
  {
    int c;
+   char *p;
    u_char *parsename();
    extern char *optarg;
    extern int optind;
    extern boolean dochecksum;
!   static char optlist[100] = "a:B:d:f:D:n:N:t:kpsTuV:U:G:P:c:l:z:S:R:M:m:";
  #ifdef ISO_TRANSLATE
    void cISO2Mac();
  #endif ISO_TRANSLATE
***************
*** 388,393 ****
--- 396,417 ----
        if (!SetPktTrace(optarg))
  	usage(argv[0]);
        break;
+     case 'f':				/* AppleShareIP IP address filter */
+       dsiTCPIPFilter = optarg;
+       break;
+     case 'B':				/* Bind AppleShare TCP/IP address */
+       if ((p = (char *)index(optarg, ':')) != NULL) {
+ 	asip_port = atoi(p+1);
+ 	*p = '\0';
+       }
+       if ((asip_addr = (u_int)ntohl(inet_addr(optarg))) == -1)
+ 	asip_addr = INADDR_ANY;
+       if (p != NULL)
+ 	*p = ':';
+       /* fall through */
+     case 'T':				/* Enable AppleShare TCP/IP */
+       asip_enable = TRUE;
+       break;
      case 'V':				/* system afpvols file */
        sysvolfile = optarg;
        break;
***************
*** 688,693 ****
--- 712,722 ----
    if ((ctp_stack = (int *)malloc(sizeof(int)*maxsess)) == NULL) {
      logit(0,"couldn't malloc stack for pid recording, fatal!");
    }
+   if (asip_enable)
+     if (asip_addr != INADDR_ANY)
+       logit(0,"AFP over TCP/IP enabled (IP %08x Port %d)",asip_addr,asip_port);
+     else
+       logit(0,"AFP over TCP/IP enabled (IP INADDR_ANY Port %d)", asip_port);
  #ifdef LWSRV_AUFS_SECURITY
    if (userlogindir != NULL) {			/* budd... */
        logit(0,"Aufs: user login database in %s", userlogindir);
***************
*** 725,731 ****
    if (n_rrpkts < atpMaxNum)
      logit(0,"remote limited to %d packet%s in a response", n_rrpkts,
  	n_rrpkts > 1 ? "s" : "");
!   SPGetParms(&mcs, &qs);
    if (DBDEB)
      printf("Command buffer size is %d, Quantum size is %d\n", mcs, qs);
    buf = (byte *)malloc(mcs);
--- 754,760 ----
    if (n_rrpkts < atpMaxNum)
      logit(0,"remote limited to %d packet%s in a response", n_rrpkts,
  	n_rrpkts > 1 ? "s" : "");
!   dsiGetParms(&mcs, &qs);
    if (DBDEB)
      printf("Command buffer size is %d, Quantum size is %d\n", mcs, qs);
    buf = (byte *)malloc(mcs);
***************
*** 783,798 ****
      PrtSrvrInfo(srvinfo,srvinfolen);
    
    /* Init asp */
!   err = SPInit(&addr,srvinfo,srvinfolen,&slsref);
    if (err != noErr) {
!     logit(0,"SPInit failed with code %d, fatal",err);
      exit(0);
    }
  
    logit(0,"Aufs Starting (%s)",srvrname);
    if (sysvolfile)
      logit(0,"System vols in '%s'",sysvolfile);
!   logit(0,"SPInit Completed.  Waiting for connection...");
  
  #ifndef NOSHUTDOWNCODE
  # ifndef NOPGRP
--- 812,827 ----
      PrtSrvrInfo(srvinfo,srvinfolen);
    
    /* Init asp */
!   err = dsiInit(&addr,srvinfo,srvinfolen,&slsref);
    if (err != noErr) {
!     logit(0,"dsiInit failed with code %d, fatal",err);
      exit(0);
    }
  
    logit(0,"Aufs Starting (%s)",srvrname);
    if (sysvolfile)
      logit(0,"System vols in '%s'",sysvolfile);
!   logit(0,"dsiInit Completed.  Waiting for connection...");
  
  #ifndef NOSHUTDOWNCODE
  # ifndef NOPGRP
***************
*** 819,825 ****
  
    do {
      pid = -1;			/* make sure zero at start */
!     SPGetSession(slsref,&cno,&comp);
      if (comp > 0)
        logit(0,"Waiting for session %d to activate", cno);
      /* won't wait if we set comp above */
--- 848,854 ----
  
    do {
      pid = -1;			/* make sure zero at start */
!     dsiGetSession(slsref,&cno,&comp);
      if (comp > 0)
        logit(0,"Waiting for session %d to activate", cno);
      /* won't wait if we set comp above */
***************
*** 848,855 ****
        sesscount++;
        logit(0,"New session %d started on server socket %d, count %d",
  	  cno,slsref,sesscount);
!       if ((err = SPGetNetworkInfo(cno, &addr)) != noErr) {
! 	logit(0,"Get Network info failed with error %d", err);
        } else {
  #ifdef AUTHENTICATE
  	err = (authenticate(ntohs(addr.net), addr.node)) ? noErr : ~noErr;
--- 877,889 ----
        sesscount++;
        logit(0,"New session %d started on server socket %d, count %d",
  	  cno,slsref,sesscount);
!       if ((err = dsiGetNetworkInfo(cno, &addr)) != noErr) {
! 	if (err > 0) { /* AppleShareIP session */
! 	logit(0,"Session %d from [IP addr %d.%d.%d.%d, port %d]",
! 	    cno, addr.net>>8, addr.net&0xff, addr.node, addr.skt, err);
! 	  err = noErr;
! 	} else
! 	  logit(0,"Get Network info failed with error %d", err);
        } else {
  #ifdef AUTHENTICATE
  	err = (authenticate(ntohs(addr.net), addr.node)) ? noErr : ~noErr;
***************
*** 864,870 ****
        }
  #ifdef AUTHENTICATE
        if(err != noErr) {
! 	SPCloseSession(cno, 1, 1, &comp2);
  	continue;
        }
  #endif AUTHENTICATE
--- 898,904 ----
        }
  #ifdef AUTHENTICATE
        if(err != noErr) {
! 	dsiCloseSession(cno, 1, 1, &comp2);
  	continue;
        }
  #endif AUTHENTICATE
***************
*** 889,898 ****
  # endif NOSHUTDOWNCODE;
  #endif NOSIGMASK
        /* fork on connection - only tickle from parent */
!       if ((pid = SPFork(cno, TRUE, FALSE)) < 0) {
! 	logit(0,"SPFork failed on session %d, last system error %d",cno, errno);
  	/* try to close, but don't worry too much */
! 	SPCloseSession(cno, 1, 1, &comp2);
  #ifdef NOSIGMASK
  	sigrelse(SIGCHLD);
  	sigrelse(SIGHUP);
--- 923,932 ----
  # endif NOSHUTDOWNCODE;
  #endif NOSIGMASK
        /* fork on connection - only tickle from parent */
!       if ((pid = dsiFork(cno, TRUE, FALSE)) < 0) {
! 	logit(0,"dsiFork failed on session %d, last system error %d",cno,errno);
  	/* try to close, but don't worry too much */
! 	dsiCloseSession(cno, 1, 1, &comp2);
  #ifdef NOSIGMASK
  	sigrelse(SIGCHLD);
  	sigrelse(SIGHUP);
***************
*** 905,912 ****
  #endif NOSIGMASK
  	continue;
        }
        if (pid) {
- 	SPTickleUserRoutine(cno, timedout, pid);
  	logit(0,"pid %d starting for session %d",pid, cno);
  	addinferior(cno, pid);	/* addinferior scans (phew) */
        } else {
--- 939,946 ----
  #endif NOSIGMASK
  	continue;
        }
+       dsiTickleUserRoutine(cno, timedout, pid);
        if (pid) {
  	logit(0,"pid %d starting for session %d",pid, cno);
  	addinferior(cno, pid);	/* addinferior scans (phew) */
        } else {
***************
*** 997,1003 ****
    umask(0);			/* file creates have explict modes */
    for (;;) {
  #ifndef TREL_TIMEOUT
!     SPGetRequest(cno,buf,mcs,&reqref,&type,&rlen,&comp);
      while (comp > 0) {
        abSleep(sectotick(60),TRUE);
  #ifdef AUFS_IDLE_TIMEOUT
--- 1031,1037 ----
    umask(0);			/* file creates have explict modes */
    for (;;) {
  #ifndef TREL_TIMEOUT
!     dsiGetRequest(cno,buf,mcs,&reqref,&type,&rlen,&comp);
      while (comp > 0) {
        abSleep(sectotick(60),TRUE);
  #ifdef AUFS_IDLE_TIMEOUT
***************
*** 1016,1022 ****
      }
  	    
     if (comp1 <= 0) {
!     SPGetRequest(cno,buf1,mcs,&reqref1,&type1,&rlen1,&comp1);
      while (comp1 > 0) {
        abSleep(sectotick(60),TRUE);
  #ifdef AUFS_IDLE_TIMEOUT
--- 1050,1056 ----
      }
  	    
     if (comp1 <= 0) {
!     dsiGetRequest(cno,buf1,mcs,&reqref1,&type1,&rlen1,&comp1);
      while (comp1 > 0) {
        abSleep(sectotick(60),TRUE);
  #ifdef AUFS_IDLE_TIMEOUT
***************
*** 1034,1043 ****
      }
  #ifndef TREL_TIMEOUT
      if (comp < 0) {
!       logit(0,"SPGetRequest failed %d",comp);
  #else TREL_TIMEOUT
      if (comp1 < 0) {
!       logit(0,"SPGetRequest failed %d",comp1);
  #endif TREL_TIMEOUT
        continue;
      }
--- 1068,1077 ----
      }
  #ifndef TREL_TIMEOUT
      if (comp < 0) {
!       logit(0,"dsiGetRequest failed %d",comp);
  #else TREL_TIMEOUT
      if (comp1 < 0) {
!       logit(0,"dsiGetRequest failed %d",comp1);
  #endif TREL_TIMEOUT
        continue;
      }
***************
*** 1079,1108 ****
        }
  #ifndef TREL_TIMEOUT
        if (type == aspWrite)
! 	SPWrtReply(cno,reqref,(dword) err,rspbuf,rsplen,&comp);
  #else TREL_TIMEOUT
        if (type1 == aspWrite)
! 	SPWrtReply(cno,reqref1,(dword) err,rspbuf1,rsplen1,&comp1);
  #endif TREL_TIMEOUT
        else
  #ifndef TREL_TIMEOUT
! 	SPCmdReply(cno,reqref,(dword) err,rspbuf,rsplen,&comp);
        while (comp > 0) {
  	abSleep(sectotick(60),TRUE);
        }
        if (DBSRV)
  	printf("done\n");
  #else TREL_TIMEOUT
! 	SPCmdReply(cno,reqref1,(dword) err,rspbuf1,rsplen1,&comp1);
  #endif TREL_TIMEOUT
        break;
      case aspCloseSession:
        logit(0,"Closing ASP Session...");
  #ifndef TREL_TIMEOUT
!       SPCloseSession(cno,10,3,&comp); /* 5 times, .75 seconds */
        while (comp > 0)
  #else TREL_TIMEOUT
!       SPCloseSession(cno,10,3,&comp1); /* 5 times, .75 seconds */
        while (comp1 > 0)
  #endif TREL_TIMEOUT
  	abSleep(1, TRUE);
--- 1113,1142 ----
        }
  #ifndef TREL_TIMEOUT
        if (type == aspWrite)
! 	dsiWrtReply(cno,reqref,(dword) err,rspbuf,rsplen,&comp);
  #else TREL_TIMEOUT
        if (type1 == aspWrite)
! 	dsiWrtReply(cno,reqref1,(dword) err,rspbuf1,rsplen1,&comp1);
  #endif TREL_TIMEOUT
        else
  #ifndef TREL_TIMEOUT
! 	dsiCmdReply(cno,reqref,(dword) err,rspbuf,rsplen,&comp);
        while (comp > 0) {
  	abSleep(sectotick(60),TRUE);
        }
        if (DBSRV)
  	printf("done\n");
  #else TREL_TIMEOUT
! 	dsiCmdReply(cno,reqref1,(dword) err,rspbuf1,rsplen1,&comp1);
  #endif TREL_TIMEOUT
        break;
      case aspCloseSession:
        logit(0,"Closing ASP Session...");
  #ifndef TREL_TIMEOUT
!       dsiCloseSession(cno,10,3,&comp); /* 5 times, .75 seconds */
        while (comp > 0)
  #else TREL_TIMEOUT
!       dsiCloseSession(cno,10,3,&comp1); /* 5 times, .75 seconds */
        while (comp1 > 0)
  #endif TREL_TIMEOUT
  	abSleep(1, TRUE);
***************
*** 1133,1139 ****
  #endif NOSHUTDOWNCODE;
  #ifdef TREL_TIMEOUT
     } else {  /* comp2 */
!     SPGetRequest(cno,buf2,mcs,&reqref2,&type2,&rlen2,&comp2);
      while (comp2 > 0) {
        abSleep(sectotick(60),TRUE);
  #ifdef AUFS_IDLE_TIMEOUT
--- 1167,1173 ----
  #endif NOSHUTDOWNCODE;
  #ifdef TREL_TIMEOUT
     } else {  /* comp2 */
!     dsiGetRequest(cno,buf2,mcs,&reqref2,&type2,&rlen2,&comp2);
      while (comp2 > 0) {
        abSleep(sectotick(60),TRUE);
  #ifdef AUFS_IDLE_TIMEOUT
***************
*** 1149,1155 ****
        return;
      }
      if (comp2 < 0) {
!       logit(0,"SPGetRequest failed %d",comp2);
        continue;
      }
      if (rlen2 == 0)
--- 1183,1189 ----
        return;
      }
      if (comp2 < 0) {
!       logit(0,"dsiGetRequest failed %d",comp2);
        continue;
      }
      if (rlen2 == 0)
***************
*** 1173,1185 ****
  	fflush(stdout);			/* force out */
        }
        if (type2 == aspWrite)
! 	SPWrtReply(cno,reqref2,(dword) err,rspbuf2,rsplen2,&comp2);
        else
! 	SPCmdReply(cno,reqref2,(dword) err,rspbuf2,rsplen2,&comp2);
        break;
      case aspCloseSession:
        logit(0,"Closing ASP Session...");
!       SPCloseSession(cno,10,3,&comp2); /* 5 times, .75 seconds */
        while (comp2 > 0)
  	abSleep(1, TRUE);
  #ifndef NOSHUTDOWNCODE
--- 1207,1219 ----
  	fflush(stdout);			/* force out */
        }
        if (type2 == aspWrite)
! 	dsiWrtReply(cno,reqref2,(dword) err,rspbuf2,rsplen2,&comp2);
        else
! 	dsiCmdReply(cno,reqref2,(dword) err,rspbuf2,rsplen2,&comp2);
        break;
      case aspCloseSession:
        logit(0,"Closing ASP Session...");
!       dsiCloseSession(cno,10,3,&comp2); /* 5 times, .75 seconds */
        while (comp2 > 0)
  	abSleep(1, TRUE);
  #ifndef NOSHUTDOWNCODE
***************
*** 1300,1308 ****
        logit(0,"process %d, session %d was suspended! gads what is happening?",
  	  cp->pid, srn);
      } else if (WIFSIGNALED(cp->status)) {
!       SPAttention(srn, AFPSHUTDOWNNOW, 1, -1, &comp);
        while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
!       SPCloseSession(srn, 3, 2, &comp); /* try 3 times every .5 seconds */
        while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
        logit(0,"process %d, session %d was terminated on signal %d",
  	  cp->pid, srn, W_TERMSIG(cp->status));
--- 1334,1342 ----
        logit(0,"process %d, session %d was suspended! gads what is happening?",
  	  cp->pid, srn);
      } else if (WIFSIGNALED(cp->status)) {
!       dsiAttention(srn, AFPSHUTDOWNNOW, 1, -1, &comp);
        while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
!       dsiCloseSession(srn, 3, 2, &comp); /* try 3 times every .5 seconds */
        while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
        logit(0,"process %d, session %d was terminated on signal %d",
  	  cp->pid, srn, W_TERMSIG(cp->status));
***************
*** 1321,1327 ****
        logit(0,"process %d, session %d terminated with exit code %d",
  	  cp->pid, srn, W_RETCODE(cp->status));
      }
!     SPShutdown(srn);
      nomoresessions = FALSE;	/* if this was set, unset now */
  #ifdef DORUSAGE
      logit(0,"%d messages out, %d in, CPU %.2f user %.2f system",
--- 1355,1361 ----
        logit(0,"process %d, session %d terminated with exit code %d",
  	  cp->pid, srn, W_RETCODE(cp->status));
      }
!     dsiShutdown(srn);
      nomoresessions = FALSE;	/* if this was set, unset now */
  #ifdef DORUSAGE
      logit(0,"%d messages out, %d in, CPU %.2f user %.2f system",
***************
*** 1385,1391 ****
    /* assume sigchild interlocked here */
    if (ctp_tab[srn].state & CP_RUNNING)
      ctp_tab[srn].state |= CP_TIMEDOUT;
!   SPShutdown(srn);		/* ignore errors */
    kill(pid, SIGHUP);		/* hangup inferior */
  }
  
--- 1419,1425 ----
    /* assume sigchild interlocked here */
    if (ctp_tab[srn].state & CP_RUNNING)
      ctp_tab[srn].state |= CP_TIMEDOUT;
!   dsiShutdown(srn);		/* ignore errors */
    kill(pid, SIGHUP);		/* hangup inferior */
  }
  
***************
*** 1399,1408 ****
    /* The following shouldn't really do anything since remote should be gone */
    /* be in case it really isn't, let's go through this rigamorle */
    /* Tell remote we are shutting down */
!   SPAttention(cno, AFPSHUTDOWNNOW, 1, -1, &comp);
    while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
    /* Try closing just in case */
!   SPCloseSession(cno, 3, 2, &comp); /* 3 times, .5 seconds */
    while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
  #ifdef LWSRV_AUFS_SECURITY
    clearuserlogin(); /* gtw: delete auth-file entry for dead users */
--- 1433,1442 ----
    /* The following shouldn't really do anything since remote should be gone */
    /* be in case it really isn't, let's go through this rigamorle */
    /* Tell remote we are shutting down */
!   dsiAttention(cno, AFPSHUTDOWNNOW, 1, -1, &comp);
    while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
    /* Try closing just in case */
!   dsiCloseSession(cno, 3, 2, &comp); /* 3 times, .5 seconds */
    while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
  #ifdef LWSRV_AUFS_SECURITY
    clearuserlogin(); /* gtw: delete auth-file entry for dead users */
***************
*** 1431,1437 ****
    /* Tell remote we are shutting down */
    if (minutes_to_shutdown % 2) {		/* all odd minutes */
      /* there is a potential race condition here */
!     SPAttention(cno, AFPSHUTDOWNTIME(minutes_to_shutdown), 1, -1, &comp);
      while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
    }
    minutes_to_shutdown--;
--- 1465,1471 ----
    /* Tell remote we are shutting down */
    if (minutes_to_shutdown % 2) {		/* all odd minutes */
      /* there is a potential race condition here */
!     dsiAttention(cno, AFPSHUTDOWNTIME(minutes_to_shutdown), 1, -1, &comp);
      while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
    }
    minutes_to_shutdown--;
***************
*** 1465,1471 ****
    int comp;
  
    signal(SIGURG, SIG_IGN);
!   SPAttention(cno, AFPSERVERMESG, 1, -1, &comp);
    while (comp > 0)
      abSleep(30, TRUE);
    signal(SIGURG, msgavail);
--- 1499,1505 ----
    int comp;
  
    signal(SIGURG, SIG_IGN);
!   dsiAttention(cno, AFPSERVERMESG, 1, -1, &comp);
    while (comp > 0)
      abSleep(30, TRUE);
    signal(SIGURG, msgavail);
***************
*** 1893,1899 ****
    if (cmp == 0 && *buf != 17) { /* periodic GetVolParms AFP call */
      if (sentshutdown) {
        logit(0, "Session %d: Aborting Idle Timeout", cno);
!       SPAttention(cno, AFPSHUTDOWNCANCEL, 1, -1, &comp);
        while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
        sentshutdown = 0;
      }
--- 1927,1933 ----
    if (cmp == 0 && *buf != 17) { /* periodic GetVolParms AFP call */
      if (sentshutdown) {
        logit(0, "Session %d: Aborting Idle Timeout", cno);
!       dsiAttention(cno, AFPSHUTDOWNCANCEL, 1, -1, &comp);
        while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
        sentshutdown = 0;
      }
***************
*** 1922,1937 ****
      case 12: /* shutdown in 3 min */
      case 24: /* shutdown in 1 min */
        logit(0, "Session %d: sending %d minute idle timeout warning",cno,5-i/6);
!       SPAttention(cno, AFPSHUTDOWNTIME(5-i/6), 1, -1, &comp);
        while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
        sentshutdown++;
        return;
        break;
      case 30: /* shutdown now */
        logit(0, "Session %d: Idle Timeout Shutdown", cno);
!       SPAttention(cno, AFPSHUTDOWNNOW, 1, -1, &comp);
        while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
!       SPCloseSession(cno, 3, 2, &comp); /* 3 times, .5 seconds */
        while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
  #ifdef LWSRV_AUFS_SECURITY
        clearuserlogin(); /* gtw: delete auth-file entry for dead users */
--- 1956,1971 ----
      case 12: /* shutdown in 3 min */
      case 24: /* shutdown in 1 min */
        logit(0, "Session %d: sending %d minute idle timeout warning",cno,5-i/6);
!       dsiAttention(cno, AFPSHUTDOWNTIME(5-i/6), 1, -1, &comp);
        while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
        sentshutdown++;
        return;
        break;
      case 30: /* shutdown now */
        logit(0, "Session %d: Idle Timeout Shutdown", cno);
!       dsiAttention(cno, AFPSHUTDOWNNOW, 1, -1, &comp);
        while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
!       dsiCloseSession(cno, 3, 2, &comp); /* 3 times, .5 seconds */
        while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
  #ifdef LWSRV_AUFS_SECURITY
        clearuserlogin(); /* gtw: delete auth-file entry for dead users */
*** applications/aufs/Makefile.m4.orig	Wed Sep 25 00:09:57 1996
--- applications/aufs/Makefile.m4	Mon Jul  7 02:03:26 1997
***************
*** 48,59 ****
  	afpmisc.c afpserver.c aufsicon.c abmisc2.c \
  	afpdt.c afpdid.c afposenum.c  afpavl.c \
  	afposfi.c afpgc.c afppasswd.c afposlock.c aufsv.c \
! 	afpudb.c afposncs.c afpspd.c afpfid.c
  OBJS=afpos.o afpvols.o afpfile.o \
  	afpmisc.o afpserver.o aufsicon.o abmisc2.o \
  	afpdt.o afpdir.o afpfork.o afpdid.o afposenum.o afpavl.o \
  	afposfi.o afpgc.o afppasswd.o aufsv.o \
! 	afpudb.o afposncs.o afpspd.o afpfid.o
  SYMLINKS=att_getopt.c
  
  all:	aufs sizeserver afpidsrvr afpidlist afpidtool
--- 48,59 ----
  	afpmisc.c afpserver.c aufsicon.c abmisc2.c \
  	afpdt.c afpdid.c afposenum.c  afpavl.c \
  	afposfi.c afpgc.c afppasswd.c afposlock.c aufsv.c \
! 	afpudb.c afposncs.c afpspd.c afpfid.c afpdsi.c
  OBJS=afpos.o afpvols.o afpfile.o \
  	afpmisc.o afpserver.o aufsicon.o abmisc2.o \
  	afpdt.o afpdir.o afpfork.o afpdid.o afposenum.o afpavl.o \
  	afposfi.o afpgc.o afppasswd.o aufsv.o \
! 	afpudb.o afposncs.o afpspd.o afpfid.o afpdsi.o
  SYMLINKS=att_getopt.c
  
  all:	aufs sizeserver afpidsrvr afpidlist afpidtool
***************
*** 189,191 ****
--- 189,193 ----
  afppasswd.o:    afppasswd.c	$I/netat/sysvcompat.h afppasswd.h
  afposncs.o:	afposncs.c	$I/netat/appletalk.h $I/netat/afp.h \
  				afposncs.h afps.h
+ afpdsi.o:	afpdsi.c	$I/netat/appletalk.h ../../lib/cap/abasp.h \
+ 				afpdsi.h
*** lib/afp/afppacks.c.orig		Wed Sep 25 00:10:07 1996
--- lib/afp/afppacks.c			Mon Mar  3 17:34:40 1997
***************
*** 615,620 ****
--- 615,622 ----
    PAKB(GVPRPPtr,P_DWRD,gvpr_free,VP_FREE), /* free bytes */
    PAKB(GVPRPPtr,P_DWRD,gvpr_size,VP_SIZE), /* size in bytes */
    PKSB(GVPRPPtr,P_OSTR,gvpr_name,VP_NAME), /* name of volume */
+   PKSB(GVPRPPtr,P_BYTS,gvpr_efree,VP_EFREE), /* extended free bytes */
+   PKSB(GVPRPPtr,P_BYTS,gvpr_esize,VP_ESIZE), /* extended total bytes */
    PACKEND()
  };
  
***************
*** 663,668 ****
--- 665,673 ----
    PACK(GSIRPPtr, P_OPTR, sr_vicono),
    PACK(GSIRPPtr, P_WORD, sr_flags),
    PAKS(GSIRPPtr, P_PATH, sr_servername),
+   PACKEVEN(),
+   PACK(GSIRPPtr, P_OPTR, sr_sigo),
+   PACK(GSIRPPtr, P_OPTR, sr_naddro),
    PACKEND()
  };
  
*** lib/cap/abasp.c.orig		Thu Mar 14 13:47:51 1991
--- lib/cap/abasp.c			Fri Jul 11 18:20:13 1997
***************
*** 18,25 ****
   *  Aug   4, 1986    CCKim	Verified: level 0
  */
  
- /* PATCH: Moy@Berkeley/abasp.c.diff, djh@munnari.OZ.AU, 17/11/90 */
- 
  #include <stdio.h>
  #include <sys/types.h>
  #include <netinet/in.h>
--- 18,23 ----
***************
*** 61,78 ****
  private void start_client_aspskt();
  private void shutdown_aspskt();
  
! private ASPQE *create_aq();
  private ASPQE *get_aq();
- private void delete_aq();
  private boolean match_aspwe();
  private ASPQE *find_aspawe();
  
  private void startasptickle();
! private void stopasptickle();
  private void ttimeout();
  private void start_ttimer();
  private void reset_ttimer();
! private void stop_ttimer();
  
  int SPFork();
  OSErr SPShutdown();
--- 59,76 ----
  private void start_client_aspskt();
  private void shutdown_aspskt();
  
! void delete_aq();
! ASPQE *create_aq();
  private ASPQE *get_aq();
  private boolean match_aspwe();
  private ASPQE *find_aspawe();
  
  private void startasptickle();
! void stopasptickle();
  private void ttimeout();
  private void start_ttimer();
  private void reset_ttimer();
! void stop_ttimer();
  
  int SPFork();
  OSErr SPShutdown();
***************
*** 89,98 ****
  #ifdef ASPPID
  private ASPSkt *aspskt_find_pid();
  #endif
- private ASPSkt *aspskt_find_active();
- private ASPSkt *aspskt_find_sessrefnum();
  private OSErr aspsskt_new();
! private ASPSSkt *aspsskt_find_slsrefnum();
  private boolean aspsskt_isactive();
  
  private void sizeof_abr_bds_and_req();
--- 87,96 ----
  #ifdef ASPPID
  private ASPSkt *aspskt_find_pid();
  #endif
  private OSErr aspsskt_new();
! ASPSkt *aspskt_find_active();
! ASPSkt *aspskt_find_sessrefnum();
! ASPSSkt *aspsskt_find_slsrefnum();
  private boolean aspsskt_isactive();
  
  private void sizeof_abr_bds_and_req();
***************
*** 1896,1901 ****
--- 1894,1900 ----
        stopasptickle(as);
      }
      ATPCloseSocket(sas->addr.skt); /* close down server listener here */
+     dsiTCPIPCloseSLS(); /* and the AppleShareIP SLS */
    }
    return(pid);
  }
***************
*** 2093,2099 ****
  }
  #endif
  
! private ASPSkt *
  aspskt_find_active(SLSRefNum)
  int SLSRefNum;
  {
--- 2092,2098 ----
  }
  #endif
  
! ASPSkt *
  aspskt_find_active(SLSRefNum)
  int SLSRefNum;
  {
***************
*** 2106,2112 ****
    return(NULL);
  }
  
! private ASPSkt *
  aspskt_find_sessrefnum(srn)
  int srn;
  {
--- 2105,2111 ----
    return(NULL);
  }
  
! ASPSkt *
  aspskt_find_sessrefnum(srn)
  int srn;
  {
***************
*** 2137,2143 ****
  }
  
  
! private ASPSSkt *
  aspsskt_find_slsrefnum(sls)
  int sls;
  {
--- 2136,2148 ----
  }
  
  
! /*
!  * locate SLSRefNum structure
!  * (non-private for DSI access)
!  *
!  */
! 
! ASPSSkt *
  aspsskt_find_slsrefnum(sls)
  int sls;
  {
***************
*** 2212,2218 ****
   * stopasptickle - cancel the tickle on the specified connection
   *
  */
! private void
  stopasptickle(as)
  ASPSkt *as;
  {
--- 2217,2223 ----
   * stopasptickle - cancel the tickle on the specified connection
   *
  */
! void
  stopasptickle(as)
  ASPSkt *as;
  {
***************
*** 2277,2283 ****
   * cancel the remote tickle timeout
   *
  */
! private void
  stop_ttimer(as)
  ASPSkt *as;
  {
--- 2282,2288 ----
   * cancel the remote tickle timeout
   *
  */
! void
  stop_ttimer(as)
  ASPSkt *as;
  {
***************
*** 2291,2297 ****
  private ASPQE *aspqe_list;
  private QElemPtr aspqe_free;
  
! private ASPQE *
  create_aq(which, as)
  int which;
  ASPSkt *as;
--- 2296,2302 ----
  private ASPQE *aspqe_list;
  private QElemPtr aspqe_free;
  
! ASPQE *
  create_aq(which, as)
  int which;
  ASPSkt *as;
***************
*** 2320,2326 ****
    return(aspqe);
  }
  
! private void
  delete_aq(aspqe, which, as)
  ASPQE *aspqe;
  int which;
--- 2325,2331 ----
    return(aspqe);
  }
  
! void
  delete_aq(aspqe, which, as)
  ASPQE *aspqe;
  int which;
*** lib/cap/absched.c.orig		Wed Sep 25 00:10:17 1996
--- lib/cap/absched.c			Wed Jul  9 16:07:49 1997
***************
*** 704,709 ****
--- 704,711 ----
      }
      if (dbug.db_skd)
        fprintf(stderr,"%d ", rdy);
+     if (rdy < 0)
+       return(rdy);
      if (rdy > 0) {
        /* rdy should be # of set file descriptors in the masks */
        /* since we only pass it the "read" bits, this loop */
*** etc/aufsIPFilter.orig	Mon Jul 14 13:46:44 1997
--- etc/aufsIPFilter		Mon Jul 14 13:49:11 1997
***************
*** 0 ****
--- 1,26 ----
+ #
+ # aufs/AppleShareIP Address Access Filter List
+ #
+ # NB: The filter file format is compatible with that used by the ARNS
+ # Remote Access package (http://www.cs.mu.OZ.AU/appletalk/atalk.html)
+ #
+ # The filter list consists of a single character mode, an IP mask and
+ # optional IP address. If the latter is included, the mask is applied
+ # to the incoming IP address and tested against the provided address.
+ # Otherwise the incoming IP address must be unchanged by the mask.
+ #
+ # Modes:
+ #
+ # * IP_MASK [ IP_ADDR ]		permit access
+ # + IP_MASK [ IP_ADDR ]		permit access
+ # - IP_MASK [ IP_ADDR ]		deny access
+ #
+ #
+ # any mac on a specific subnet
+ + 255.255.255.0    192.43.207.0
+ # connections from ariel
+ * 128.250.255.255  128.250.20.3
+ # anybody on campus
+ + 128.243.255.255
+ # nobody else
+ - 255.255.255.255
*** samples/ash.c.orig			Wed Sep 25 00:10:10 1996
--- samples/ash.c			Mon Jul 14 14:27:33 1997
***************
*** 1090,1092 ****
--- 1090,1102 ----
    *bp++ = '\0';
    return(buf);
  }
+ 
+ /*
+  * this is a dummy routine for abasp.c
+  *
+  */
+ 
+ dsiTCPIPCloseSLS()
+ {
+   return(noErr);
+ }
*** man/AUFS.8.orig			Wed Sep 25 00:09:56 1996
--- man/AUFS.8				Mon Jul 14 13:53:02 1997
***************
*** 21,26 ****
--- 21,30 ----
  ] [
  .BI \-F " <file type mapping>"
  ] [
+ .BI \-B " <IPaddress[:port]>"
+ ] [
+ .BI \-f " <IP filter file>"
+ ] [
  .BI \-[i|I] " <idle timeout>"
  ] [
  .BI \-c " <directory name>"
***************
*** 45,50 ****
--- 49,56 ----
  ] [
  .BI \-u
  ] [
+ .BI \-T
+ ] [
  .BI \-d " <flags>"
  ] [
  .BI \-a " <flags>"
***************
*** 57,71 ****
  ]
  .SH DESCRIPTION
  .I aufs
! implements a file server on a UNIX host connected
! to an AppleTalk network, for client computers on AppleTalk that support AFP.
! Specifically, it works as a file server for Macintosh computers with 
! the AppleShare client code.
  This manual entry describes how to run the UNIX server daemon process.
  See AUFS(1) for information about how to use the server.
  .PP
  .I aufs
! is normally started at boot time via a command in start-cap-servers (whic
  is usually run from /etc/rc.local).
  The CAP name information server daemon
  .I atis
--- 63,77 ----
  ]
  .SH DESCRIPTION
  .I aufs
! implements a file server on a UNIX host for client computers on AppleTalk
! that support AFP,
! or Macintoshes on the internet that support AFP via TCP/IP using AppleShare
! client 3.7 or later.
  This manual entry describes how to run the UNIX server daemon process.
  See AUFS(1) for information about how to use the server.
  .PP
  .I aufs
! is normally started at boot time via a command in start-cap-servers (which
  is usually run from /etc/rc.local).
  The CAP name information server daemon
  .I atis
***************
*** 148,153 ****
--- 154,186 ----
  user may over-ride these mappings by having a .afpfile (or afpfile) file
  in their home directory.
  .TP 10
+ .BI \-T
+ enables AppleShareIP (AFP via TCP/IP) support in
+ .I aufs.
+ Note that the first
+ .I aufs
+ process defaults to the well-know port number 548. Subsequent incarnations
+ of
+ .I aufs
+ will require that the TCP/IP port number be specified using the \-B option.
+ Clients needing to connect to these servers, that are not also connected to
+ the same network via AppleTalk, must specify the port number in
+ the dialog box obtained by clicking on the Chooser "Server IP Address..."
+ button. The format is the same as for the \-B option, ie: 128.250.1.21:2169
+ to use port number 2169 on host 128.250.1.21.
+ .TP 10
+ .BI \-B " <IPaddress[:port]>"
+ tells
+ .I aufs
+ to listen for TCP/IP connections at the specified IP address and optional
+ port (defaults to any available interface address and port number 548).
+ This option implies \-T.
+ .TP 10
+ .BI \-f " <IP filter file>"
+ specifies the pathname of a file containing yes/no permissions for client
+ IP numbers or subnets wishing to connect using AFP via TCP/IP. See the file
+ cap60/etc/aufsIPFilter for details.
+ .TP 10
  .BI \-c " <directory name>"
  specifies a directory where
  .I aufs
***************
*** 341,354 ****
  .PP
  Notes and warnings pertaining to client use and file system implementation
  are documented in AUFS(1).
- .PP
- AUFS Version 3, released post 2/88, has a different .finderinfo and
- desktop format than previous releases of AUFS.  Old format desktop
- files are automatically discarded and old format .finderinfo files are
- rewritten on sight (if possible).  You should consider rebuilding your
- desktop if you had a volume created with AUFS Version 2 or previous to
- regain the applications mappings and to ensure that all .finderinfo
- files are rewritten.
  .SH AUTHOR
  AUFS was written by Bill Schilit, Computer Science Deparment and
  Charlie C. Kim, User Services, Columbia University.
--- 374,379 ----
*** netat/afp.h.orig			Wed Sep 25 00:09:55 1996
--- netat/afp.h				Tue Mar  4 14:40:34 1997
***************
*** 192,207 ****
  
  /* Volume Params */
  
! #define VP_ATTR  0001		/* attributes */
! #define VP_SIG   0002		/* signature byte */
! #define VP_CDATE 0004		/* creation date */
! #define VP_MDATE 0010		/* modification date */
! #define VP_BDATE 0020		/* backup date */
! #define VP_VOLID 0040		/* volume id */
! #define VP_FREE  0100		/* free bytes */
! #define VP_SIZE  0200		/* size in bytes */
! #define VP_NAME  0400		/* volume name */
! #define VP_ALL  (0777)
  
  #define VOL_VAR_DIRID 0x03	/* volume has variable dirids */
  #define VOL_FIXED_DIRID 0x02	/* volume has fixed dirids */
--- 192,209 ----
  
  /* Volume Params */
  
! #define VP_ATTR  00001		/* attributes */
! #define VP_SIG   00002		/* signature byte */
! #define VP_CDATE 00004		/* creation date */
! #define VP_MDATE 00010		/* modification date */
! #define VP_BDATE 00020		/* backup date */
! #define VP_VOLID 00040		/* volume id */
! #define VP_FREE  00100		/* free bytes */
! #define VP_SIZE  00200		/* size in bytes */
! #define VP_NAME  00400		/* volume name */
! #define VP_EFREE 01000		/* AFP2.2: extended free bytes */
! #define VP_ESIZE 02000		/* AFP2.2: extended total bytes */
! #define VP_ALL  (03777)
  
  #define VOL_VAR_DIRID 0x03	/* volume has variable dirids */
  #define VOL_FIXED_DIRID 0x02	/* volume has fixed dirids */
***************
*** 278,282 ****
--- 280,286 ----
  #define UIP_PRIMARY_GID 0x2	/* primary group (dword) */
  
  #define AFSTYPE "AFPServer"	/* NBP type for AFS */
+ 
+ #define ASIP_PORT 548		/* AppleShare over TCP/IP well-known port */
  
  char *afperr();			/* in afperr.c */
*** netat/afpcmd.h.orig			Wed Sep 25 00:09:56 1996
--- netat/afpcmd.h			Tue Mar  4 13:22:33 1997
***************
*** 279,285 ****
--- 279,290 ----
  #define SupportsChgPwd     0x02	/* AFP2.0: can do change password */
  #define DontAllowSavePwd   0x04	/* AFP2.1: user can't save password */
  #define SupportsServerMsgs 0x08	/* AFP2.1: can send server messages */
+ #define SupportsServerSig  0x10	/* AFP2.2: can supply unique signature */
+ #define SupportsTCPIP      0x20	/* AFP2.2: AFP commands via TCP/IP stream */
+ #define SupportsSrvrNotif  0x40	/* AFP2.2: server to client messages */
    byte sr_servername[33];	/* server name */
+   byte *sr_sigo;		/* AFP2.2: offset to signature */
+   byte *sr_naddro;		/* AFP2.2: offset to network address count */
  } GetSrvrInfoReplyPkt, *GSIRPPtr;
  
  typedef struct {		/* FPGetSrvrParms */
***************
*** 319,324 ****
--- 324,331 ----
    sdword gvpr_size;		/* size of volume in bytes */
    sdword gvpr_free;		/* free bytes on volume */
    byte gvpr_name[MAXVLEN];	/* advertised name */
+   byte gvpr_esize[8];		/* extended volume size */
+   byte gvpr_efree[8];		/* extended bytes free */
  } GetVolParmsReplyPkt, *GVPRPPtr;
  
  
