Source code of Windows XP (NT5)
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.

701 lines
21 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1990-2000 **/
  4. /********************************************************************/
  5. /* :ts=4 */
  6. //*** iploop.c - IP loopback routines.
  7. //
  8. // This file contains all the routines related to loopback
  9. #include "precomp.h"
  10. #include "iprtdef.h"
  11. #include "iproute.h"
  12. #include "tcpipbuf.h"
  13. #define LOOP_LOOKAHEAD MAX_HDR_SIZE + 8
  14. extern int NumNTE;
  15. extern int NumActiveNTE;
  16. extern Interface *IFList;
  17. extern uint NumIF;
  18. extern BOOLEAN CopyToNdisSafe(PNDIS_BUFFER DestBuf, PNDIS_BUFFER * ppNextBuf,
  19. uchar * SrcBuf, uint Size, uint * StartOffset);
  20. CACHE_LINE_KSPIN_LOCK LoopLock;
  21. PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET) NULL;
  22. PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET) NULL;
  23. CTEEvent LoopXmitEvent;
  24. RouteInterface LoopInterface; // Loopback interface.
  25. uint LoopXmitRtnRunning = 0;
  26. int LoopGetEList(void *Context, TDIEntityID *EntityList, uint *Count);
  27. NetTableEntry *InitLoopback(IPConfigInfo * ConfigInfo);
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, LoopGetEList)
  30. #pragma alloc_text(INIT, InitLoopback)
  31. #endif // ALLOC_PRAGMA
  32. uint LoopIndex; // Index of loop I/F.
  33. uint LoopInstance = INVALID_ENTITY_INSTANCE; // I/F instance of loopback I/F.
  34. NetTableEntry *LoopNTE; // Pointer to loopback NTE.
  35. IFEntry LoopIFE; // Loopback IF Entry.
  36. uchar LoopName[] = "MS TCP Loopback interface";
  37. uint LoopEntityType = IF_MIB;
  38. //* LoopXmitRtn - Loopback xmit event routine.
  39. //
  40. // This is the delayed event routine called for a loopback transmit.
  41. //
  42. // Entry: Event - Pointer to event structure.
  43. // Context - Pointer to loopback NTE
  44. //
  45. // Returns: Nothing.
  46. //
  47. void
  48. LoopXmitRtn(CTEEvent *Event, void *Context)
  49. {
  50. PNDIS_PACKET Packet; // Pointer to packet being transmitted
  51. CTELockHandle Handle;
  52. PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
  53. uint TotalLength; // Total length of send.
  54. uint LookaheadLength; // Bytes in lookahead.
  55. uint Copied; // Bytes copied so far.
  56. uchar *CopyPtr; // Pointer to buffer being copied into.
  57. uchar *SrcPtr; // Pointer to buffer being copied from.
  58. uint SrcLength; // Length of src buffer.
  59. uchar LookaheadBuffer[LOOP_LOOKAHEAD];
  60. uchar Rcvd = FALSE;
  61. #if !MILLEN
  62. KIRQL OldIrql;
  63. #endif // !MILLEN
  64. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  65. //
  66. // Raise IRQL so we can acquire locks at DPC level in the receive code.
  67. // On Windows ME, this is NOT done since receive indications are in the
  68. // context of a global event rather than DPC (in fact due to TDI client
  69. // restrictions, TCP/IP can't indicate up at DPC, so care must be taken).
  70. //
  71. #if !MILLEN
  72. KeEnterCriticalRegion();
  73. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  74. #endif // !MILLEN
  75. CTEGetLockAtDPC(&LoopLock.Lock, &Handle);
  76. if (LoopXmitRtnRunning) {
  77. CTEFreeLockFromDPC(&LoopLock.Lock, Handle);
  78. #if !MILLEN
  79. KeLowerIrql(OldIrql);
  80. KeLeaveCriticalRegion();
  81. #endif // !MILLEN
  82. return;
  83. }
  84. LoopXmitRtnRunning = 1;
  85. for (;;) {
  86. Packet = LoopXmitHead; // Get the next packet from the list.
  87. if (Packet != (PNDIS_PACKET) NULL) {
  88. LoopXmitHead = *(PNDIS_PACKET *) Packet->MacReserved;
  89. LoopIFE.if_outqlen--;
  90. CTEFreeLockFromDPC(&LoopLock.Lock, Handle);
  91. } else { // Nothing left to do.
  92. LoopXmitRtnRunning = 0;
  93. CTEFreeLockFromDPC(&LoopLock.Lock, Handle);
  94. break;
  95. }
  96. // See if the interface is up. If it's not, we can't deliver it.
  97. if (LoopIFE.if_adminstatus == IF_STATUS_UP) {
  98. NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
  99. LoopIFE.if_outoctets += TotalLength;
  100. LoopIFE.if_inoctets += TotalLength;
  101. LookaheadLength = MIN(LOOP_LOOKAHEAD, TotalLength);
  102. Copied = 0;
  103. CopyPtr = LookaheadBuffer;
  104. while (Copied < LookaheadLength) {
  105. uint ThisCopy; // Bytes to copy this time.
  106. ASSERT(Buffer);
  107. TcpipQueryBuffer(Buffer, &SrcPtr, &SrcLength, NormalPagePriority);
  108. if (SrcPtr == NULL) {
  109. IPSendComplete(Context, Packet, NDIS_STATUS_RESOURCES);
  110. CTEGetLockAtDPC(&LoopLock.Lock, &Handle);
  111. LoopXmitRtnRunning = 0;
  112. LoopIFE.if_indiscards++;
  113. CTEFreeLockFromDPC(&LoopLock.Lock, Handle);
  114. #if !MILLEN
  115. KeLowerIrql(OldIrql);
  116. KeLeaveCriticalRegion();
  117. #endif // !MILLEN
  118. return;
  119. }
  120. ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
  121. RtlCopyMemory(CopyPtr, SrcPtr, ThisCopy);
  122. Copied += ThisCopy;
  123. CopyPtr += ThisCopy;
  124. NdisGetNextBuffer(Buffer, &Buffer);
  125. }
  126. Rcvd = TRUE;
  127. LoopIFE.if_inucastpkts++;
  128. // Call the RcvPacket Handler
  129. IPRcvPacket(Context, LookaheadBuffer, LookaheadLength, TotalLength,
  130. (NDIS_HANDLE) Packet, 0, FALSE, 0, NULL, (PINT) Packet,
  131. NULL);
  132. } else {
  133. LoopIFE.if_indiscards++;
  134. }
  135. IPSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
  136. #if !MILLEN
  137. //
  138. // Give other threads a chance to run.
  139. // Block special k mode APC delivery
  140. // so that thread will not be blocked
  141. // in a completion routine
  142. //
  143. KeLowerIrql(OldIrql);
  144. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  145. #endif // !MILLEN
  146. CTEGetLockAtDPC(&LoopLock.Lock, &Handle);
  147. }
  148. if (Rcvd) {
  149. IPRcvComplete();
  150. }
  151. #if !MILLEN
  152. KeLowerIrql(OldIrql);
  153. KeLeaveCriticalRegion();
  154. #endif // !MILLEN
  155. }
  156. //** LoopXmit - Transmit a loopback packet.
  157. //
  158. // This is the routine called when we need to transmit a packet to ourselves.
  159. // We put the packet on our loopback list, and schedule an event to deal
  160. // with it.
  161. //
  162. // Entry: Context - Pointer to the loopback NTE.
  163. // Packet - Pointer to packet to be transmitted.
  164. // Dest - Destination addres of packet.
  165. // RCE - Pointer to RCE (should be NULL).
  166. //
  167. // Returns: NDIS_STATUS_PENDING
  168. //
  169. NDIS_STATUS
  170. __stdcall
  171. LoopXmit(void *Context, PNDIS_PACKET *PacketArray, uint NoPackets,
  172. IPAddr Dest, RouteCacheEntry * RCE, void *LinkCtxt)
  173. {
  174. PNDIS_PACKET *PacketPtr;
  175. CTELockHandle Handle;
  176. PNDIS_PACKET Packet = *PacketArray;
  177. ASSERT(NoPackets == 1);
  178. LoopIFE.if_outucastpkts++;
  179. if (LoopIFE.if_adminstatus == IF_STATUS_UP) {
  180. PacketPtr = (PNDIS_PACKET *) Packet->MacReserved;
  181. *PacketPtr = (PNDIS_PACKET) NULL;
  182. CTEGetLock(&LoopLock.Lock, &Handle);
  183. if (LoopXmitHead == (PNDIS_PACKET) NULL) { // Xmit. Q is empty
  184. LoopXmitHead = Packet;
  185. } else { // Xmit. Q is not empty
  186. PacketPtr = (PNDIS_PACKET *) LoopXmitTail->MacReserved;
  187. *PacketPtr = Packet;
  188. }
  189. LoopXmitTail = Packet;
  190. LoopIFE.if_outqlen++;
  191. if (!LoopXmitRtnRunning) {
  192. CTEScheduleDelayedEvent(&LoopXmitEvent, Context);
  193. }
  194. CTEFreeLock(&LoopLock.Lock, Handle);
  195. return NDIS_STATUS_PENDING;
  196. } else {
  197. LoopIFE.if_outdiscards++;
  198. return NDIS_STATUS_SUCCESS;
  199. }
  200. }
  201. //* LoopXfer - Loopback transfer data routine.
  202. //
  203. // Called when we need to transfer data for the loopback net. The input
  204. // TDContext is the original packet.
  205. //
  206. // Entry: Context - Pointer to loopback NTE.
  207. // TDContext - Original packet that was sent.
  208. // Dummy - Unused
  209. // Offset - Offset in frame from which to start copying.
  210. // BytesToCopy - Number of bytes to copy.
  211. // DestPacket - Packet describing buffer to copy into.
  212. // BytesCopied - Place to return bytes copied.
  213. //
  214. // Returns: NDIS_STATUS_SUCCESS
  215. //
  216. NDIS_STATUS
  217. __stdcall
  218. LoopXfer(void *Context, NDIS_HANDLE TDContext, uint Dummy, uint Offset,
  219. uint BytesToCopy, PNDIS_PACKET DestPacket, uint *BytesCopied)
  220. {
  221. PNDIS_BUFFER SrcBuffer; // Current buffer we're copying from.
  222. PNDIS_PACKET SrcPacket = (PNDIS_PACKET) TDContext;
  223. uchar *SrcPtr; // Where we're copying from.
  224. uint SrcLength; // Length of current src buffer.
  225. PNDIS_BUFFER DestBuffer; // Buffer we're copying to.
  226. uchar *DestPtr; // Where we're copying to.
  227. uint DestLength; // Length of current dest. buffer.
  228. uint Copied; // Length we've copied so far.
  229. NDIS_STATUS Status;
  230. // First, skip over Offset bytes in the packet.
  231. NdisQueryPacket(SrcPacket, NULL, NULL, &SrcBuffer, NULL);
  232. ASSERT(SrcBuffer);
  233. TcpipQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength, NormalPagePriority);
  234. if (SrcPtr == NULL) {
  235. return NDIS_STATUS_RESOURCES;
  236. }
  237. while (Offset >= SrcLength) {
  238. Offset -= SrcLength;
  239. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  240. ASSERT(SrcBuffer);
  241. TcpipQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength, NormalPagePriority);
  242. if (SrcPtr == NULL) {
  243. return NDIS_STATUS_RESOURCES;
  244. }
  245. }
  246. // Update Src pointer and length.
  247. SrcPtr += Offset;
  248. SrcLength -= Offset;
  249. // Set up the destination pointers and lengths.
  250. NdisQueryPacket(DestPacket, NULL, NULL, &DestBuffer, NULL);
  251. TcpipQueryBuffer(DestBuffer, &DestPtr, &DestLength, NormalPagePriority);
  252. if (DestPtr == NULL) {
  253. return NDIS_STATUS_RESOURCES;
  254. }
  255. Copied = 0;
  256. Status = NDIS_STATUS_SUCCESS;
  257. while (BytesToCopy) {
  258. uint ThisCopy; // What we're copying this time.
  259. ThisCopy = MIN(SrcLength, DestLength);
  260. RtlCopyMemory(DestPtr, SrcPtr, ThisCopy);
  261. Copied += ThisCopy;
  262. DestPtr += ThisCopy;
  263. SrcPtr += ThisCopy;
  264. BytesToCopy -= ThisCopy;
  265. SrcLength -= ThisCopy;
  266. DestLength -= ThisCopy;
  267. if (!SrcLength) { // We've exhausted the source buffer.
  268. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  269. if (!SrcBuffer) {
  270. ASSERT(0 == BytesToCopy);
  271. break; // Copy is done.
  272. }
  273. TcpipQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength,
  274. NormalPagePriority);
  275. if (SrcPtr == NULL && BytesToCopy) {
  276. Status = NDIS_STATUS_RESOURCES;
  277. break;
  278. }
  279. }
  280. if (!DestLength) { // We've exhausted the destination buffer.
  281. NdisGetNextBuffer(DestBuffer, &DestBuffer);
  282. if (!DestBuffer) {
  283. ASSERT(0 == BytesToCopy);
  284. break; // Copy is done.
  285. }
  286. TcpipQueryBuffer(DestBuffer, &DestPtr, &DestLength,
  287. NormalPagePriority);
  288. if (DestPtr == NULL && BytesToCopy) {
  289. Status = NDIS_STATUS_RESOURCES;
  290. break;
  291. }
  292. }
  293. }
  294. if (Status == NDIS_STATUS_SUCCESS) {
  295. *BytesCopied = Copied;
  296. }
  297. return Status;
  298. }
  299. //* LoopClose - Loopback close routine.
  300. //
  301. // This is the loopback close routine. It does nothing but return.
  302. //
  303. // Entry: Context - Unused.
  304. //
  305. // Returns: Nothing.
  306. //
  307. void
  308. __stdcall
  309. LoopClose(void *Context)
  310. {
  311. }
  312. //* LoopInvalidate - Invalidate an RCE.
  313. //
  314. // The loopback invalidate RCE routine. It also does nothing.
  315. //
  316. // Entry: Context - Unused.
  317. // RCE - Pointer to RCE to be invalidated.
  318. //
  319. // Returns: Nothing.
  320. //
  321. void
  322. __stdcall
  323. LoopInvalidate(void *Context, RouteCacheEntry * RCE)
  324. {
  325. }
  326. //* LoopQInfo - Loopback query information handler.
  327. //
  328. // Called when the upper layer wants to query information about the loopback
  329. // interface.
  330. //
  331. // Input: IFContext - Interface context (unused).
  332. // ID - TDIObjectID for object.
  333. // Buffer - Buffer to put data into.
  334. // Size - Pointer to size of buffer. On return, filled with
  335. // bytes copied.
  336. // Context - Pointer to context block.
  337. //
  338. // Returns: Status of attempt to query information.
  339. //
  340. int
  341. __stdcall
  342. LoopQInfo(void *IFContext, TDIObjectID * ID, PNDIS_BUFFER Buffer, uint * Size,
  343. void *Context)
  344. {
  345. uint Offset = 0;
  346. uint BufferSize = *Size;
  347. uint Entity;
  348. uint Instance;
  349. BOOLEAN fStatus;
  350. Entity = ID->toi_entity.tei_entity;
  351. Instance = ID->toi_entity.tei_instance;
  352. // First, make sure it's possibly an ID we can handle.
  353. if (Entity != IF_ENTITY || Instance != LoopInstance) {
  354. return TDI_INVALID_REQUEST;
  355. }
  356. *Size = 0; // In case of an error.
  357. if (ID->toi_type != INFO_TYPE_PROVIDER)
  358. return TDI_INVALID_PARAMETER;
  359. if (ID->toi_class == INFO_CLASS_GENERIC) {
  360. if (ID->toi_id == ENTITY_TYPE_ID) {
  361. // He's trying to see what type we are.
  362. if (BufferSize >= sizeof(uint)) {
  363. fStatus = CopyToNdisSafe(Buffer, NULL,
  364. (uchar *) &LoopEntityType,
  365. sizeof(uint), &Offset);
  366. if (fStatus == FALSE) {
  367. return (TDI_NO_RESOURCES);
  368. }
  369. return TDI_SUCCESS;
  370. } else
  371. return TDI_BUFFER_TOO_SMALL;
  372. }
  373. return TDI_INVALID_PARAMETER;
  374. } else if (ID->toi_class != INFO_CLASS_PROTOCOL)
  375. return TDI_INVALID_PARAMETER;
  376. // If he's asking for MIB statistics, then return them, otherwise fail
  377. // the request.
  378. if (ID->toi_id == IF_MIB_STATS_ID) {
  379. // He's asking for statistics. Make sure his buffer is at least big
  380. // enough to hold the fixed part.
  381. if (BufferSize < IFE_FIXED_SIZE) {
  382. return TDI_BUFFER_TOO_SMALL;
  383. }
  384. // He's got enough to hold the fixed part. Copy our IFE structure
  385. // into his buffer.
  386. fStatus = CopyToNdisSafe(Buffer, &Buffer, (uchar *) & LoopIFE,
  387. IFE_FIXED_SIZE, &Offset);
  388. if (fStatus == TRUE) {
  389. // See if he has room for the descriptor string.
  390. if (BufferSize >= (IFE_FIXED_SIZE + sizeof(LoopName))) {
  391. // He has room. Copy it.
  392. fStatus = CopyToNdisSafe(Buffer, NULL, LoopName,
  393. sizeof(LoopName), &Offset);
  394. if (fStatus == TRUE) {
  395. *Size = IFE_FIXED_SIZE + sizeof(LoopName);
  396. return TDI_SUCCESS;
  397. }
  398. } else {
  399. // Not enough room to copy the desc. string.
  400. *Size = IFE_FIXED_SIZE;
  401. return TDI_BUFFER_OVERFLOW;
  402. }
  403. }
  404. return TDI_NO_RESOURCES;
  405. }
  406. return TDI_INVALID_PARAMETER;
  407. }
  408. //* LoopSetInfo - Loopback set information handler.
  409. //
  410. // The loopback set information handler. We support setting of an I/F admin
  411. // status.
  412. //
  413. // Input: Context - Pointer to I/F to set on.
  414. // ID - The object ID
  415. // Buffer - Pointer to buffer containing value to set.
  416. // Size - Size in bytes of Buffer.
  417. //
  418. // Returns: Status of attempt to set information.
  419. //
  420. int
  421. __stdcall
  422. LoopSetInfo(void *Context, TDIObjectID *ID, void *Buffer, uint Size)
  423. {
  424. IFEntry *IFE = (IFEntry *) Buffer;
  425. uint Entity, Instance, Status;
  426. Entity = ID->toi_entity.tei_entity;
  427. Instance = ID->toi_entity.tei_instance;
  428. // First, make sure it's possibly an ID we can handle.
  429. if (Entity != IF_ENTITY || Instance != LoopInstance) {
  430. return TDI_INVALID_REQUEST;
  431. }
  432. if (ID->toi_class != INFO_CLASS_PROTOCOL ||
  433. ID->toi_type != INFO_TYPE_PROVIDER) {
  434. return TDI_INVALID_PARAMETER;
  435. }
  436. // It's for the I/F level, see if it's for the statistics.
  437. if (ID->toi_id == IF_MIB_STATS_ID) {
  438. // It's for the stats. Make sure it's a valid size.
  439. if (Size >= IFE_FIXED_SIZE) {
  440. // It's a valid size. See what he wants to do.
  441. Status = IFE->if_adminstatus;
  442. if (Status == IF_STATUS_UP || Status == IF_STATUS_DOWN)
  443. LoopIFE.if_adminstatus = Status;
  444. else if (Status != IF_STATUS_TESTING)
  445. return TDI_INVALID_PARAMETER;
  446. return TDI_SUCCESS;
  447. } else
  448. return TDI_INVALID_PARAMETER;
  449. }
  450. return TDI_INVALID_PARAMETER;
  451. }
  452. //* LoopAddAddr - Dummy loopback add address routine.
  453. //
  454. // Called at init time when we need to initialize ourselves.
  455. //
  456. uint
  457. __stdcall
  458. LoopAddAddr(void *Context, uint Type, IPAddr Address, IPMask Mask, void *Context2)
  459. {
  460. return TRUE;
  461. }
  462. //* LoopDelAddr - Dummy loopback del address routine.
  463. //
  464. // Called at init time when we need to initialize ourselves.
  465. //
  466. uint
  467. __stdcall
  468. LoopDelAddr(void *Context, uint Type, IPAddr Address, IPMask Mask)
  469. {
  470. return TRUE;
  471. }
  472. #pragma BEGIN_INIT
  473. extern int InitNTE(NetTableEntry *);
  474. extern int InitInterface(NetTableEntry *);
  475. //* LoopGetEList - Get the entity list.
  476. //
  477. // Called at init time to get an entity list. We fill our stuff in and return.
  478. //
  479. // Input: Context - Unused.
  480. // EntityList - Pointer to entity list to be filled in.
  481. // Count - Pointer to number of entries in the list.
  482. //
  483. // Returns Status of attempt to get the info.
  484. //
  485. int
  486. __stdcall
  487. LoopGetEList(void *Context, TDIEntityID *EntityList, uint *Count)
  488. {
  489. uint MyIFBase;
  490. uint i;
  491. TDIEntityID *IFEntity;
  492. // Walk down the list, looking for existing IF entities, and
  493. // adjust our base instance accordingly.
  494. MyIFBase = 0;
  495. IFEntity = NULL;
  496. for (i = 0; i < *Count; i++, EntityList++) {
  497. if (EntityList->tei_entity == IF_ENTITY)
  498. // if we are already on the list remember our entity item
  499. // o/w find an instance # for us.
  500. if (EntityList->tei_instance == LoopInstance &&
  501. EntityList->tei_instance != INVALID_ENTITY_INSTANCE) {
  502. IFEntity = EntityList;
  503. break;
  504. } else {
  505. MyIFBase = MAX(MyIFBase, EntityList->tei_instance + 1);
  506. }
  507. }
  508. if (IFEntity == NULL) {
  509. // we are not on the list.
  510. // make sure we have the room for it.
  511. if (*Count >= MAX_TDI_ENTITIES) {
  512. return FALSE;
  513. }
  514. LoopInstance = MyIFBase;
  515. // Now fill it in.
  516. EntityList->tei_entity = IF_ENTITY;
  517. EntityList->tei_instance = MyIFBase;
  518. (*Count)++;
  519. }
  520. return TRUE;
  521. }
  522. //** InitLoopback - Initialize the loopback NTE.
  523. //
  524. // This function initialized the loopback NTE. We set up the the MSS and
  525. // pointer to the various pseudo-link routines, then call InitNTE and return.
  526. //
  527. // Entry: ConfigInfo - Pointer to config. info structure.
  528. //
  529. // Returns: TRUE if we initialized, FALSE if we didn't.
  530. //
  531. NetTableEntry *
  532. InitLoopback(IPConfigInfo * ConfigInfo)
  533. {
  534. LLIPBindInfo ARPInfo;
  535. LoopNTE = CTEAllocMem(sizeof(NetTableEntry));
  536. if (LoopNTE == NULL)
  537. return LoopNTE;
  538. RtlZeroMemory(LoopNTE, sizeof(NetTableEntry));
  539. RtlZeroMemory(&LoopInterface, sizeof(RouteInterface));
  540. LoopNTE->nte_addr = LOOPBACK_ADDR;
  541. LoopNTE->nte_mask = CLASSA_MASK;
  542. LoopNTE->nte_icmpseq = 1;
  543. LoopNTE->nte_flags = NTE_VALID | NTE_ACTIVE | NTE_PRIMARY;
  544. CTEInitLock(&LoopNTE->nte_lock);
  545. CTEInitLock(&LoopInterface.ri_if.if_lock);
  546. LoopNTE->nte_mss = LOOPBACK_MSS;
  547. LoopNTE->nte_if = (Interface *) & LoopInterface;
  548. LoopInterface.ri_if.if_lcontext = LoopNTE;
  549. LoopInterface.ri_if.if_xmit = LoopXmit;
  550. LoopInterface.ri_if.if_transfer = LoopXfer;
  551. LoopInterface.ri_if.if_close = LoopClose;
  552. LoopInterface.ri_if.if_invalidate = LoopInvalidate;
  553. LoopInterface.ri_if.if_qinfo = LoopQInfo;
  554. LoopInterface.ri_if.if_setinfo = LoopSetInfo;
  555. LoopInterface.ri_if.if_getelist = LoopGetEList;
  556. LoopInterface.ri_if.if_addaddr = LoopAddAddr;
  557. LoopInterface.ri_if.if_deladdr = LoopDelAddr;
  558. LoopInterface.ri_if.if_bcast = IP_LOCAL_BCST;
  559. LoopInterface.ri_if.if_speed = 10000000;
  560. LoopInterface.ri_if.if_mtu = LOOPBACK_MSS;
  561. LoopInterface.ri_if.if_llipflags = LIP_COPY_FLAG;
  562. LOCKED_REFERENCE_IF(&LoopInterface.ri_if);
  563. LoopInterface.ri_if.if_order = MAXLONG;
  564. ARPInfo.lip_mss = LOOPBACK_MSS + sizeof(IPHeader);
  565. ARPInfo.lip_index = LoopIndex;
  566. ARPInfo.lip_close = LoopClose;
  567. ARPInfo.lip_addaddr = LoopAddAddr;
  568. ARPInfo.lip_deladdr = LoopDelAddr;
  569. ARPInfo.lip_flags = LIP_COPY_FLAG;
  570. LoopIndex = NumIF + 1;
  571. LoopInterface.ri_if.if_index = LoopIndex;
  572. CTEInitEvent(&LoopXmitEvent, LoopXmitRtn);
  573. CTEInitLock(&LoopLock.Lock);
  574. LoopIFE.if_index = LoopIndex;
  575. LoopIFE.if_type = IF_TYPE_SOFTWARE_LOOPBACK;
  576. LoopIFE.if_mtu = ARPInfo.lip_mss;
  577. LoopIFE.if_speed = 10000000;
  578. LoopIFE.if_adminstatus = IF_STATUS_UP;
  579. LoopIFE.if_operstatus = IF_OPER_STATUS_OPERATIONAL;
  580. LoopIFE.if_lastchange = GetTimeTicks();
  581. LoopIFE.if_descrlen = sizeof(LoopName);
  582. IFList = (Interface *) & LoopInterface;
  583. NumIF++;
  584. NumNTE++;
  585. if (!InitInterface(LoopNTE))
  586. return NULL;
  587. if (!InitNTE(LoopNTE))
  588. return NULL;
  589. NumActiveNTE++;
  590. return LoopNTE;
  591. }
  592. #pragma END_INIT