Leaked source code of windows server 2003
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.

1017 lines
30 KiB

  1. /*-------------------------------------------------------------------
  2. hdlc.c - handle LAN communications. Provide error free transport
  3. of packets: take care of packet drop detection, retransmition.
  4. HDLC like services. Layer 2.
  5. 4-27-98 - adjust for scanrate addition.
  6. 6-17-97 - change link-integrity check code.
  7. 6-17-97 - rewrite sequencing logic, in hdlc_clear_outpkts().
  8. Copyright 1996,97 Comtrol Corporation. All rights reserved. Proprietary
  9. information not permitted for development or use with non-Comtrol products.
  10. |---------------------------------------------------------------------*/
  11. #include "precomp.h"
  12. //void hdlc_send_ialive(Hdlc *hd);
  13. int hdlc_send_ack_only(Hdlc *hd);
  14. static void hdlc_clear_outpkts(Hdlc *hd);
  15. int hdlc_SendPkt(Hdlc *hd, int pkt_num, int length);
  16. int hdlc_ctl_SendPkt(Hdlc *hd, int pkt_num, int length);
  17. #define Trace1(s,p1) GTrace1(D_Hdlc, sz_modid, s, p1)
  18. #define TraceStr(s) GTrace(D_Hdlc, sz_modid, s)
  19. #define TraceErr(s) GTrace(D_Error, sz_modid_err, s)
  20. static char *sz_modid = {"Hdlc"};
  21. static char *sz_modid_err = {"Error,Hdlc"};
  22. #define DISABLE()
  23. #define ENABLE()
  24. /*--------------------------------------------------------------------------
  25. | hdlc_open - setup and initialize a LanPort thing.
  26. |--------------------------------------------------------------------------*/
  27. int hdlc_open(Hdlc *hd, BYTE *box_mac_addr)
  28. {
  29. int i;
  30. NTSTATUS Status;
  31. PNDIS_BUFFER NdisBuffer;
  32. TraceStr("open");
  33. if (hd->qout.QBase != NULL)
  34. {
  35. MyKdPrint(D_Error, ("HDLC already open!\n"))
  36. return 0;
  37. }
  38. hd->out_snd_index= 0;
  39. hd->in_ack_index = 0;
  40. hd->next_in_index = 0;
  41. hd->rec_ack_timer = 0;
  42. hd->sender_ack_timer = 0;
  43. hd->tx_alive_timer = 0;
  44. hd->rx_alive_timer = 0;
  45. hd->qout_ctl.QPut = 0;
  46. hd->qout_ctl.QGet = 0;
  47. hd->qout_ctl.QSize = 2; // 2 pkts
  48. hd->qout.QPut = 0;
  49. hd->qout.QGet = 0;
  50. hd->qout.QSize = HDLC_TX_PKT_QUEUE_SIZE; // number of iframe pkts
  51. hd->pkt_window_size = HDLC_TX_PKT_QUEUE_SIZE-2;
  52. memcpy(hd->dest_addr, box_mac_addr, 6);
  53. // default to the first nic card slot, port state handling and nic
  54. // packet reception handling dynamically figures this out.
  55. // we should probably set it to null, but I'm afraid of this right now
  56. #ifdef BREAK_NIC_STUFF
  57. hd->nic = NULL;
  58. #else
  59. hd->nic = &Driver.nics[0];
  60. #endif
  61. // NDIS packets consist of one or more buffer descriptors which point
  62. // to the actual data. We send or receive single packets made up of
  63. // 1 or more buffers. A MDL is used as a buffer descriptor under NT.
  64. //--------- Allocate a packet pool for our tx packets
  65. NdisAllocatePacketPool(&Status, &hd->TxPacketPool, HDLC_TX_PKT_QUEUE_SIZE,
  66. sizeof(PVOID));
  67. // sizeof(PACKET_RESERVED));
  68. if (Status != NDIS_STATUS_SUCCESS)
  69. {
  70. hdlc_close(hd);
  71. return 4;
  72. }
  73. //--------- Allocate a buffer pool for our tx packets
  74. // we will only use 1 buffer per packet.
  75. NdisAllocateBufferPool(&Status, &hd->TxBufferPool, HDLC_TX_PKT_QUEUE_SIZE);
  76. if (Status != NDIS_STATUS_SUCCESS)
  77. {
  78. hdlc_close(hd);
  79. return 5;
  80. }
  81. //-------- create tx data buffer area
  82. hd->qout.QBase = our_locked_alloc( MAX_PKT_SIZE * HDLC_TX_PKT_QUEUE_SIZE,"hdTX");
  83. //-------- form our tx queue packets so they link to our tx buffer area
  84. for (i=0; i<HDLC_TX_PKT_QUEUE_SIZE; i++)
  85. {
  86. // Get a packet from the pool
  87. NdisAllocatePacket(&Status, &hd->TxPackets[i], hd->TxPacketPool);
  88. if (Status != NDIS_STATUS_SUCCESS)
  89. {
  90. hdlc_close(hd);
  91. return 8;
  92. }
  93. hd->TxPackets[i]->ProtocolReserved[0] = i; // mark with our index
  94. hd->TxPackets[i]->ProtocolReserved[1] = 0; // free for use
  95. // get a buffer for the header
  96. NdisAllocateBuffer(&Status, &NdisBuffer, hd->TxBufferPool,
  97. &hd->qout.QBase[MAX_PKT_SIZE * i], 1500);
  98. if (Status != NDIS_STATUS_SUCCESS)
  99. {
  100. hdlc_close(hd);
  101. return 9;
  102. }
  103. // we use only one data buffer per packet
  104. NdisChainBufferAtFront(hd->TxPackets[i], NdisBuffer);
  105. }
  106. //--------- Allocate a packet pool for our tx control packets(2)
  107. NdisAllocatePacketPool(&Status, &hd->TxCtlPacketPool, 2, sizeof(PVOID));
  108. // sizeof(PACKET_RESERVED));
  109. if (Status != NDIS_STATUS_SUCCESS)
  110. {
  111. hdlc_close(hd);
  112. return 4;
  113. }
  114. //--------- Allocate a buffer pool for our tx ctl packets
  115. // we will only use 1 buffer per packet.
  116. NdisAllocateBufferPool(&Status, &hd->TxCtlBufferPool, 2);
  117. if (Status != NDIS_STATUS_SUCCESS)
  118. {
  119. hdlc_close(hd);
  120. return 5;
  121. }
  122. //-------- create tx control data buffer area
  123. hd->qout_ctl.QBase = our_locked_alloc( MAX_PKT_SIZE * 2,"hdct");
  124. //-------- form our tx queue packets so they link to our tx buffer area
  125. for (i=0; i<2; i++)
  126. {
  127. // Get a packet from the pool
  128. NdisAllocatePacket(&Status, &hd->TxCtlPackets[i], hd->TxCtlPacketPool);
  129. if (Status != NDIS_STATUS_SUCCESS)
  130. {
  131. hdlc_close(hd);
  132. return 8;
  133. }
  134. hd->TxCtlPackets[i]->ProtocolReserved[0] = i; // mark with our index
  135. hd->TxCtlPackets[i]->ProtocolReserved[1] = 0; // free for use
  136. // get a buffer for the header
  137. NdisAllocateBuffer(&Status, &NdisBuffer, hd->TxCtlBufferPool,
  138. &hd->qout_ctl.QBase[MAX_PKT_SIZE * i], 1500);
  139. if (Status != NDIS_STATUS_SUCCESS)
  140. {
  141. hdlc_close(hd);
  142. return 9;
  143. }
  144. // we use only one data buffer per packet
  145. NdisChainBufferAtFront(hd->TxCtlPackets[i], NdisBuffer);
  146. }
  147. return 0;
  148. }
  149. /*--------------------------------------------------------------------------
  150. | hdlc_close -
  151. |--------------------------------------------------------------------------*/
  152. int hdlc_close(Hdlc *hd)
  153. {
  154. TraceStr("close");
  155. if (hd->TxPacketPool != NULL)
  156. NdisFreePacketPool(hd->TxPacketPool);
  157. hd->TxPacketPool = NULL;
  158. if (hd->TxBufferPool != NULL)
  159. NdisFreeBufferPool(hd->TxBufferPool);
  160. hd->TxBufferPool = NULL;
  161. if (hd->qout.QBase != NULL)
  162. our_free(hd->qout.QBase, "hdTX");
  163. hd->qout.QBase = NULL;
  164. //------- close up the control packet buffers
  165. if (hd->TxCtlPacketPool != NULL)
  166. NdisFreePacketPool(hd->TxCtlPacketPool);
  167. hd->TxCtlPacketPool = NULL;
  168. if (hd->TxCtlBufferPool != NULL)
  169. NdisFreeBufferPool(hd->TxCtlBufferPool);
  170. hd->TxCtlBufferPool = NULL;
  171. if (hd->qout_ctl.QBase != NULL)
  172. our_free(hd->qout_ctl.QBase, "hdct");
  173. hd->qout_ctl.QBase = NULL;
  174. return 0;
  175. }
  176. /*----------------------------------------------------------------
  177. hdlc_validate_rx_pkt - Handle "hdlc" like validation of the
  178. rx packets from our nic driver.
  179. Handle checking sequence index byte and return an error if packet
  180. is out of sequence.
  181. |-----------------------------------------------------------------*/
  182. int hdlc_validate_rx_pkt(Hdlc *hd, BYTE *buf)
  183. {
  184. #define CONTROL_HEADER buf[0]
  185. #define SND_INDEX buf[1]
  186. #define ACK_INDEX buf[2]
  187. #define PRODUCT_HEADER buf[3]
  188. TraceStr("validate");
  189. switch (CONTROL_HEADER)
  190. {
  191. case 1: // 1H=unindex
  192. TraceStr("val,unindexed");
  193. break;
  194. case 3: // 1H=unindex, 2H=sync_init
  195. //----- use to re-sync up our index count
  196. // the vs-1000 device will never do this now, only us(the server) will
  197. TraceStr("RESYNC");
  198. hdlc_resync(hd);
  199. return ERR_CONTROL_PACKET; // control packet, no network data
  200. case 0: // normal information frame
  201. break;
  202. }
  203. if ((CONTROL_HEADER & 1) == 0) // indexed, so validate
  204. {
  205. if (hd->rec_ack_timer == 0)
  206. hd->rec_ack_timer = MIN_ACK_REC_TIME;
  207. // now check that packet is syncronized in-order
  208. // make sure we didn't miss a packet
  209. if (SND_INDEX != ((BYTE)(hd->next_in_index)) )
  210. {
  211. ++hd->iframes_outofseq;
  212. hd->status |= LST_SEND_ACK; // force an acknowledgement packet
  213. TraceErr("bad index");
  214. return ERR_GET_BAD_INDEX; // error, packet out of sequence
  215. }
  216. ++hd->unacked_pkts; // when to trip acknowledge at 80% full
  217. if (hd->unacked_pkts > (hd->pkt_window_size - 1))
  218. {
  219. hd->status |= LST_SEND_ACK;
  220. TraceStr("i_ack");
  221. }
  222. hd->rx_alive_timer = 0; // reset this since we have a good rx-active link
  223. ++hd->next_in_index; // bump our index count
  224. TraceStr("iframe OK");
  225. } // indexed
  226. //---- now grab the packet acknowledged index.
  227. if (hd->in_ack_index != ACK_INDEX) // only act when changed.
  228. {
  229. //--- we can assume this ack-index is a reasonable value
  230. // since it has gone threw the ethernet checksum.
  231. hd->in_ack_index = ACK_INDEX; // update our copy
  232. hd->status |= LST_RECLAIM; // perform reclaim operation
  233. }
  234. return 0; // ok
  235. }
  236. /*--------------------------------------------------------------------------
  237. | hdlc_poll - Call at regular interval to handle packet sequencing,
  238. and packet resending. Called 20 times per second for DOS,embedded,
  239. for NT called 100 times per sec.
  240. |--------------------------------------------------------------------------*/
  241. void hdlc_poll(Hdlc *hd)
  242. {
  243. WORD timer;
  244. hd->tick_timer += ((WORD) Driver.Tick100usBase);
  245. if (hd->tick_timer >= 1000) // 1/10th second
  246. {
  247. hd->tick_timer = 0;
  248. // every 1/10th second
  249. ++hd->tx_alive_timer;
  250. ++hd->rx_alive_timer;
  251. if ((hd->tx_alive_timer >= KEEP_ALIVE_TIMEOUT) || // about 1 min.
  252. (hd->rx_alive_timer >= KEEP_ALIVE_TIMEOUT))
  253. {
  254. // Rx or Tx or both activity has not happened, or com-link
  255. // failure has occurred, so send out a iframe to see if
  256. // we are in failure or just a state of non-activity.
  257. // take the biggest timeout value, so we don't have to do
  258. // the logic twice for each.
  259. if (hd->tx_alive_timer > hd->rx_alive_timer)
  260. timer = hd->tx_alive_timer;
  261. else timer = hd->rx_alive_timer;
  262. if (timer == KEEP_ALIVE_TIMEOUT)
  263. {
  264. //hdlc_send_ialive(hd); // send out a iframe to get ack back.
  265. //TraceStr("Snd ialive");
  266. //----- notify owner to check link
  267. if (hd->upper_layer_proc != NULL)
  268. (*hd->upper_layer_proc) (hd->context, EV_L2_CHECK_LINK, 0);
  269. }
  270. else if (timer == (KEEP_ALIVE_TIMEOUT * 2))
  271. {
  272. // declare a bad connection, bring connection down.
  273. //----- notify owner that it needs to resync
  274. if (hd->upper_layer_proc != NULL)
  275. (*hd->upper_layer_proc) (hd->context, EV_L2_RELOAD, 0);
  276. TraceErr("ialive fail");
  277. // make sure everything is cleared out, or reset at our level
  278. hdlc_resync(hd);
  279. hd->tx_alive_timer = 0;
  280. hd->rx_alive_timer = 0;
  281. }
  282. }
  283. if (hd->sender_ack_timer > 0)
  284. {
  285. --hd->sender_ack_timer;
  286. if (hd->sender_ack_timer == 0)
  287. {
  288. if (!q_empty(&hd->qout)) // have outpkts waiting for ack.
  289. {
  290. TraceStr("Snd timeout");
  291. ++hd->send_ack_timeouts; // statistics: # of send-ack-timeouts
  292. hdlc_resend_outpkt(hd); // send it out again!
  293. }
  294. }
  295. }
  296. if (hd->rec_ack_timer > 0)
  297. {
  298. --hd->rec_ack_timer;
  299. if (hd->rec_ack_timer == 0) // timeout on rec. packet ack.
  300. {
  301. ++hd->rec_ack_timeouts; // statistics: # of rec-ack-timeouts
  302. TraceStr("RecAck timeout");
  303. if (!q_empty(&hd->qout)) // have outpkts waiting for ack.
  304. hdlc_resend_outpkt(hd); // send it out again!
  305. else
  306. {
  307. // no iframe packets sent out(piggy back acks on them normally)
  308. // for REC_ACK_TIME amount, so we have to send out just an
  309. // acknowledgement packet.
  310. // arrange for a ack-packet to be sent by setting this bit
  311. hd->status |= LST_SEND_ACK;
  312. }
  313. }
  314. }
  315. } // end of 100ms tick period
  316. // check if received packets more than 80% of senders capacity, if so
  317. // send immediate ack.
  318. if (hd->status & LST_SEND_ACK)
  319. {
  320. if (hdlc_send_ack_only(hd) == 0) // ok
  321. {
  322. hd->status &= ~LST_SEND_ACK;
  323. TraceStr("Ack Sent");
  324. }
  325. else
  326. {
  327. TraceStr("Ack Pkt Busy!");
  328. }
  329. }
  330. if (hd->status & LST_RECLAIM) // check if we should perform reclaim operation
  331. hdlc_clear_outpkts(hd);
  332. return;
  333. }
  334. /*--------------------------------------------------------------------------
  335. | hdlc_get_ctl_outpkt - Used to allocate a outgoing control data
  336. packet, fill in the
  337. common header elements and return a pointer to the packet, so the
  338. application can fill in the data in the packet. The caller is then
  339. expected to send the packet via hdlc_send_ctl_outpkt().
  340. |--------------------------------------------------------------------------*/
  341. int hdlc_get_ctl_outpkt(Hdlc *hd, BYTE **buf)
  342. {
  343. BYTE *bptr;
  344. TraceStr("get_ctl_outpkt");
  345. bptr = &hd->qout_ctl.QBase[(MAX_PKT_SIZE * hd->qout_ctl.QPut)];
  346. *buf = &bptr[20]; // return ptr to the sub-packet area
  347. if (hd->TxCtlPackets[hd->qout_ctl.QPut]->ProtocolReserved[1] != 0) // free for use
  348. {
  349. TraceErr("CPktNotOurs!");
  350. *buf = NULL;
  351. return 2; // error, packet is owned, busy
  352. }
  353. return 0;
  354. }
  355. /*--------------------------------------------------------------------------
  356. | hdlc_get_outpkt - Used to allocate a outgoing data packet, fill in the
  357. common header elements and return a pointer to the packet, so the
  358. application can fill in the data in the packet. The caller is then
  359. expected to send the packet via hdlc_send_outpkt().
  360. |--------------------------------------------------------------------------*/
  361. int hdlc_get_outpkt(Hdlc *hd, BYTE **buf)
  362. {
  363. BYTE *bptr;
  364. TraceStr("get_outpkt");
  365. if (hd->status & LST_RECLAIM) // check if we should perform reclaim operation
  366. hdlc_clear_outpkts(hd);
  367. // if indexed, then reduce by one so we always leave one for an
  368. // unindexed packet.
  369. if (q_count(&hd->qout) >= hd->pkt_window_size)
  370. {
  371. return 1; // no room
  372. }
  373. if (hd->TxPackets[hd->qout.QPut]->ProtocolReserved[1] != 0) // free for use
  374. {
  375. TraceErr("PktNotOurs!");
  376. *buf = NULL;
  377. return 2;
  378. }
  379. bptr = &hd->qout.QBase[(MAX_PKT_SIZE * hd->qout.QPut)];
  380. *buf = &bptr[20]; // return ptr to the sub-packet area
  381. return 0;
  382. }
  383. /*--------------------------------------------------------------------------
  384. | hdlc_clear_outpkts - go through output queue and re-claim any packet
  385. buffers which have been acknowledged.
  386. |--------------------------------------------------------------------------*/
  387. static void hdlc_clear_outpkts(Hdlc *hd)
  388. {
  389. #define NEW_WAY
  390. #ifndef NEW_WAY
  391. int count, get, i, ack_count, ack_get;
  392. BYTE *tx_base;
  393. #define OUT_SNDINDEX tx_base[18]
  394. #else
  395. #define OUT_SNDINDEX_BYTE_OFFSET 18
  396. #endif
  397. int put;
  398. int ack_index;
  399. TraceStr("clear_outpkt");
  400. hd->status &= ~LST_RECLAIM; // clear this flag
  401. // in_ack_index is the last packet V(r) acknowledgement, so it
  402. // is equal to what the other party expects the next rec. pkt
  403. // index to be.
  404. if (hd->in_ack_index > 0)
  405. ack_index = hd->in_ack_index-1;
  406. else ack_index = 0xff;
  407. #ifdef NEW_WAY
  408. put = hd->qout.QPut;
  409. // figure out a queue index of the last(most recent) pkt we sent
  410. // (back up the QPut index)
  411. while (put != hd->qout.QGet) // while not end of ack-pending out-packets
  412. {
  413. // (back up the QPut index)
  414. if (put == 0)
  415. put = HDLC_TX_PKT_QUEUE_SIZE-1;
  416. else --put;
  417. // if ack matches the out_snd_index for this packet
  418. if (hd->qout.QBase[(MAX_PKT_SIZE * put)+OUT_SNDINDEX_BYTE_OFFSET]
  419. == ack_index)
  420. {
  421. // clear all pending up to this packet by updating the QGet index.
  422. if (put == (HDLC_TX_PKT_QUEUE_SIZE-1))
  423. hd->qout.QGet = 0;
  424. else hd->qout.QGet = (put+1);
  425. hd->tx_alive_timer = 0; // reset this since we have a good active link
  426. if (q_empty(&hd->qout)) // all packets cleared
  427. hd->sender_ack_timer = 0; // stop the timeout counter
  428. break; // bail out of while loop, all done
  429. }
  430. }
  431. #else
  432. count = q_count(&hd->qout);
  433. get = hd->qout.QGet;
  434. ack_count = 0;
  435. ack_get = get; // acknowledge all up to this point
  436. for (i=0; i<count; i++)
  437. {
  438. //-- setup a ptr to our first outgoing packet in our resend buffer
  439. tx_base= &hd->qout.QBase[(MAX_PKT_SIZE * get)];
  440. ++get; // setup for next one
  441. if (get >= HDLC_TX_PKT_QUEUE_SIZE)
  442. get = 0;
  443. // if the packet is definitely older than our ACK index
  444. if (OUT_SNDINDEX <= ack_index)
  445. {
  446. ++ack_count; // acknowledge all up to this point
  447. ack_get = get; // acknowledge all up to this point
  448. }
  449. // else if roll over cases might exist
  450. else if (ack_index < HDLC_TX_PKT_QUEUE_SIZE)
  451. {
  452. if (OUT_SNDINDEX > HDLC_TX_PKT_QUEUE_SIZE) // roll over case
  453. {
  454. ++ack_count; // acknowledge all up to this point
  455. ack_get = get; // acknowledge all up to this point
  456. }
  457. else break; // bail from for loop
  458. }
  459. else // we are all done, because pkts must be in order
  460. {
  461. break; // bail from for loop
  462. }
  463. }
  464. if (ack_count) // if we did acknowledge(free) some output packets
  465. {
  466. hd->tx_alive_timer = 0; // reset this since we have a good active link
  467. hd->qout.QGet = ack_get; // update the circular get queue index.
  468. if (q_empty(&hd->qout)) // all packets cleared
  469. hd->sender_ack_timer = 0; // stop the timeout counter
  470. }
  471. #endif
  472. }
  473. /*--------------------------------------------------------------------------
  474. | hdlc_resend_outpkt - resend packet(s) due to sequence error. Only indexed
  475. iframe packets get resent.
  476. |--------------------------------------------------------------------------*/
  477. int hdlc_resend_outpkt(Hdlc *hd)
  478. {
  479. BYTE *tx_base;
  480. int phy_len, count;
  481. // BYTE *buf;
  482. // WORD *wptr;
  483. int get;
  484. TraceStr("resend_outpkt");
  485. if (hd->status & LST_RECLAIM) // check if we should perform reclaim operation
  486. hdlc_clear_outpkts(hd);
  487. count = q_count(&hd->qout);
  488. get = hd->qout.QGet;
  489. if (count == 0)
  490. return 0; // none to send
  491. while (count > 0)
  492. {
  493. if (hd->TxPackets[get]->ProtocolReserved[1] == 0) {
  494. /* Make sure packet has come back from NDIS */
  495. /* free to resend */
  496. // assume indexing used
  497. tx_base= &hd->qout.QBase[(MAX_PKT_SIZE * get)];
  498. ++hd->iframes_sent; // statistics
  499. // get calculated length of packet for resending at out pkt prefix.
  500. phy_len = hd->phys_outpkt_len[get];
  501. // always make the ack as current as possible
  502. tx_base[19] = hd->next_in_index; // V(r)
  503. hdlc_SendPkt(hd, get, phy_len);
  504. ++hd->iframes_resent; // statistics: # of packets re-sent
  505. }
  506. ++get;
  507. if (get >= HDLC_TX_PKT_QUEUE_SIZE)
  508. get = 0;
  509. --count;
  510. }
  511. hd->unacked_pkts = 0;
  512. // reset timeout
  513. hd->sender_ack_timer = (MIN_ACK_REC_TIME * 2);
  514. // reset this timer, since we are sending out new ack.
  515. hd->rec_ack_timer = 0;
  516. return 0;
  517. }
  518. /*--------------------------------------------------------------------------
  519. | hdlc_send_ctl_outpkt - App. calls hdlc_get_ctl_outpkt() to get a buffer.
  520. App then fills buffer and sends it out by calling us.
  521. |--------------------------------------------------------------------------*/
  522. int hdlc_send_ctl_outpkt(Hdlc *hd, int data_len, BYTE *dest_addr)
  523. {
  524. BYTE *tx_base;
  525. int phy_len;
  526. int get, stat;
  527. TraceStr("send_ctl_outpkt");
  528. get = hd->qout_ctl.QPut;
  529. tx_base = &hd->qout_ctl.QBase[(MAX_PKT_SIZE * get)];
  530. ++hd->qout_ctl.QPut;
  531. if (hd->qout_ctl.QPut >= hd->qout_ctl.QSize)
  532. hd->qout_ctl.QPut = 0;
  533. ++hd->ctlframes_sent; // statistics
  534. if (dest_addr == NULL)
  535. memcpy(tx_base, hd->dest_addr, 6); // set dest addr
  536. else memcpy(tx_base, dest_addr, 6); // set dest addr
  537. memcpy(&tx_base[6], hd->nic->address, 6); // set src addr
  538. // + 1 for trailing 0(sub-pkt terminating header)
  539. phy_len = 20 + data_len + 1;
  540. // BYTE 12-13: Comtrol PCI ID (11H, FEH), Ethernet Len field
  541. *((WORD *)&tx_base[12]) = 0xfe11;
  542. if (phy_len < 60)
  543. phy_len = 60;
  544. tx_base[14] = ASYNC_PRODUCT_HEADER_ID; // comtrol packet type = driver management, any product.
  545. tx_base[15] = 0; // conc. index field
  546. tx_base[16] = ASYNC_FRAME; // ASYNC FRAME(0x55)
  547. tx_base[17] = 1; // hdlc control field(ctrl-packet)
  548. tx_base[18] = 0; // V(s), unindexed so mark as 0 to avoid confusion
  549. tx_base[19] = hd->next_in_index; // V(r), acknowl. field
  550. tx_base[20+data_len] = 0; // terminating sub-packet type
  551. hd->unacked_pkts = 0; // reset this
  552. // reset this timer, since we are sending out new ack.
  553. hd->rec_ack_timer = 0;
  554. stat = hdlc_ctl_SendPkt(hd, get, phy_len);
  555. return stat;
  556. }
  557. /*--------------------------------------------------------------------------
  558. | hdlc_send_outpkt - App. calls hdlc_get_outpkt() to get a buffer. App then
  559. fills buffer and sends it out by calling us. This packet sits in
  560. transmit queue for possible re-send until a packet comes in which
  561. acknowledges reception of it.
  562. |--------------------------------------------------------------------------*/
  563. int hdlc_send_outpkt(Hdlc *hd, int data_len, BYTE *dest_addr)
  564. {
  565. BYTE *tx_base;
  566. int phy_len;
  567. int get, stat;
  568. TraceStr("send_outpkt");
  569. get = hd->qout.QPut;
  570. tx_base = &hd->qout.QBase[(MAX_PKT_SIZE * get)];
  571. ++hd->qout.QPut;
  572. if (hd->qout.QPut >= HDLC_TX_PKT_QUEUE_SIZE)
  573. hd->qout.QPut = 0;
  574. // setup this timeout for ack. back.
  575. hd->sender_ack_timer = (MIN_ACK_REC_TIME * 2);
  576. ++hd->iframes_sent; // statistics
  577. if (dest_addr == NULL)
  578. memcpy(tx_base, hd->dest_addr, 6); // set dest addr
  579. else memcpy(tx_base, dest_addr, 6); // set dest addr
  580. memcpy(&tx_base[6], hd->nic->address, 6); // set src addr
  581. // + 1 for trailing 0(sub-pkt terminating header)
  582. phy_len = 20 + data_len + 1;
  583. // BYTE 12-13: Comtrol PCI ID (11H, FEH), Ethernet Len field
  584. *((WORD *)&tx_base[12]) = 0xfe11;
  585. if (phy_len < 60)
  586. phy_len = 60;
  587. tx_base[14] = ASYNC_PRODUCT_HEADER_ID; // comtrol packet type = driver management, any product.
  588. tx_base[15] = 0; // conc. index field
  589. tx_base[16] = ASYNC_FRAME; // ASYNC FRAME(0x55)
  590. tx_base[17] = 0; // hdlc control field(iframe-packet)
  591. tx_base[19] = hd->next_in_index; // V(r), acknowl. field
  592. tx_base[20+data_len] = 0; // terminating sub-packet type
  593. // save calculated length of packet for resending at out pkt prefix.
  594. hd->phys_outpkt_len[get] = phy_len;
  595. tx_base[18] = hd->out_snd_index; // V(s)
  596. hd->out_snd_index++;
  597. hd->unacked_pkts = 0; // reset this
  598. // reset this timer, since we are sending out new ack.
  599. hd->rec_ack_timer = 0;
  600. stat = hdlc_SendPkt(hd, get, phy_len);
  601. return stat;
  602. }
  603. /*----------------------------------------------------------------------
  604. hdlc_ctl_SendPkt - Our send routine.
  605. |----------------------------------------------------------------------*/
  606. int hdlc_ctl_SendPkt(Hdlc *hd, int pkt_num, int length)
  607. {
  608. NTSTATUS Status;
  609. #if DBG
  610. if (hd == NULL)
  611. {
  612. MyKdPrint(D_Error, ("H1\n"))
  613. TraceErr("Hsnd1a1");
  614. return 1;
  615. }
  616. if (hd->nic == NULL)
  617. {
  618. MyKdPrint(D_Error, ("H2\n"))
  619. TraceErr("Hsnd1a");
  620. return 1;
  621. }
  622. if (hd->nic->TxBufTemp == NULL)
  623. {
  624. MyKdPrint(D_Error, ("H3\n"))
  625. TraceErr("Hsnd1b");
  626. return 1;
  627. }
  628. if (hd->nic->TxPacketsTemp == NULL)
  629. {
  630. MyKdPrint(D_Error, ("H4\n"))
  631. TraceErr("Hsnd1c");
  632. return 1;
  633. }
  634. if (hd->nic->Open == 0)
  635. {
  636. MyKdPrint(D_Error, ("H5\n"))
  637. TraceErr("Hsnd1d");
  638. return 1;
  639. }
  640. #endif
  641. Trace1("Hsendpkt Nic%d", hd->nic->RefIndex);
  642. hd->TxCtlPackets[pkt_num]->Private.TotalLength = length;
  643. NdisAdjustBufferLength(hd->TxCtlPackets[pkt_num]->Private.Head, length);
  644. hd->TxCtlPackets[pkt_num]->ProtocolReserved[1] = 1; // mark as pending
  645. NdisSend(&Status, hd->nic->NICHandle, hd->TxCtlPackets[pkt_num]);
  646. if (Status == NDIS_STATUS_SUCCESS)
  647. {
  648. TraceStr(" ok");
  649. hd->TxCtlPackets[pkt_num]->ProtocolReserved[1] = 0; // free for use
  650. }
  651. else if (Status == NDIS_STATUS_PENDING)
  652. {
  653. TraceStr(" pend");
  654. // Status = NicWaitForCompletion(nic); // wait for completion
  655. }
  656. else
  657. {
  658. hd->TxCtlPackets[pkt_num]->ProtocolReserved[1] = 0; // free for use
  659. TraceErr(" send1A");
  660. return 1;
  661. }
  662. ++hd->nic->pkt_sent; // statistics
  663. hd->nic->send_bytes += length; // statistics
  664. return 0;
  665. }
  666. /*----------------------------------------------------------------------
  667. hdlc_SendPkt - Our send routine.
  668. |----------------------------------------------------------------------*/
  669. int hdlc_SendPkt(Hdlc *hd, int pkt_num, int length)
  670. {
  671. NTSTATUS Status;
  672. TraceStr("sendpkt");
  673. hd->TxPackets[pkt_num]->Private.TotalLength = length;
  674. NdisAdjustBufferLength(hd->TxPackets[pkt_num]->Private.Head, length);
  675. hd->TxPackets[pkt_num]->ProtocolReserved[1] = 1; // mark as pending
  676. NdisSend(&Status, hd->nic->NICHandle, hd->TxPackets[pkt_num]);
  677. if (Status == NDIS_STATUS_SUCCESS)
  678. {
  679. TraceStr(" ok");
  680. hd->TxPackets[pkt_num]->ProtocolReserved[1] = 0; // free for use
  681. }
  682. else if (Status == NDIS_STATUS_PENDING)
  683. {
  684. TraceStr(" pend");
  685. // Status = NicWaitForCompletion(nic); // wait for completion
  686. }
  687. else
  688. {
  689. hd->TxPackets[pkt_num]->ProtocolReserved[1] = 0; // free for use
  690. TraceErr(" send1A");
  691. return 1;
  692. }
  693. ++hd->nic->pkt_sent; // statistics
  694. hd->nic->send_bytes += length; // statistics
  695. return 0;
  696. }
  697. #ifdef COMMENT_OUT
  698. /*--------------------------------------------------------------------------
  699. hdlc_send_ialive - Send out a iframe packet which device is required
  700. to acknowledge(and send iframe back) so that we can determine if he
  701. is still alive.
  702. |--------------------------------------------------------------------------*/
  703. void hdlc_send_ialive(Hdlc *hd)
  704. {
  705. int stat;
  706. BYTE *buf;
  707. if (!q_empty(&hd->qout)) // have outpkts waiting for ack.
  708. {
  709. hdlc_resend_outpkt(hd); // send it out again!
  710. }
  711. else
  712. {
  713. stat = hdlc_get_outpkt(hd, &buf);
  714. if (stat == 0)
  715. {
  716. buf[0] = 0; // an empty iframe packet
  717. buf[1] = 0;
  718. stat = hdlc_send_outpkt(hd, 1, hd->dest_addr); // send it out!
  719. if (stat != 0)
  720. { TraceErr("2D"); }
  721. }
  722. else
  723. {
  724. // else we might as well go fishing and forget about this stuff.
  725. TraceErr("3D");
  726. }
  727. }
  728. }
  729. #endif
  730. /*--------------------------------------------------------------------------
  731. hdlc_resync - At appropriate times it is needed to reset the sequence
  732. indexing logic in order to get the two sides up a talking. On
  733. startup(either side) or a fatal(long) timeout, it is needed to send
  734. a message to the other party saying: "reset your packet sequencing
  735. logic so we can get sync-ed up".
  736. |--------------------------------------------------------------------------*/
  737. void hdlc_resync(Hdlc *hd)
  738. {
  739. TraceErr("resync");
  740. //----- flush re-send output buffer
  741. hd->qout.QPut = 0;
  742. hd->qout.QGet = 0;
  743. //----- flush ctl output buffer
  744. hd->qout_ctl.QPut = 0;
  745. hd->qout_ctl.QGet = 0;
  746. //----- use to re-sync up our index count
  747. hd->in_ack_index = 0;
  748. hd->out_snd_index= 0;
  749. hd->next_in_index= 0;
  750. //----- reset our outgoing packet queue
  751. hd->sender_ack_timer = 0;
  752. hd->unacked_pkts = 0;
  753. //----- notify owner that it needs to resync
  754. if (hd->upper_layer_proc != NULL)
  755. (*hd->upper_layer_proc) (hd->context, EV_L2_RESYNC, 0);
  756. }
  757. /*--------------------------------------------------------------------------
  758. | hdlc_send_ack_only - Used to recover from timeout condition. Used to
  759. resend ACK only. Used to send over ACK and index fields in a
  760. unindexed frame(won't flow off). No data sent along, just HDLC header.
  761. |--------------------------------------------------------------------------*/
  762. int hdlc_send_ack_only(Hdlc *hd)
  763. {
  764. int ret_stat;
  765. BYTE *pkt;
  766. TraceStr("send_ack_only");
  767. if (hdlc_get_ctl_outpkt(hd, &pkt) == 0)
  768. ret_stat = hdlc_send_ctl_outpkt(hd, 0, NULL);
  769. else
  770. ret_stat = 1; // packet is already in use
  771. return ret_stat;
  772. }
  773. /*--------------------------------------------------------------------------
  774. | hdlc_send_raw - Used to send raw ethernets out(non-hdlc).
  775. Caller has gotten a control packet by hdlc_get_ctl_outpkt()
  776. and has filled in the header. We just plug in src/dest addr and
  777. send it out. Used to send out non-hdlc packets, we provide the service
  778. in hdlc layer because we have the nic buffers already setup, so its
  779. convienent to implement here.
  780. |--------------------------------------------------------------------------*/
  781. int hdlc_send_raw(Hdlc *hd, int data_len, BYTE *dest_addr)
  782. {
  783. BYTE *tx_base;
  784. int phy_len;
  785. int get, stat;
  786. TraceStr("send_raw");
  787. get = hd->qout_ctl.QPut;
  788. tx_base = &hd->qout_ctl.QBase[(MAX_PKT_SIZE * get)];
  789. ++hd->qout_ctl.QPut;
  790. if (hd->qout_ctl.QPut >= hd->qout_ctl.QSize)
  791. hd->qout_ctl.QPut = 0;
  792. ++hd->rawframes_sent; // statistics
  793. if (dest_addr == NULL)
  794. memcpy(tx_base, hd->dest_addr, 6); // set dest addr
  795. else memcpy(tx_base, dest_addr, 6); // set dest addr
  796. memcpy(&tx_base[6], hd->nic->address, 6); // set src addr
  797. // + 1 for trailing 0(sub-pkt terminating header)
  798. phy_len = 20 + data_len + 1;
  799. // BYTE 12-13: Comtrol PCI ID (11H, FEH), Ethernet Len field
  800. *((WORD *)&tx_base[12]) = 0xfe11;
  801. if (phy_len < 60)
  802. phy_len = 60;
  803. stat = hdlc_ctl_SendPkt(hd, get, phy_len);
  804. return stat;
  805. }
  806. /*--------------------------------------------------------------------------
  807. | hdlc_send_control - Used to send small un-indexed hdlc frames.
  808. |--------------------------------------------------------------------------*/
  809. int hdlc_send_control(Hdlc *hd, BYTE *header_data, int header_len,
  810. BYTE *data, int data_len,
  811. BYTE *dest_addr)
  812. {
  813. BYTE *buf;
  814. int i,stat;
  815. BYTE *pkt;
  816. i = hdlc_get_ctl_outpkt(hd, &pkt);
  817. if (i)
  818. return 1; // error
  819. buf = pkt;
  820. if (header_len)
  821. {
  822. for (i=0; i<header_len; i++)
  823. buf[i] = header_data[i];
  824. buf += header_len;
  825. }
  826. if (data_len)
  827. {
  828. for (i=0; i<data_len; i++)
  829. buf[i] = data[i];
  830. buf += data_len;
  831. }
  832. if (dest_addr == NULL)
  833. {
  834. stat = hdlc_send_ctl_outpkt(hd, header_len + data_len, hd->dest_addr);
  835. }
  836. else
  837. {
  838. stat = hdlc_send_ctl_outpkt(hd, header_len + data_len, dest_addr);
  839. }
  840. return stat;
  841. }