Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1615 lines
42 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Copyright (c) 1993 Micro Computer Systems, Inc.
Module Name:
net\svcdlls\nwsap\server\network.c
Abstract:
These are the network interface routines for the NT SAP Agent
Author:
Brian Walker (MCS) 06-15-1993
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
/** This is the address we send to **/
#define SAP_ADDRESS_LENGTH 15
INT SapBroadcastAddressLength = SAP_ADDRESS_LENGTH;
UCHAR SapBroadcastAddress[] = {
AF_IPX, 0, /* Address Family */
0x00, 0x00, 0x00, 0x00, /* Dest. Net Number */
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Dest. Node Number */
0x04, 0x52, /* Dest. Socket */
0x04 /* Packet type */
};
/** Internal Function Prototypes **/
INT
SapAddSendEntry(
PSAP_RECORD Entry,
PSAP_PKTLIST Plist,
USHORT HopInc);
/*++
*******************************************************************
S a p N e t w o r k I n i t
Routine Description:
This routine initializes the network portion of the Sap Agent.
Arguments:
None
Return Value:
0 = OK
Else = Error
*******************************************************************
--*/
INT
SapNetworkInit(
VOID)
{
INT rc;
INT Length;
BOOL Value;
SOCKADDR_IPX Bindaddr;
PSAP_CARD Cardptr;
INT Cardnum;
IPX_ADDRESS_DATA Addrdata;
/** Open an IPX datagram socket **/
SapSocket = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
if (SapSocket == INVALID_SOCKET) {
SapError = h_errno;
SapEventId = NWSAP_EVENT_SOCKET_FAILED;
return -1;
}
/** Enable sending of broadcasts **/
Value = TRUE;
rc = setsockopt(SapSocket, SOL_SOCKET, SO_BROADCAST, (PVOID)&Value, sizeof(INT));
if (rc == -1) {
SapError = h_errno;
SapEventId = NWSAP_EVENT_SETOPTBCAST_FAILED;
return -1;
}
/** Setup the address to bind to **/
memset(&Bindaddr, 0, sizeof(SOCKADDR_IPX));
Bindaddr.sa_family = AF_IPX;
Bindaddr.sa_socket = htons(NWSAP_SAP_SOCKET);
/** Bind to the socket **/
rc = bind(SapSocket, (PSOCKADDR)&Bindaddr, sizeof(SOCKADDR_IPX));
if (rc == -1) {
SapError = h_errno;
SapEventId = NWSAP_EVENT_BIND_FAILED;
IF_DEBUG(INITIALIZATION_ERRORS) {
SS_PRINT(("NWSAP: Error binding to SAP socket: error = %d\n", SapError));
}
return -1;
}
/** Get the bound address and save off the net/node numbers **/
Length = sizeof(SOCKADDR_IPX);
rc = getsockname(SapSocket, (PSOCKADDR)&Bindaddr, &Length);
if (rc == -1) {
SapError = h_errno;
SapEventId = NWSAP_EVENT_GETSOCKNAME_FAILED;
IF_DEBUG(INITIALIZATION_ERRORS) {
SS_PRINT(("NWSAP: Error getting socket name (address): error = %d\n", SapError));
}
return -1;
}
/** **/
IF_DEBUG(INITIALIZATION) {
SS_PRINT(("NWSAP: Bound Address is 0x%02x:0x%02x:0x%02x:0x%02x - 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x - 0x%02x:0x%02x\n",
(UCHAR)Bindaddr.sa_netnum[0],
(UCHAR)Bindaddr.sa_netnum[1],
(UCHAR)Bindaddr.sa_netnum[2],
(UCHAR)Bindaddr.sa_netnum[3],
(UCHAR)Bindaddr.sa_nodenum[0],
(UCHAR)Bindaddr.sa_nodenum[1],
(UCHAR)Bindaddr.sa_nodenum[2],
(UCHAR)Bindaddr.sa_nodenum[3],
(UCHAR)Bindaddr.sa_nodenum[4],
(UCHAR)Bindaddr.sa_nodenum[5],
(UCHAR)*(PUCHAR)&Bindaddr.sa_socket,
(UCHAR)*((PUCHAR)&Bindaddr.sa_socket + 1)));
}
/** Save off the net/node in global variables **/
SAP_COPY_NETNUM(SapNetNum, Bindaddr.sa_netnum);
SAP_COPY_NODENUM(SapNodeNum, Bindaddr.sa_nodenum);
/** Set the extended address option **/
Length = 1;
rc = setsockopt(
SapSocket, /* Socket Handle */
NSPROTO_IPX, /* Option Level */
IPX_EXTENDED_ADDRESS, /* Option Name */
(PUCHAR)&Length, /* Ptr to on/off flag */
sizeof(INT)); /* Length of flag */
if (rc == -1) {
SapError = h_errno;
SapEventId = NWSAP_EVENT_OPTEXTENDEDADDR_FAILED;
IF_DEBUG(INITIALIZATION_ERRORS) {
SS_PRINT(("NWSAP: Error setting EXTENDED ADDRESS option: error = %d\n", SapError));
}
return -1;
}
/** Get the max number of cards there are **/
Length = sizeof(INT);
rc = getsockopt(
SapSocket, /* Socket Handle */
NSPROTO_IPX, /* Option Level */
IPX_MAX_ADAPTER_NUM, /* Option Name */
(PUCHAR)&SapMaxCardIndex, /* Ptr to on/off flag */
&Length); /* Length of flag */
if (rc == -1) {
SapError = h_errno;
SapEventId = NWSAP_EVENT_OPTMAXADAPTERNUM_ERROR;
IF_DEBUG(INITIALIZATION_ERRORS) {
SS_PRINT(("NWSAP: Error getting MAX_ADAPTER_NUM from transport: error = %d\n", SapError));
}
return -1;
}
/** **/
IF_DEBUG(INITIALIZATION) {
SS_PRINT(("NWSAP: Max number of cards from xport = %d\n", SapMaxCardIndex));
}
/** Get the list of cards we have **/
Cardnum = 0;
while (Cardnum != SapMaxCardIndex) {
/** Fill in this entry **/
Addrdata.adapternum = Cardnum;
Length = sizeof(IPX_ADDRESS_DATA);
rc = getsockopt(
SapSocket,
NSPROTO_IPX,
IPX_ADDRESS,
(PCHAR)&Addrdata,
&Length);
/** If error - just skip it **/
if (rc) {
IF_DEBUG(INITIALIZATION_ERRORS) {
SS_PRINT(("NWSAP: Error getting card info: h_errno = %d: Anum = %d\n", h_errno, Cardnum));
}
Cardnum++;
continue;
}
/** If this card not active - skip it **/
if (!Addrdata.status) {
IF_DEBUG(INITIALIZATION_ERRORS) {
SS_PRINT(("NWSAP: Netinit: Card info says card is down: h_errno = %d: Anum = %d\n", h_errno, Cardnum));
}
Cardnum++;
continue;
}
/** If this card already in the list - skip it **/
ACQUIRE_CARDLIST_WRITERS_LOCK(rc, "Cardinit");
Cardptr = SapCardHead;
while (Cardptr) {
if (Cardptr->Number == Addrdata.adapternum)
break;
Cardptr = Cardptr->Next;
}
/**
If we found the card, then it was added by the
WAN notify thread already. Just skip to the next
adapter.
**/
if (Cardptr) {
RELEASE_CARDLIST_WRITERS_LOCK("Cardinit X0");
Cardnum++;
continue;
}
/** Allocate an entry for this card **/
Cardptr = SAP_MALLOC(SAP_CARD_SIZE, "ALLOC CARD");
if (Cardptr == NULL) {
RELEASE_CARDLIST_WRITERS_LOCK("Cardinit X1");
SapError = 0;
SapEventId = NWSAP_EVENT_CARDMALLOC_FAILED;
return -1;
}
/** Fill in the values **/
SAP_COPY_NETNUM(Cardptr->Netnum, Addrdata.netnum);
SAP_COPY_NODENUM(Cardptr->Nodenum, Addrdata.nodenum);
Cardptr->Linkspeed = Addrdata.linkspeed;
Cardptr->Wanflag = Addrdata.wan;
Cardptr->Maxpkt = Addrdata.maxpkt;
Cardptr->Number = Cardnum;
Cardptr->ReqCount = 0;
/** For building with **/
Cardptr->Plist.Curnum = 0;
Cardptr->Plist.Curpkt = NULL;
Cardptr->Plist.Curptr = NULL;
Cardptr->Plist.PktHead = NULL;
Cardptr->Plist.PktTail = NULL;
Cardptr->Plist.NumPkts = 0;
/** **/
#if DBG
IF_DEBUG(INITIALIZATION) {
SS_PRINT(("Card %d\n", Cardnum));
SapDumpMem(Cardptr->Netnum, 10, "NET/NODE");
}
#endif
/** Put this entry on the end of the list **/
Cardptr->Next = NULL;
if (SapCardHead)
SapCardTail->Next = Cardptr;
else
SapCardHead = Cardptr;
SapCardTail = Cardptr;
SapNumCards++;
RELEASE_CARDLIST_WRITERS_LOCK("Cardinit X2");
/** Goto the next card number **/
Cardnum++;
}
/**
If there are no cards, that is OK. We allow that because
if all we have is a WAN adapter that is not up yet, then
we will come up later when the WAN adapter comes up.
**/
/** Initialization is OK **/
return 0;
}
/*++
*******************************************************************
S a p N e t w o r k S h u t d o w n
Routine Description:
When we are terminating, this routine will clean
up everything.
Arguments:
None
Return Value:
Nothing
*******************************************************************
--*/
VOID
SapNetworkShutdown(
VOID)
{
PSAP_CARD Cardptr;
PSAP_CARD NCardptr;
/** Free the card list **/
Cardptr = SapCardHead;
while (Cardptr) {
NCardptr = Cardptr->Next;
SAP_FREE(Cardptr, "CARD NET SHUTDOWN");
Cardptr = NCardptr;
}
/** All Done **/
return;
}
/*++
*******************************************************************
S a p S e n d P a c k e t s
Routine Description:
This routine sends a SAP advertise for all servers
needing one.
Arguments:
Flag = 0 - This is from SendThread
1 - This is from SapAddAdvertise
2 - Shutting down - send all with HOP = 16.
Return Value:
0 = OK
Else = Error
*******************************************************************
--*/
INT
SapSendPackets(
INT Flag)
{
PSAP_RECORD Entry;
PSAP_RECORD NextEntry;
PSAP_RECORD HeadEntry;
PSAP_RECORD NextHeadEntry;
SAP_RECORD Myentry;
PSAP_SERVER Servp;
PSAP_SERVER Nextp;
PSAP_SERVER Backp;
PSAP_CARD Cardptr;
PSAP_PKTENTRY Pktp;
PSAP_PKTENTRY NPktp;
INT rc;
BOOL doit;
UCHAR DestAddr[SAP_ADDRESS_LENGTH];
/**
If we are already in here, then we need to mark that
we caught ourselves here and leave.
We will save who called us. If we already have saved
off a call from the main advertise thread or the
cleanup code, then we will not overwrite that.
**/
ACQUIRE_SENDBUSY_LOCK();
if (SapSendPacketsBusy) {
if (SapAgainFlag == -1)
SapAgainFlag = Flag; /* Save who called in */
else if (SapAgainFlag == 1)
SapAgainFlag= Flag;
RELEASE_SENDBUSY_LOCK();
return 0;
}
SapSendPacketsBusy = 1;
SapAgainFlag = -1;
RELEASE_SENDBUSY_LOCK();
/** **/
send_again:
ACQUIRE_CARDLIST_READERS_LOCK("SapSendPackets");
/** Lock the server send table **/
ACQUIRE_SENDTABLE_LOCK();
/** Send all the packets we need to **/
Servp = SapServHead;
/**
Go thru the list and build all that we can.
We also update these in the database to make sure that
we don't timeout our internal entries.
**/
Backp = NULL;
while (Servp) {
/** If from shutdown set hop to 16 now **/
if (Flag == 2)
Servp->Hopcount = htons(16);
/** Go add this entry for all cards **/
Nextp = Servp->Next;
/** Figure whether to do this entry or not **/
if (Flag == 1) {
if (Servp->Changed)
doit = TRUE;
else
doit = FALSE;
}
else
doit = TRUE;
/**
If we should do it this entry, then add it to the list.
BUT check the filters first.
**/
if (doit) {
/** Go send it for all cards **/
Cardptr = SapCardHead;
while (Cardptr) {
/**
Check the filter here. If we should
advertise this entry or not. We do not
check the name since this is an internal server
and we must advertise for it. BUT we do check
for WAN filtering.
**/
if (Cardptr->Wanflag) {
doit = SapShouldIAdvertiseByCard(
Cardptr,
Servp->Changed);
}
else
doit = TRUE;
/** Copy this to an entry **/
if (doit) {
SAP_COPY_SERVNAME(Myentry.ServName, Servp->ServerName);
Myentry.ServType = ntohs(Servp->ServerType);
Myentry.HopCount = ntohs(Servp->Hopcount);
SAP_COPY_ADDRESS(Myentry.ServAddress, Servp->Address);
/** Add this entry to the send list **/
SapAddSendEntry(&Myentry, &Cardptr->Plist, 0);
}
/** Goto the next card entry **/
Cardptr = Cardptr->Next;
}
}
/** This entry not changed anymore **/
Servp->Changed = FALSE;
/** Update this entry in the database **/
SdmdUpdateEntry(
Servp->ServerName, /* Server name */
ntohs(Servp->ServerType), /* Server Type */
Servp->Address, /* Server Address */
ntohs(Servp->Hopcount), /* Server Hopcount */
CARDRET_MYSELF, /* Card number */
SapZeros, /* My address (don't care)*/
FALSE);
/**
If going away - delete the entry from the
advertise list.
**/
if (Servp->Hopcount == htons(16)) {
/** Take this entry out of the list **/
if (Backp)
Backp->Next = Nextp;
else
SapServHead = Nextp;
if (Servp == SapServTail)
SapServTail = Backp;
/** Free this entry **/
SAP_FREE(Servp, "Advertised deleted adv srv and deleted");
}
else {
/** Save ptr to this entry as back entry **/
Backp = Servp;
}
/** Goto the next entry **/
Servp = Nextp;
}
/** Release the server send table **/
RELEASE_SENDTABLE_LOCK();
/**
Now we need to add all the SAP's that are on different nets.
For each card we need to advertise SAP's that came in
on other cards.
We only send the actual packets if there is more then 1 card.
If there is only 1 card - we go thru so we can delete servers
that have gone away.
**/
/** Lock the database **/
ACQUIRE_WRITERS_LOCK(rc,"Send Packets");
if (rc) {
IF_DEBUG(ERRORS) {
SS_PRINT(("NWSAP: SendPackets: Error getting writers lock\n"));
}
goto send_the_packets; /* Error on get writers lock */
}
/** Get ptr to the head of the type list **/
HeadEntry = GETPTRFROMINDEX(SdmdLists[SAP_TYPELIST_INDEX].Flink);
while (HeadEntry && (HeadEntry->ServType != 0xFFFF)) {
/** Save ptr to next head entry **/
NextHeadEntry = GETPTRFROMINDEX(HeadEntry->Links[SAP_TYPELIST_INDEX].Flink);
/** Go thru this sublist **/
Entry = GETPTRFROMINDEX(HeadEntry->Links[SAP_SUBLIST_INDEX].Flink);
while (Entry) {
/** If from shutdown - set hopcount now to 16 **/
if (Flag == 2)
Entry->HopCount = 16;
/** If internal or only one card - skip it **/
if ((Entry->Internal) || (SapNumCards == 1))
goto do_next_entry;
/** Figure whether to do this entry or not **/
if (Flag == 1)
doit = Entry->Changed;
else
doit = TRUE;
/**
If we have decided to advertise this server, then
check the filter table to see if we can. We
check the WAN flags later on.
**/
if (doit) {
doit = SapShouldIAdvertiseByName(Entry->ServName);
}
/**
If this is from advertise or update, only send
ones that are changed.
**/
if (doit) {
/** Go add this entry for all cards **/
Cardptr = SapCardHead;
while (Cardptr) {
/**
Never advertise on same card as this
came to us from.
**/
if (Entry->CardNumber == Cardptr->Number) {
Cardptr = Cardptr->Next;
continue;
}
/**
If this is a WAN adapter - then check
the name to see if we should send advertisments
across the WAN or not.
Check the filter for this server as to
whether we should advertise this one or not.
We have already checked the name, we just
check the WAN status now.
**/
if (Cardptr->Wanflag) {
doit = SapShouldIAdvertiseByCard(
Cardptr,
Entry->Changed);
}
else {
/** This is a LAN card we are sending on **/
/**
We have 4 cases at advertise time:
1. Advertise came on a LAN - Sending to a WAN
2. Advertise came on a LAN - Sending to a LAN
3. Advertise came on a WAN - Sending on a WAN
4. Advertise came on a WAN - Sending on a LAN
Cases 1,3,4 are always OK. But case 2 is special
in that if the IPX layer is not a router here then
we might advertise a server across to a different
card that there is no route to.
SapDontHopLans is TRUE if we should not advertise
in the case 2.
If this is entry NOT from a wan and we don't
hop lan entries - do not advertise this entry.
**/
if ((!Entry->FromWan) && (SapDontHopLans))
doit = FALSE;
else
doit = TRUE;
}
/** If not for this card - add it in **/
if (doit) {
SapAddSendEntry(Entry, &Cardptr->Plist, 1);
}
/** Goto the next card entry **/
Cardptr = Cardptr->Next;
}
}
/** This entry is updated now **/
do_next_entry:
Entry->Changed = FALSE;
/** Get ptr to the next entry **/
NextEntry = GETPTRFROMINDEX(Entry->Links[SAP_SUBLIST_INDEX].Flink);
/** If this entry is gone - toss it now **/
if (Entry->HopCount == 16)
SdmdFreeEntry(Entry);
/** Goto the next entry **/
Entry = NextEntry;
}
/** Goto the next type **/
HeadEntry = NextHeadEntry;
}
/** We can release the lock now **/
RELEASE_WRITERS_LOCK("Send Packets X1");
/**
Now we have built all the packets. We need to send all the
packets. Each card has a list of packets to send.
**/
send_the_packets:
Cardptr = SapCardHead;
while (Cardptr) {
/** If we have a partial - finish it up **/
if (Cardptr->Plist.Curnum) {
/** Add this packet to the list **/
if (Cardptr->Plist.PktHead)
Cardptr->Plist.PktTail->Next = Cardptr->Plist.Curpkt;
else
Cardptr->Plist.PktHead = Cardptr->Plist.Curpkt;
Cardptr->Plist.PktTail = Cardptr->Plist.Curpkt;
Cardptr->Plist.NumPkts++;
}
/** Set the network number **/
memcpy(DestAddr, SapBroadcastAddress, SAP_ADDRESS_LENGTH);
SAP_COPY_NETNUM(DestAddr+2, Cardptr->Netnum);
/** Go send all the packets **/
Pktp = Cardptr->Plist.PktHead;
/** Reset all for next time **/
Cardptr->Plist.PktHead = NULL;
Cardptr->Plist.PktTail = NULL;
Cardptr->Plist.Curnum = 0;
Cardptr->Plist.Curptr = NULL;
Cardptr->Plist.Curpkt = NULL;
/** Send this packet **/
while (Pktp) {
/** Get ptr to next packet and get send length **/
NPktp = Pktp->Next;
/** Send the packet **/
rc = sendto(
SapSocket,
(PVOID)(Pktp->Buffer),
Pktp->SendLength,
0,
(PSOCKADDR)DestAddr,
SapBroadcastAddressLength);
/** Check for errors **/
if (rc == -1) {
IF_DEBUG(ERRORS) {
SS_PRINT(("SENDPACKETS: Error sending SAP: h_errno = %d\n", h_errno));
}
}
/** Free this packet **/
SAP_FREE(Pktp, "Sent Packet for Card");
/**
If there are more - insert delay here. We do not
check for starting other worker threads, because we
are never called from a worker thread here.
**/
if (NPktp) {
NWSAP_SEND_DELAY();
}
/** Goto the next packet **/
Pktp = NPktp;
}
/** Goto the next card entry **/
Cardptr = Cardptr->Next;
}
RELEASE_CARDLIST_READERS_LOCK("SapSendPackets");
/**
Check if we were called while we were in here
**/
ACQUIRE_SENDBUSY_LOCK();
if (SapAgainFlag != -1) {
Flag = SapAgainFlag;
SapAgainFlag = -1; /* Mark not here again */
/** If from main send - go send again **/
if (Flag == 0) {
RELEASE_SENDBUSY_LOCK();
goto send_again;
}
/** If from advertise - just mark changed **/
if (Flag == 1)
SapChanged = 1;
/** Else it is OK to leave **/
}
/** We are OK to leave **/
SapSendPacketsBusy = 0;
RELEASE_SENDBUSY_LOCK();
/** All Done **/
return 0;
}
/*++
*******************************************************************
S a p S e n d F o r T y p e s
Routine Description:
This routine will find all servers of the given type (0xFFFF
means all types) and send the records for all matching servers
to the remote address given.
Arguments:
ServerType = Type of server to send for (0xFFFF = all)
RemoteAddress = Address to send to
RemoteAddressLength = Length of the Remote Address
Cardnum = Card number request was received on
CARDRET_INTERNAL = 0xFF = We got this
request from an internal process. We
should only respond for services that are
local on this machine.
Bcast = 0 = Unicast request packet
Else = Broadcast request packet
WanFlag = TRUE = Card recv'd from is WAN
FALSE = Card recv'd from is LAN
Return Value:
0 = OK
Else = Terminate this worker thread
*******************************************************************
--*/
INT
SapSendForTypes(
USHORT ServerType,
PUCHAR RemoteAddress,
INT RemoteAddressLength,
INT Cardnum,
UCHAR Bcast,
BOOL WanFlag)
{
INT rc;
PSAP_RECORD Entry;
PSAP_RECORD HeadEntry;
SAP_PKTLIST Plist;
PSAP_PKTENTRY Pktp;
PSAP_PKTENTRY NPktp;
BOOL doit;
BOOL started_new_worker;
/** Zero out the plist **/
memset(&Plist, 0, sizeof(SAP_PKTLIST));
/** Find the server type we want **/
ACQUIRE_READERS_LOCK("Send For Types A1");
/**
Get a pointer to the first entry in the typelist. If
this is for wildcards, then this is the entry we want.
If not for wildcards, then find the first type that this is for.
If not found - just leave.
**/
HeadEntry = GETPTRFROMINDEX(SdmdLists[SAP_TYPELIST_INDEX].Flink);
if (ServerType != 0xFFFF) {
while (HeadEntry && (HeadEntry->ServType < ServerType)) {
HeadEntry = GETPTRFROMINDEX(HeadEntry->Links[SAP_TYPELIST_INDEX].Flink);
}
}
/**
Go build all the entries we can.
**/
while (HeadEntry) {
/** If we are into the free entries - bail out **/
if (HeadEntry->ServType == 0xFFFF)
break;
/**
If not for wildcards and it is another kind of server
type - then bail out.
**/
if (ServerType != 0xFFFF) {
if (HeadEntry->ServType != ServerType)
break;
}
/**
We have an entry we might want to send back. If the
service for this entry is on the same network as the
machine that made this request - do not send it back.
It will respond for itself.
If this request was made by a process on this local machine,
then we should only respond for internal servers. But if the
request was unicast - then we need to send for ALL servers.
OTHERWISE - Build the entry into the packet.
**/
Entry = GETPTRFROMINDEX(HeadEntry->Links[SAP_SUBLIST_INDEX].Flink);
while (Entry) {
/** **/
doit = FALSE;
if (Cardnum == CARDRET_INTERNAL) {
if (!Bcast)
doit = TRUE;
else if (Entry->Internal)
doit = TRUE; /* Bcast = respond for internal srvs only */
}
else {
/**
If entry is an internal server - return it. If not
then we need only send back for services that are
on different cards from where the request came.
BUT if the request is unicast - always send back
everything.
**/
if (!Bcast)
doit = TRUE;
else if (Entry->Internal)
doit = TRUE;
else if (Entry->CardNumber != Cardnum)
doit = TRUE;
/**
If this server is NOT internal to us AND the
request is from a LAN card AND this entry is
a LAN entry AND we do not do LAN-LAN routing -
then do not send this entry if the request
came in on a different card then the server
advertised us on.
**/
if (SapDontHopLans &&
(!Entry->Internal) && /* Entry not internal */
(!Entry->FromWan) && /* Entry from LAN card */
(Entry->CardNumber != Cardnum) &&
(!WanFlag)) { /* Request from a LAN card */
doit = FALSE;
}
}
/** Add the entry to the list if we need to **/
if (doit) {
/**
Check the name to see if we can send this
name. The WAN status does not matter
because this is a response.
**/
doit = SapShouldIAdvertiseByName(Entry->ServName);
/** Add the entry **/
if (doit) {
if (SapAddSendEntry(Entry, &Plist, 0))
break;
}
}
/** Get ptr to the next entry **/
Entry = GETPTRFROMINDEX(Entry->Links[SAP_SUBLIST_INDEX].Flink);
}
/** Goto the next head entry **/
HeadEntry = GETPTRFROMINDEX(HeadEntry->Links[SAP_TYPELIST_INDEX].Flink);
}
/** We can release the lock now **/
RELEASE_READERS_LOCK("Send For Types X2");
/**
If we have a partial packet - finish it
up now.
**/
if (Plist.Curnum) {
/** Add this packet to the list **/
if (Plist.PktHead)
Plist.PktTail->Next = Plist.Curpkt;
else
Plist.PktHead = Plist.Curpkt;
Plist.PktTail = Plist.Curpkt;
Plist.NumPkts++;
}
/**
We are now ready to send packets to the client that requested
them. If there is more the one packet, then I am going to delay
55 ms between each packet.
In order not to clog myself up, I check here to see
if there is someone else waiting on the worker queue. If not, then
I startup a new worker thread. When I get done, I will check to
see if I need to kill myself.
**/
started_new_worker = 0;
if (Plist.NumPkts > 1) {
/** If no other threads are waiting - start a new worker **/
if (SapWorkerThreadWaiting == 0) {
if (!SapStartWorkerThread()) {
started_new_worker = 1; /* We started a new one */
}
}
}
/** Go send all the packets **/
Pktp = Plist.PktHead;
/** Send this packet **/
//
// If we need to delay responding to General Service Request, do
// so here but only if the client is not asking for all services
// since this is probably a router coming up and asking us to dump
// our sap table.
//
if ( (Pktp != NULL) &&
(ServerType != 0xFFFF) &&
(SapDelayRespondToGeneral > 0) ) {
Sleep( SapDelayRespondToGeneral );
}
while (Pktp) {
/** Get ptr to next packet and get send length **/
NPktp = Pktp->Next;
/** Send the packet **/
rc = sendto(
SapSocket,
(PVOID)(Pktp->Buffer),
Pktp->SendLength,
0,
(PSOCKADDR)RemoteAddress,
RemoteAddressLength);
/** Check for errors **/
if (rc == -1) {
IF_DEBUG(ERRORS) {
SS_PRINT(("NWSAP: SENDFORTYPES: Error sending SAP: h_errno = %d\n", h_errno));
}
}
/** Free this packet **/
SAP_FREE(Pktp, "SendforTypes pkt release");
/**
If there are more - insert delay here.
**/
if (NPktp) {
NWSAP_SEND_DELAY();
}
/** Goto the next packet **/
Pktp = NPktp;
}
/**
If we started a new worker, then check if any other
worker threads are waiting on the worker queue. If so, kill
my thread now. If not, then just return back to keep going.
**/
if (started_new_worker) {
if (SapWorkerThreadWaiting != 0) {
return -1; /* Terminate this thread */
}
}
/** Return nothing to send back **/
return 0;
}
/*++
*******************************************************************
S a p S e n d G e n e r a l R e q u e s t
Routine Description:
This routine send a general request to broadcast.
Arguments:
Flag = 0 - This is from SendThread
1 - This is from SapAddAdvertise
NetNum = Ptr to 4 byte network number to send to
(NULL = Send to all local nets)
Return Value:
0 = OK
Else = Error
*******************************************************************
--*/
INT
SapSendGeneralRequest(
INT Flag,
PUCHAR NetNum)
{
INT rc;
INT SendLength;
SAP_REQUEST SendBuffer;
UCHAR DestAddr[SAP_ADDRESS_LENGTH];
/** Build the packet **/
SendBuffer.QueryType = htons(SAPTYPE_GENERAL_SERVICE_QUERY);
SendBuffer.ServerType = 0xFFFF; /* All types */
SendLength = SAP_REQUEST_SIZE;
/** Set the address to send to **/
memcpy(DestAddr, SapBroadcastAddress, SAP_ADDRESS_LENGTH);
if (NetNum) {
SAP_COPY_NETNUM(DestAddr+2, NetNum);
}
/**
Set the card init done to 1 here so that
as the WAN NOTIFY comes back, we will need to
process the calls.
**/
SapCardInitDone = 1;
/**
HACK for getting receive threads to stop. Send a packet
to myself.
**/
if (Flag) {
SAP_COPY_NETNUM(DestAddr+2, SapNetNum);
SAP_COPY_NODENUM(DestAddr+6, SapNodeNum);
}
/** Send this packet **/
rc = sendto(
SapSocket,
(PVOID)&SendBuffer,
SendLength,
0,
(PSOCKADDR)DestAddr,
SapBroadcastAddressLength);
/** Check for errors **/
if (rc == -1) {
IF_DEBUG(ERRORS) {
SS_PRINT(("SENDGENERAL: Error sending packet: h_errno = %d\n", h_errno));
}
}
/** All Done **/
return rc;
}
/*++
*******************************************************************
S a p A d d S e n d E n t r y
Routine Description:
Add an entry to the send list of a card. This will
allocate a new buffer if necessary.
Arguments:
Entry = Ptr to SAP_RECORD that shows entry to add
Plist = Ptr to packet list structure to use
HopInc = Amount to add to HopCount for this entry
Return Value:
0 = OK
Else = Error
*******************************************************************
--*/
INT
SapAddSendEntry(
PSAP_RECORD Entry,
PSAP_PKTLIST Plist,
USHORT HopInc)
{
PSAP_HEADER Hdrp;
PSAP_PKTENTRY Pktp;
/**
If the max number of entries are in this packet, then
we need to add this packet to the list.
**/
if (Plist->Curnum == 7) {
/** Add this packet to the list **/
if (Plist->PktHead)
Plist->PktTail->Next = Plist->Curpkt;
else
Plist->PktHead = Plist->Curpkt;
Plist->PktTail = Plist->Curpkt;
Plist->NumPkts++; /* Count this one */
/** Reset current packet stuff **/
Plist->Curpkt = NULL;
Plist->Curnum = 0;
}
/** If no current buffer - make one **/
Pktp = Plist->Curpkt;
if (Pktp == NULL) {
/**
Allocate a new buffer. We add 8 bytes to the buffer
as a header. The first 4 bytes are a forward pointer
to link up the buffers. The next 4 bytes are a length
holder to tell how much data is in the packet.
**/
Pktp = (PSAP_PKTENTRY)SAP_MALLOC(SAP_PKTENTRY_SIZE+SAP_MAX_SENDLEN, "AddSendEntry");
if (Pktp == NULL) {
IF_DEBUG(ERRORS) {
SS_PRINT(("SAP: Alloc failed for %d bytes in AddSendEntry\n", SAP_MAX_SENDLEN + 8));
}
return 1;
}
/** Init the pointers **/
Pktp->Next = NULL;
Pktp->SendLength = 2; /* Length of service response cmd code */
Plist->Curpkt = Pktp;
Plist->Curnum = 0;
Plist->Curptr = Pktp->Buffer;
/** Set the command code = service response **/
*Plist->Curptr++ = 0x00;
*Plist->Curptr++ = SAPTYPE_GENERAL_SERVICE_RESPONSE;
}
/** Add this entry **/
Hdrp = (PSAP_HEADER)Plist->Curptr;
Hdrp->ServerType = htons(Entry->ServType);
if (Entry->HopCount == 16)
Hdrp->Hopcount = htons(Entry->HopCount);
else
Hdrp->Hopcount = htons((USHORT)(Entry->HopCount + HopInc));
SAP_COPY_ADDRESS(Hdrp->Address, Entry->ServAddress);
SAP_COPY_SERVNAME(Hdrp->ServerName, Entry->ServName);
/** Bump up the pointers **/
Plist->Curptr += SAP_HEADER_SIZE;
Plist->Curnum++;
Pktp->SendLength += SAP_HEADER_SIZE;
/** All OK **/
return 0;
}
/*++
*******************************************************************
S a p G e t D e l a y T i m e
Routine Description:
This routine gets the RIP delay time for a given network
from the NWLink driver.
Arguments:
Netnum = Ptr to 4 byte network number to get delay time for
Return Value:
The delay time
0xFFFF = Invalid network number
*******************************************************************
--*/
USHORT
SapGetDelayTime(
PUCHAR Netnum)
{
IPX_NETNUM_DATA Netdata;
INT rc;
INT Length;
/** Fill out to get the info on this netnum from NWLink **/
memcpy(Netdata.netnum, Netnum, 4);
Length = sizeof(IPX_NETNUM_DATA);
/** Get the info **/
rc = getsockopt(
SapSocket,
NSPROTO_IPX,
IPX_GETNETINFO_NORIP,
(PCHAR)&Netdata,
&Length);
/** If error - return it **/
if (rc)
return 0xFFFF;
/** Return the result **/
return Netdata.netdelay;
}
/*++
*******************************************************************
S a p C l e a n u p D o w n e d C a r d
Routine Description:
A certain card number has gone down. We need to cleanup
everything about that card from the list. The card has already
been deleted from the card list when we get here.
Arguments:
Cardnum = Number of the card that died.
Return Value:
Nothing
*******************************************************************
--*/
VOID
SapCleanupDownedCard(
INT Cardnum)
{
PSAP_RECORD Entry;
PSAP_RECORD NextEntry;
PSAP_RECORD HeadEntry;
PSAP_RECORD NextHeadEntry;
INT rc;
/**
We need to hold the readers lock here so that as cards
come up and go down. If one goes down with a certain
adapter number and while we are cleaning it up, we have
another come up with the same number, we could get
confused. This will keep this from happening.
**/
ACQUIRE_CARDLIST_READERS_LOCK("SapCleanupDownedCard Entry");
/**
Now we need to add all the SAP's that are on different nets.
For each card we need to advertise SAP's that came in
on other cards.
We only send the actual packets if there is more then 1 card.
If there is only 1 card - we go thru so we can delete servers
that have gone away.
**/
/** Lock the database **/
ACQUIRE_WRITERS_LOCK(rc,"Cleanup Downed Card");
if (rc) {
RELEASE_CARDLIST_READERS_LOCK("SapCleanupDownedCard X1");
IF_DEBUG(ERRORS) {
SS_PRINT(("NWSAP: CleanupDownedCard: Error getting writers lock\n"));
}
return;
}
/** Get ptr to the head of the type list **/
HeadEntry = GETPTRFROMINDEX(SdmdLists[SAP_TYPELIST_INDEX].Flink);
while (HeadEntry && (HeadEntry->ServType != 0xFFFF)) {
/** Save ptr to next head entry **/
NextHeadEntry = GETPTRFROMINDEX(HeadEntry->Links[SAP_TYPELIST_INDEX].Flink);
/** Go thru this sublist **/
Entry = GETPTRFROMINDEX(HeadEntry->Links[SAP_SUBLIST_INDEX].Flink);
while (Entry) {
/** If for card that went down - mark it **/
if ((Entry->CardNumber == Cardnum) &&
(!Entry->Internal)) {
Entry->HopCount = 16;
Entry->Changed = TRUE;
SapChanged = TRUE;
}
/** Get ptr to the next entry **/
NextEntry = GETPTRFROMINDEX(Entry->Links[SAP_SUBLIST_INDEX].Flink);
/** Goto the next entry **/
Entry = NextEntry;
}
/** Goto the next type **/
HeadEntry = NextHeadEntry;
}
/** We can release the lock now **/
RELEASE_WRITERS_LOCK("Send Packets X1");
RELEASE_CARDLIST_READERS_LOCK("SapCleanupDownedCard X2");
/** All Done **/
return;
}
/*++
*******************************************************************
S a p U p d a t e C a r d N e t w o r k N u m b e r s
Routine Description:
The main thread will call here every minute ONLY if we
have adapters that have a network number of zero. This is
used to check if those adapters have detected a network number
Arguments:
None
Return Value:
Nothing
*******************************************************************
--*/
VOID
SapUpdateCardNetworkNumbers(
VOID)
{
PSAP_CARD Cardptr;
INT Retcode;
INT Length;
IPX_ADDRESS_DATA Addrdata;
/** Lock the cardlist so we can check everything **/
ACQUIRE_CARDLIST_WRITERS_LOCK(Retcode, "SapUpdateCardNetworkNumbers");
/**
Go thru the list of adapters to see if any have a network number
of zero. If any of them do, then query IPX to see if it has changed
to non-zero.
**/
Cardptr = SapCardHead;
while (Cardptr) {
/** If this card has netnum = 0 - ask IPX **/
if (!memcmp(Cardptr->Netnum, SapZeros, SAP_NET_LEN)) {
/** Fill in this entry **/
Addrdata.adapternum = Cardptr->Number;
Length = sizeof(IPX_ADDRESS_DATA);
Retcode = getsockopt(
SapSocket,
NSPROTO_IPX,
IPX_ADDRESS,
(PCHAR)&Addrdata,
&Length);
/** If ok - set the new network number **/
if (Retcode == 0) {
SAP_COPY_NETNUM(Cardptr->Netnum, Addrdata.netnum);
}
}
/** Goto the next card **/
Cardptr = Cardptr->Next;
}
/** Release the lock on the list now **/
RELEASE_CARDLIST_WRITERS_LOCK("SapUpdateCardNetworkNumbers");
/** All Done **/
return;
}