273 lines
7.1 KiB
C
273 lines
7.1 KiB
C
/*
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
fsd_srv.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the entry points for the AFP server APIs. The API
|
||
dispatcher calls these. These are all callable from FSD. All of the APIs
|
||
complete in the DPC context. The ones which are completed in the FSP are
|
||
directly queued to the workers in fsp_srv.c
|
||
|
||
Author:
|
||
|
||
Jameel Hyder (microsoft!jameelh)
|
||
|
||
|
||
Revision History:
|
||
25 Apr 1992 Initial Version
|
||
|
||
Notes: Tab stop: 4
|
||
--*/
|
||
|
||
#define FILENUM FILE_FSD_SRV
|
||
|
||
#include <afp.h>
|
||
#include <gendisp.h>
|
||
|
||
|
||
/*** AfpFsdDispGetSrvrParms
|
||
*
|
||
* This routine implements the AfpGetSrvrParms API. This completes here i.e.
|
||
* it is not queued up to the Fsp.
|
||
*
|
||
* There is no request packet for this API.
|
||
*
|
||
* Locks are acquired for both the volume list and individual volume descs.
|
||
*
|
||
* LOCKS: vds_VolLock (SPIN), AfpVolumeListLock (SPIN)
|
||
*
|
||
* LOCK_ORDER: vds_VolLock (SPIN) after AfpVolumeListLock (SPIN)
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFsdDispGetSrvrParms(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
PBYTE pTemp; // Roving pointer
|
||
PVOLDESC pVolDesc;
|
||
LONG VolCount;
|
||
AFPTIME MacTime;
|
||
BOOLEAN MoreSpace = True;
|
||
struct _ResponsePacket
|
||
{
|
||
BYTE __ServerTime[4];
|
||
BYTE __NumVols;
|
||
};
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
|
||
("AfpFsdDispGetSrvrParms: Entered\n"));
|
||
|
||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||
/*
|
||
* Estimate the size of reply buffer needed. We need one big enough to
|
||
* either accomodate all volumes or the maximum size buffer whichever
|
||
* is less.
|
||
*
|
||
* The reply consists of the server time, count of volumes and a list of
|
||
* volumes and flags to indicate if this volume has a password.
|
||
*
|
||
* NOTE: If we decide to do private volumes, then the following code
|
||
* has to change. Specifically AfpVolCount will have to be computed
|
||
* based on how many private volumes exist and if there is one
|
||
* for this user.
|
||
*/
|
||
|
||
ACQUIRE_SPIN_LOCK_AT_DPC(&AfpVolumeListLock);
|
||
|
||
/*
|
||
* Each volume entry takes a byte for flags, a byte for length and the
|
||
* size of the volume name string. We estimate based on maximum size of
|
||
* the volume name. On an average it will be less. For every volume, apart
|
||
* from the volume name, we need a byte for volume flags and a byte for
|
||
* the volume name length.
|
||
*/
|
||
if ((pSda->sda_ReplySize = (USHORT)(SIZE_RESPPKT + AfpVolCount *
|
||
(SIZE_PASCALSTR(AFP_VOLNAME_LEN+1) + sizeof(BYTE)))) > pSda->sda_MaxWriteSize)
|
||
pSda->sda_ReplySize = (USHORT)pSda->sda_MaxWriteSize;
|
||
|
||
if (AfpAllocReplyBuf(pSda) != AFP_ERR_NONE)
|
||
{
|
||
RELEASE_SPIN_LOCK_FROM_DPC(&AfpVolumeListLock);
|
||
return AFP_ERR_MISC;
|
||
}
|
||
|
||
// Point pTemp past the response header
|
||
pTemp = pSda->sda_ReplyBuf + SIZE_RESPPKT;
|
||
|
||
for (VolCount = 0, pVolDesc = AfpVolumeList;
|
||
(pVolDesc != NULL) && MoreSpace;
|
||
pVolDesc = pVolDesc->vds_Next)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_AT_DPC(&pVolDesc->vds_VolLock);
|
||
do
|
||
{
|
||
// Ignore volumes that have not been added completely
|
||
if (pVolDesc->vds_Flags & (VOLUME_INTRANSITION | VOLUME_DELETED | VOLUME_INITIAL_CACHE))
|
||
break;
|
||
|
||
// Ignore volumes that do not have guest access and the client
|
||
// is guest
|
||
if (!(pVolDesc->vds_Flags & AFP_VOLUME_GUESTACCESS) &&
|
||
(pSda->sda_ClientType == SDA_CLIENT_GUEST))
|
||
break;
|
||
|
||
// See if we are likely to cross bounds. For each volume we need a
|
||
// byte for the PASCALSTR name and a flag byte. Note that we do not
|
||
// add any pads.
|
||
if ((pTemp + SIZE_PASCALSTR(pVolDesc->vds_MacName.Length) +
|
||
sizeof(BYTE)) >= (pSda->sda_ReplyBuf + pSda->sda_ReplySize))
|
||
{
|
||
DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
|
||
("AfpFsdDispGetSrvrParms: Out of space\n"));
|
||
MoreSpace = False;
|
||
break;
|
||
}
|
||
|
||
// Check for volume password. We never carry the HasConfigInfo bit !!
|
||
*pTemp++ = (pVolDesc->vds_Flags & AFP_VOLUME_HASPASSWORD) ?
|
||
SRVRPARMS_VOLUMEHASPASS : 0;
|
||
|
||
*pTemp++ = (BYTE)pVolDesc->vds_MacName.Length;
|
||
RtlCopyMemory(pTemp, pVolDesc->vds_MacName.Buffer,
|
||
pVolDesc->vds_MacName.Length);
|
||
|
||
pTemp += pVolDesc->vds_MacName.Length;
|
||
VolCount ++;
|
||
} while (False);
|
||
RELEASE_SPIN_LOCK_FROM_DPC(&pVolDesc->vds_VolLock);
|
||
}
|
||
RELEASE_SPIN_LOCK_FROM_DPC(&AfpVolumeListLock);
|
||
|
||
pSda->sda_ReplySize = (USHORT)(pTemp - pSda->sda_ReplyBuf);
|
||
|
||
ASSERT (VolCount <= AfpVolCount);
|
||
AfpGetCurrentTimeInMacFormat(&MacTime);
|
||
PUTDWORD2DWORD(pRspPkt->__ServerTime, MacTime);
|
||
PUTDWORD2BYTE(&pRspPkt->__NumVols, VolCount);
|
||
|
||
return AFP_ERR_NONE;
|
||
}
|
||
|
||
|
||
/*** AfpFsdDispGetSrvrMsg
|
||
*
|
||
* This routine implements the AfpGetSrvrMsg API. This completes here i.e.
|
||
* it is not queued up to the Fsp.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_ReqBlock DWORD MsgType
|
||
* sda_ReqBlock DWORD Bitmap
|
||
*
|
||
* LOCKS: AfpServerGlobalLock (SPIN), sda_Lock (SPIN)
|
||
* LOCK_ORDER: sda_Lock after AfpServerGlobalLock
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFsdDispGetSrvrMsg(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
DWORD MsgType,
|
||
Bitmap;
|
||
AFPSTATUS Status = AFP_ERR_NONE;
|
||
ANSI_STRING Message;
|
||
|
||
struct _RequestPacket
|
||
{
|
||
DWORD _MsgType,
|
||
_Bitmap;
|
||
};
|
||
struct _ResponsePacket
|
||
{
|
||
BYTE __MsgType[2],
|
||
__Bitmap[2],
|
||
__Message[1];
|
||
};
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_SRV, DBG_LEVEL_INFO,
|
||
("AfpFsdDispGetSrvrMsg: Entered\n"));
|
||
|
||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||
|
||
// Note: Should we be doing this ? Why not give it to him since he asked.
|
||
if (pSda->sda_ClientVersion < AFP_VER_21)
|
||
return AFP_ERR_CALL_NOT_SUPPORTED;
|
||
|
||
MsgType = pReqPkt->_MsgType;
|
||
Bitmap = pReqPkt->_Bitmap;
|
||
|
||
do
|
||
{
|
||
if (Bitmap & ~SRVRMSG_BITMAP_MESSAGE)
|
||
{
|
||
Status = AFP_ERR_BITMAP;
|
||
break;
|
||
}
|
||
|
||
if ((MsgType != SRVRMSG_LOGIN) &&
|
||
(MsgType != SRVRMSG_SERVER))
|
||
{
|
||
Status = AFP_ERR_PARAM;
|
||
break;
|
||
}
|
||
|
||
// Allocate a reply buffer for a maximum size message. We cannot hold the
|
||
// SDA lock and call the AllocBuf routine since it calls AfpInterlocked...
|
||
pSda->sda_ReplySize = SIZE_RESPPKT + AFP_MAXCOMMENTSIZE;
|
||
if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_AT_DPC(&AfpServerGlobalLock);
|
||
ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
|
||
|
||
switch (MsgType)
|
||
{
|
||
case SRVRMSG_LOGIN:
|
||
Message = AfpLoginMsg;
|
||
break;
|
||
case SRVRMSG_SERVER:
|
||
if (pSda->sda_Message != NULL)
|
||
Message = *(pSda->sda_Message);
|
||
else if (AfpServerMsg != NULL)
|
||
Message = *AfpServerMsg;
|
||
else // Setup a default of No message.
|
||
AfpSetEmptyAnsiString(&Message, 0, NULL);
|
||
break;
|
||
}
|
||
|
||
pSda->sda_ReplySize = SIZE_RESPPKT + Message.Length;
|
||
|
||
PUTSHORT2SHORT(pRspPkt->__MsgType, MsgType);
|
||
PUTSHORT2SHORT(pRspPkt->__Bitmap, Bitmap);
|
||
pRspPkt->__Message[0] = (BYTE) Message.Length;
|
||
if (Message.Length > 0)
|
||
{
|
||
RtlCopyMemory( &pRspPkt->__Message[1],
|
||
Message.Buffer,
|
||
Message.Length);
|
||
}
|
||
// If this is not a broadcast message, then get rid of the
|
||
// Sda message memory as it is consuming non-paged resources
|
||
if ((MsgType == SRVRMSG_SERVER) &&
|
||
(pSda->sda_Message != NULL))
|
||
{
|
||
AfpFreeMemory(pSda->sda_Message);
|
||
pSda->sda_Message = NULL;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
|
||
RELEASE_SPIN_LOCK_FROM_DPC(&AfpServerGlobalLock);
|
||
}
|
||
|
||
if (Status == AFP_ERR_NONE)
|
||
INTERLOCKED_INCREMENT_LONG(&AfpServerStatistics.stat_NumMessagesSent);
|
||
} while (False);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|