📄 irdatdi.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*****************************************************************************
*
*
*
* @doc
* @module irdatdi.c | IrDA stack interface to TDI
*
* 11/11/1997
* - Modified for new irdastk. New locking stategy.
* Everything else is same.
*
* 3/16/1998
* - Modified to used handles instead of pointers with
* AFD (AFD can call in to close connections at any
* time. We need to make sure that we ref count and
* not to delete any connection objects in use.)
*
* see AFD\peginit.c
*
* Locking Strategy:
* Lock TDI connection objects while using.
* Lock TDI address objects while using.
* (Lock connection objects before address objects).
* Don't call into IrLMP with locks held.
* IrLmp locks the LMP link control blocks.
*
* There is a specific lock for discoveries.
* There is a specific lock for IAS queries.
* There is a specific lock for manipulating object lists.
*
*/
#include "irdatdi.h"
#ifdef DEBUG
TCHAR *szIrlmpConnState[] = {
TEXT("CONN_CREATED"),
TEXT("CONN_CLOSING"),
TEXT("CONN_OPENING"),
TEXT("CONN_OPEN")
};
#define DUMP_RECVLIST(debugzone, pConn) if (debugzone) DumpRecvList(pConn)
void
DumpRecvList(PIRLMP_CONNECTION pConn)
{
PIRDATDI_RECV_BUFF pRecv;
PLIST_ENTRY pRecvEntry;
if (IsListEmpty(&pConn->RecvBuffList) == TRUE)
{
DEBUGMSG(1, (TEXT("*** IrTdi: No recv buffers are queued.\r\n")));
return;
}
DEBUGMSG(1, (TEXT("*** IrTdi: Queued recv buffers:\r\n")));
for (pRecvEntry = pConn->RecvBuffList.Flink;
pRecvEntry != &pConn->RecvBuffList;
pRecvEntry = pRecvEntry->Flink)
{
pRecv = (PIRDATDI_RECV_BUFF)pRecvEntry;
DEBUGMSG(1,
(TEXT(" %d B [%#x] %s\r\n"),
pRecv->DataLen,
pRecv->pRead,
pRecv->FinalSeg == TRUE ? TEXT("F") : TEXT("")));
}
return;
}
#define DUMP_OBJECTS(debugzone) if (debugzone) DumpObjects()
void
DumpObjects()
{
PIRLMP_ADDR_OBJ pAddr;
PIRLMP_CONNECTION pConn;
PLIST_ENTRY pAddrEntry, pConnEntry;
EnterCriticalSection(&csIrObjList);
DEBUGMSG(1,
(TEXT("*** Dump Address and Connection Objects: %s\r\n"),
(!IsListEmpty(&IrAddrObjList) && !IsListEmpty(&IrConnObjList)) ?
TEXT("NO ADDR or CONN objects.") : TEXT("")));
for (pAddrEntry = IrAddrObjList.Flink;
pAddrEntry != &IrAddrObjList;
pAddrEntry = pAddrEntry->Flink)
{
pAddr = (PIRLMP_ADDR_OBJ)pAddrEntry;
VALIDADDR(pAddr);
if (pAddr) {
GET_ADDR_LOCK(pAddr);
DEBUGMSG(1,
(TEXT(" AddrObj:%#x (%d) RefCnt: %d Loc:\"%hs\",%d Next:%#x\r\n"),
pAddr, pAddr->dwId, pAddr->cRefs,
pAddr->SockAddrLocal.irdaServiceName,
pAddr->LSAPSelLocal,
pAddrEntry->Flink != &IrAddrObjList ? pAddrEntry->Flink : NULL));
for (pConnEntry = pAddr->ConnList.Flink;
pConnEntry != &pAddr->ConnList;
pConnEntry = pConnEntry->Flink)
{
pConn = (PIRLMP_CONNECTION)pConnEntry;
VALIDCONN(pConn);
DEBUGMSG(1,
(TEXT(" ConnObj:%#x (%d) Ref: %d Loc:\"%hs\",%d Rem:\"%hs\",%d ")
TEXT("State:%s (%d) AddrObj:%#x Next:%#x\r\n"),
pConn, pConn->dwId, pConn->cRefs,
pConn->SockAddrLocal.irdaServiceName,
pConn->LSAPSelLocal,
pConn->SockAddrRemote.irdaServiceName,
pConn->LSAPSelRemote,
szIrlmpConnState[pConn->ConnState], pConn->ConnState,
pConn->pAddrObj,
pConnEntry->Flink != &pAddr->ConnList ? pConnEntry->Flink : NULL));
}
FREE_ADDR_LOCK(pAddr);
} else {
ASSERT(0); // list is corrupt
break;
}
}
if (!IsListEmpty(&IrConnObjList))
{
DEBUGMSG(1,
(TEXT(" Unassociated Connection Objects:\r\n")));
for (pConnEntry = IrConnObjList.Flink;
pConnEntry != &IrConnObjList;
pConnEntry = pConnEntry->Flink)
{
pConn = (PIRLMP_CONNECTION)pConnEntry;
VALIDCONN(pConn);
DEBUGMSG(1,
(TEXT(" ConnObj:%#x (%d) Ref: %d Loc:\"%hs\",%d Rem:\"%hs\",%d ")
TEXT("State:%s (%d) AddrObj:%#x pNext:%#x\r\n"),
pConn, pConn->dwId, pConn->cRefs,
pConn->SockAddrLocal.irdaServiceName,
pConn->LSAPSelLocal,
pConn->SockAddrRemote.irdaServiceName,
pConn->LSAPSelRemote,
szIrlmpConnState[pConn->ConnState], pConn->ConnState,
pConn->pAddrObj,
pConnEntry->Flink != &IrConnObjList ? pConnEntry->Flink : NULL));
}
}
LeaveCriticalSection(&csIrObjList);
return;
}
#else
#define DUMP_OBJECTS(debugzone) ((void)0)
#define DUMP_RECVLIST(debugzone, pConn) ((void)0)
#endif
//
// For sockets which are not bound to a service name - we will assign a
// hard coded LSAP-SEL. We will store this in the irdaServiceName of the
// sockaddr.
//
VOID
SetLsapSelAddr(
int LsapSel,
CHAR *ServiceName)
{
int Digit, i;
int StrLen = 0;
CHAR Str[4];
while (LsapSel > 0 && StrLen < 3)
{
Digit = LsapSel % 10;
LsapSel = LsapSel / 10;
Str[StrLen] = Digit + '0';
StrLen++;
}
RtlCopyMemory(ServiceName, LSAPSEL_TXT, LSAPSEL_TXTLEN);
for (i = 0; i < StrLen; i++)
{
ServiceName[i + LSAPSEL_TXTLEN] = Str[StrLen - 1 - i];
}
ServiceName[StrLen + LSAPSEL_TXTLEN] = 0;
}
#define IRDA_MIN_LSAP_SEL 1
#define IRDA_MAX_LSAP_SEL 127
int
ParseLsapSel(CHAR *pszDigits)
{
int LsapSel = 0;
int i;
for (i = 0; i < 3; i++)
{
if (pszDigits[i] == 0)
break;
// Only real digits are valid.
if ((pszDigits[i] < '0') || (pszDigits[i] > '9'))
return (-1);
// Calculate LSAP-SEL.
LsapSel = (LsapSel * 10) + (pszDigits[i] - '0');
}
// Greater than 4 characters, < 1, > 127 are all invalid LSAP-SELs.
if ((pszDigits[i] != 0) ||
(LsapSel < IRDA_MIN_LSAP_SEL) ||
(LsapSel > IRDA_MAX_LSAP_SEL))
{
return (-1);
}
return (LsapSel);
}
__inline BOOL
IsLsapSelUsed(int LsapSel)
{
PLIST_ENTRY pAddrEntry;
// Assumes AddrObjList lock is held.
// sh - We have hardcoded our IAS Lsap Sel as 3. Therefore, don't let 'em
// use it.
if (LsapSel == 3 /*IAS_LOCAL_LSAP_SEL*/)
{
return (TRUE);
}
for (pAddrEntry = IrAddrObjList.Flink;
pAddrEntry != &IrAddrObjList;
pAddrEntry = pAddrEntry->Flink)
{
if (((PIRLMP_ADDR_OBJ)pAddrEntry)->LSAPSelLocal == LsapSel)
{
return (TRUE);
}
}
return (FALSE);
}
int
GetUnusedLsapSel()
{
int LsapSel;
// Assumes AddrObjList lock is held.
for (LsapSel = IRDA_MIN_LSAP_SEL; LsapSel <= IRDA_MAX_LSAP_SEL; LsapSel++)
{
if (IsLsapSelUsed(LsapSel) == FALSE)
{
return (LsapSel);
}
}
return -1;
}
/*****************************************************************************
*
* @func TDI_STATUS | IRLMP_OpenAddress |
* Called after bind(). Allocates a new IRLMP_ADDR_OBJ.
*
* @rdesc
* TDI_SUCCESS (tdistat.h) on success, or (tdistat.h)
* @errors
* @ecode TDI_ADDR_IN_USE | Address is in use.
* @ecode TDI_BAD_ADDR | Address is bad.
* @ecode TDI_NO_FREE_ADDR | Address space is full.
* @ecode TDI_NO_RESOURCES | No memory.
*
* @parm PTDI_REQUEST | pTDIReq |
* (tdi.h) The address of the new IRLMP_ADDR_OBJ is returned in
* pTDIReq->Handle.AddressHandle.
* @parm PTRANSPORT_ADDRESS | pAddr |
* Pointer to input TRANSPORT_ADDRESS (tdi.h) struct. IrLMP assumes
* one TA_ADDRESS entry with the Address field containing the
* remaining bytes of a SOCKADDR_IRDA struct minus the first two
* bytes.
* @parm uint | Protocol |
* (TBD, see tcp.h, udp.h> IrLMP will save this value in the new
* IRLMP_ADDR_OBJ.
* @parm PVOID | pOptions |
* Pointer to options. IrLMP will ignore this value.
*/
TDI_STATUS
IRLMP_OpenAddress(PTDI_REQUEST pTDIReq,
PTRANSPORT_ADDRESS pAddr,
uint Protocol,
PVOID pOptions)
{
TDI_STATUS TdiStatus = TDI_SUCCESS;
PIRLMP_ADDR_OBJ pNewAddrObj, pAddrObj;
int LsapSel;
PSOCKADDR_IRDA pIrdaAddr;
PLIST_ENTRY pAddrEntry;
DEBUGMSG(ZONE_FUNCTION,
(TEXT("+IRLMP_OpenAddress(0x%X,0x%X,0x%X,0x%X)\r\n"),
pTDIReq, pAddr, Protocol, pOptions));
pNewAddrObj = NULL;
EnterCriticalSection(&csIrObjList);
// Service name supplied. Ensure that an address object with same
// name does not exist.
pIrdaAddr = (PSOCKADDR_IRDA)&pAddr->Address[0].AddressType;
if (pIrdaAddr->irdaServiceName[0] != 0)
{
// Truncate at 24 chars. Doc'd as a NULL terminated string in a 25
// char buffer. Truncate without error.
pIrdaAddr->irdaServiceName[24] = 0;
for (pAddrEntry = IrAddrObjList.Flink;
pAddrEntry != &IrAddrObjList;
pAddrEntry = pAddrEntry->Flink)
{
pAddrObj = (PIRLMP_ADDR_OBJ)pAddrEntry;
if (strcmp(pIrdaAddr->irdaServiceName,
pAddrObj->SockAddrLocal.irdaServiceName) == 0)
{
DEBUGMSG(ZONE_WARN,
(TEXT("IRLMP_OpenAddress, dup irdaServiceName\r\n")));
TdiStatus = TDI_ADDR_IN_USE;
goto ExitIRLMP_OpenAddress;
}
}
}
if (!memcmp (pIrdaAddr->irdaServiceName, LSAPSEL_TXT, LSAPSEL_TXTLEN))
{
DEBUGMSG(ZONE_WARN,
(TEXT("IRLMP_OpenAddress: Hard coded LSAP '%hs' requested.\r\n"),
pIrdaAddr->irdaServiceName));
LsapSel = ParseLsapSel(
&pIrdaAddr->irdaServiceName[LSAPSEL_TXTLEN]);
if (LsapSel == -1)
{
TdiStatus = TDI_ADDR_INVALID;
goto ExitIRLMP_OpenAddress;
}
DEBUGMSG(ZONE_WARN,
(TEXT("IRLMP_OpenAddress: Have hardcoded LSAP %d(0x%X)\r\n"),
LsapSel, LsapSel));
// Ensure that our LSAP does not collide.
if (IsLsapSelUsed(LsapSel) == TRUE)
{
DEBUGMSG(ZONE_WARN,
(TEXT("IRLMP_OpenAddress: Can't give hardcoded LSAP %d -- in use!\r\n"),
LsapSel));
TdiStatus = TDI_ADDR_IN_USE;
goto ExitIRLMP_OpenAddress;
}
}
else
{
// Get an unused LSAP-SEL for this socket address object.
LsapSel = GetUnusedLsapSel();
if (LsapSel == -1)
{
TdiStatus = TDI_NO_FREE_ADDR;
goto ExitIRLMP_OpenAddress;
}
}
pNewAddrObj = ALLOCADDR(&pTDIReq->Handle.AddressHandle);
if (pNewAddrObj == NULL)
{
DEBUGMSG(ZONE_ERROR,
(TEXT("IRLMP_OpenAddress() CTEAllocMem() failed\r\n")));
TdiStatus = TDI_NO_RESOURCES;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -