ldserial.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334
  1. /*+-----------------------------------------------------------------------
  2. ldserial.c -- ECU serial line discipline
  3. wht@wht.net
  4. Defined functions:
  5. display_hw_flow_config()
  6. lCLOCAL(flag)
  7. lRTSCTS_control(flag)
  8. lbreak()
  9. lclear_xmtr_xoff()
  10. lclose()
  11. lclose_failed(sig)
  12. ldcdwatch(flag)
  13. ldcdwatch_str(flagstr)
  14. ldraino(inflush_flag)
  15. lflash_dtr()
  16. lflush(flush_type)
  17. lget_xon_xoff(ixon, ixoff)
  18. lnew_bitrate(new_bitrate)
  19. lopen()
  20. lopen_failed(sig)
  21. lreset_ksr()
  22. lset_baud(ioctl_flag)
  23. lset_parity(ioctl_flag)
  24. lxon_xoff(flag)
  25. lzero_length_read_detected()
  26. set_xon_xoff_by_arg(arg)
  27. valid_baud(baud)
  28. xon_status()
  29. Note: With -DCFG_TermiosLineio, termios is used in lieu of
  30. termio. See ecu.h and ecutermio.[ch] and search for
  31. CFG_TermiosLineio for vague illumination.
  32. ------------------------------------------------------------------------*/
  33. /*+:EDITS:*/
  34. /*:04-26-2000-11:16-wht@bob-RELEASE 4.42 */
  35. /*:02-26-1998-03:10-wht@kepler-linux2/redhat */
  36. /*:12-12-1997-21:24-wht@kepler-keep errno2 away from longjmp */
  37. /*:01-24-1997-02:37-wht@yuriatin-SOURCE RELEASE 4.00 */
  38. /*:09-11-1996-20:00-wht@yuriatin-3.48-major telnet,curses,structural overhaul */
  39. /*:08-11-1996-02:10-wht@kepler-rename ecu_log_event to logevent */
  40. /*:07-24-1996-21:04-wht@n4hgf-fix stupid termiox lapse of reason */
  41. /*:07-24-1996-20:52-wht@n4hgf-need ecutermio.h */
  42. /*:01-01-1996-18:06-wht@kepler-repair LINUX_ASYNC_HACK */
  43. /*:12-28-1995-12:54-wht@kepler-Andrey Chernov FreeBSD fixes */
  44. /*:12-12-1995-16:22-wht@kepler-no more telnet intercept in lopen */
  45. /*:12-06-1995-13:30-wht@n4hgf-termecu w/errno -1 consideration */
  46. /*:12-03-1995-20:47-wht@gyro-sun toggle DTR takes forever withOUT naps */
  47. /*:12-03-1995-19:57-wht@gyro-use Setuid */
  48. /*:11-23-1995-11:20-wht@kepler-source control 3.37 for tsx-11 */
  49. /*:11-14-1995-10:23-wht@kepler-3.37.80-source control point: SOCKETS */
  50. /*:11-03-1995-16:54-wht@wwtp1-use CFG_TelnetOption */
  51. /*:10-18-1995-04:29-wht@kepler-always use select for nap */
  52. /*:10-18-1995-04:16-wht@kepler-break out of eculine.c */
  53. #include "ecu.h"
  54. #include "ecukey.h"
  55. #include "termecu.h"
  56. #include "ecutermio.h"
  57. #include <setjmp.h>
  58. #include <pwd.h>
  59. void lreset_ksr();
  60. void lzero_length_read_detected();
  61. void lCLOCAL();
  62. extern int lgetc_count;
  63. char lopen_err_str[64] = "";
  64. int dcdwatch_set = 0; /* if true, ldcdwatch() has been called */
  65. static jmp_buf _insurance_jmpbuf;
  66. static int errno2; /* keep away from longjmp */
  67. static int attempt2; /* keep away from longjmp */
  68. #ifdef SVR4
  69. int hx_flag;
  70. #endif
  71. /*
  72. * with SCO UNIX, nap doesn't work as advertized; param MUST be > granularity
  73. * or nap will return immediately; not a problem with XENIX
  74. */
  75. #define LPUTS_NAP_COUNT (min((hzmsec * 2),20L))
  76. /*+-------------------------------------------------------------------------
  77. lflush(flush_type) -- flush line driver input &/or output buffers
  78. 0 == input buffer
  79. 1 == output buffer
  80. 2 == both buffers
  81. --------------------------------------------------------------------------*/
  82. void
  83. lflush(flush_type)
  84. int flush_type;
  85. {
  86. if (shm->Ltelnet)
  87. return;
  88. switch (flush_type)
  89. {
  90. case 0:
  91. lgetc_count = 0;
  92. ecuflush(shm->Liofd, TCIFLUSH);
  93. break;
  94. case 1:
  95. ecuflush(shm->Liofd, TCOFLUSH);
  96. break;
  97. case 2:
  98. lgetc_count = 0;
  99. ecuflush(shm->Liofd, TCIOFLUSH);
  100. break;
  101. }
  102. } /* end of lflush */
  103. /*+-------------------------------------------------------------------------
  104. lreset_ksr()
  105. This procedure restores the termio for the
  106. comm line to the values in Ltermio
  107. --------------------------------------------------------------------------*/
  108. void
  109. lreset_ksr()
  110. {
  111. if (shm->Ltelnet)
  112. return;
  113. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  114. } /* end of lreset_ksr */
  115. /*+-------------------------------------------------------------------------
  116. ldraino(inflush_flag) - wait for output to drain
  117. If inflush_flag is set, also flush input after output drains
  118. --------------------------------------------------------------------------*/
  119. void
  120. ldraino(inflush_flag)
  121. int inflush_flag;
  122. {
  123. #if defined(CFG_TermiosLineio)
  124. #if defined(sun) && !defined (SVR4)
  125. int retries = 50;
  126. int outq_count;
  127. int old_outq_count = 0;
  128. if (shm->Ltelnet)
  129. return;
  130. do
  131. {
  132. ioctl(shm->Liofd, TIOCOUTQ, &outq_count);
  133. if (!outq_count)
  134. break;
  135. if (old_outq_count == outq_count) /* don't hang if flow control
  136. * lock */
  137. retries--;
  138. old_outq_count = outq_count;
  139. Nap(50L);
  140. }
  141. while (outq_count && retries);
  142. if (inflush_flag)
  143. ecuflush(shm->Liofd, TCIFLUSH);
  144. #else /* termios but not sunos */
  145. if (shm->Ltelnet)
  146. return;
  147. tcdrain(shm->Liofd);
  148. if (inflush_flag)
  149. ecuflush(shm->Liofd, TCIFLUSH);
  150. #endif
  151. #else /* !CFG_TermiosLineio */
  152. if (shm->Ltelnet)
  153. return;
  154. ecusetattr(shm->Liofd, (inflush_flag) ? TCSETAF : TCSETAW, Ltermio);
  155. #endif
  156. } /* end of ldraino */
  157. /*+-------------------------------------------------------------------------
  158. valid_baud(baud) -- returns (positive) bit rate selector
  159. or -1 if invalid bit rate
  160. Thanks to Linux, this has become an unbelivable hack, but I
  161. have no time to handle things any better now.
  162. Linux has an unbelievable hack for baud values above 38400.
  163. (We draw a line here -- "baud rate" is a redundant, meaningless
  164. term).
  165. If you use TIOCGSERIAL/TIOCSSERIAL to get the tty's
  166. Linux-specific struct serial_struct structure, and set bits in
  167. it and plug it back with TIOCSSERIAL, then you can make Linux
  168. treat B38400 as 57600 or 115200.
  169. For Linux, 38400, 57600 and 115200 the CBAUD-style values returned
  170. values have a bit extra in them: the sign bit (2^31 anyway) is set
  171. and the proper ASYNC_SPD_MASK bits for a TIOCSSERIAL operation
  172. appear in the ASYNC_SPD_MASK << 16 position.
  173. Again, since I have so little time to document, you'll just have
  174. to look at code calling valid_baud() to see how this hack is used.
  175. --------------------------------------------------------------------------*/
  176. int
  177. valid_baud(baud)
  178. UINT baud;
  179. {
  180. int rtn = -1;
  181. switch (baud)
  182. {
  183. case 110:
  184. rtn = B110;
  185. break;
  186. case 300:
  187. rtn = B300;
  188. break;
  189. case 600:
  190. rtn = B600;
  191. break;
  192. case 1200:
  193. rtn = B1200;
  194. break;
  195. case 2400:
  196. rtn = B2400;
  197. break;
  198. case 4800:
  199. rtn = B4800;
  200. break;
  201. case 9600:
  202. rtn = B9600;
  203. break;
  204. #ifdef hpux
  205. case 19200:
  206. rtn = B19200;
  207. break;
  208. case 38400:
  209. rtn = B38400;
  210. break;
  211. #else
  212. #if 1
  213. #ifdef B19200
  214. case 19200:
  215. rtn = B19200;
  216. break;
  217. #else
  218. case 19200:
  219. rtn = EXTA;
  220. break;
  221. #endif /* B19200 */
  222. #ifdef B38400
  223. #if defined(LINUX_ASYNC_HACK)
  224. case 38400:
  225. rtn = B38400 | (0x8000 << 16);
  226. break;
  227. #else
  228. case 38400:
  229. rtn = B38400;
  230. break;
  231. #endif
  232. #else
  233. case 38400:
  234. rtn = EXTB;
  235. break;
  236. #endif /* B38400 */
  237. #endif /* 1 */
  238. #endif /* hpux */
  239. #if !defined(LINUX_ASYNC_HACK)
  240. #ifdef B57600
  241. case 57600:
  242. rtn = B57600;
  243. break;
  244. #endif
  245. #ifdef B115200
  246. case 115200:
  247. rtn = B115200;
  248. break;
  249. #endif
  250. #endif /* ~LINUX_ASYNC_HACK */
  251. /*
  252. * linux excruciating 57600 and 115200 hack
  253. */
  254. #if defined(LINUX_ASYNC_HACK)
  255. case 57600:
  256. rtn = B38400 | ((0x8000 | ASYNC_SPD_HI) << 16);
  257. break;
  258. case 115200:
  259. rtn = B38400 | ((0x8000 | ASYNC_SPD_VHI) << 16);
  260. break;
  261. #endif /* LINUX_ASYNC_HACK */
  262. default:
  263. rtn = -1;
  264. break;
  265. }
  266. return (rtn);
  267. } /* end of valid_baud */
  268. /*+-----------------------------------------------------------------------
  269. lset_baud(ioctl_flag)
  270. If 'ioctl_flag' is set, then perform ioctl call
  271. is executed after setting bit rate
  272. ------------------------------------------------------------------------*/
  273. int
  274. lset_baud(ioctl_flag)
  275. int ioctl_flag;
  276. {
  277. int cbaud_value = valid_baud(shm->Lbitrate);
  278. if (shm->Ltelnet)
  279. return (0);
  280. if (shm->Liofd < 0)
  281. return (-1);
  282. if (cbaud_value == -1)
  283. cbaud_value = valid_baud(shm->Lbitrate = CFG_DefaultBitRate);
  284. shm->Lmodem_already_init = 0;
  285. #if defined(LINUX_ASYNC_HACK)
  286. if (cbaud_value & (0x8000 << 16)) /* 38400 or above */
  287. {
  288. struct serial_struct linux_serial_hack;
  289. ioctl(shm->Liofd, TIOCGSERIAL, (char *)&linux_serial_hack);
  290. linux_serial_hack.flags &= ~ASYNC_SPD_MASK;
  291. linux_serial_hack.flags |= (cbaud_value >> 16) & ASYNC_SPD_MASK;
  292. ioctl(shm->Liofd, TIOCSSERIAL, (char *)&linux_serial_hack);
  293. cbaud_value &= CBAUD;
  294. }
  295. #endif /* LINUX_ASYNC_HACK */
  296. ecusetspeed(Ltermio, cbaud_value);
  297. if (cbaud_value < B300)
  298. Ltermio->c_cflag |= CSTOPB;
  299. else
  300. Ltermio->c_cflag &= ~CSTOPB;
  301. /*
  302. * for more info on the following monkey pus, refer to the definition
  303. * of valid_baud() somewhere in here
  304. */
  305. if (ioctl_flag)
  306. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  307. return (0);
  308. } /* end of lset_baud */
  309. /*+-------------------------------------------------------------------------
  310. display_hw_flow_config() - display hardware flow control configuration
  311. --------------------------------------------------------------------------*/
  312. #if defined(HW_FLOW_CONTROL) /* see ecu.h */
  313. void
  314. display_hw_flow_config()
  315. {
  316. #if defined(CFG_TelnetOption)
  317. if (shm->Ltelnet)
  318. {
  319. pprintf("no flow control for telnet\n");
  320. return;
  321. }
  322. #endif /* defined(CFG_TelnetOption) */
  323. #undef ____HANDLED
  324. #ifdef RTSFLOW /* SCO */
  325. #define ____HANDLED
  326. pprintf("RTSFLOW %s CTSFLOW %s",
  327. (Ltermio->c_cflag & RTSFLOW) ? "on" : "off",
  328. (Ltermio->c_cflag & CTSFLOW) ? "on" : "off");
  329. #ifdef CRTSFL
  330. pprintf(" CRTSFL %s",
  331. (Ltermio->c_cflag & CRTSFL) ? "on" : "off");
  332. #endif /* CRTSFL */
  333. pprintf("\n");
  334. #endif /* RTSFLOW */
  335. #ifdef RTSXOFF /* SVR4 */
  336. #define ____HANDLED
  337. pprintf("RTSXOFF %s CTSXON %s\n",
  338. (hx_flag & RTSXOFF) ? "on" : "off",
  339. (hx_flag & CTSXON) ? "on" : "off");
  340. #endif /* RTSXOFF */
  341. #if defined(CRTSCTS) /* sun */
  342. #define ____HANDLED
  343. pprintf(" CRTSCTS %s\n",
  344. (Ltermio->c_cflag & CRTSCTS) ? "on" : "off");
  345. #endif /* sun */
  346. #ifndef ____HANDLED
  347. porting_attention_needed_here; /* HW_FLOW_CONTROL but no recognized
  348. * flags */
  349. /*
  350. * if you are reading this because of a compilation error, you may wish to
  351. * go ahead and grep for 'RTSFLOW' and 'display_hw_flow_control' to find other
  352. * hardware control dependencies (like in lRTSCTS_control() below). This is
  353. * the only rigrous test in ECU for making sure that if HW_FLOW_CONTROL is on
  354. * we know what to do about it.
  355. */
  356. #endif /* ____HANDLED */
  357. pprintf("Flow control setting: %d\n", shm->Lrtscts_val);
  358. } /* end of display_hw_flow_config */
  359. #endif /* HW_FLOW_CONTROL */
  360. /*+-------------------------------------------------------------------------
  361. lRTSCTS_control(flag)
  362. --------------------------------------------------------------------------*/
  363. void
  364. lRTSCTS_control(flag)
  365. int flag;
  366. {
  367. #ifdef RTSXOFF /* SVR4 */
  368. struct termiox flowctrl;
  369. #endif
  370. if (shm->Liofd < 0)
  371. return;
  372. if (shm->Ltelnet)
  373. return;
  374. #ifdef RTSXOFF /* SVR4 */
  375. ioctl(shm->Liofd, TCGETX, &flowctrl);
  376. switch (flag)
  377. {
  378. case 0:
  379. flowctrl.x_hflag &= ~(RTSXOFF | CTSXON);
  380. Ltermio->c_iflag |= (IXOFF);
  381. break;
  382. case 1:
  383. flowctrl.x_hflag |= CTSXON;
  384. flowctrl.x_hflag &= ~RTSXOFF;
  385. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  386. break;
  387. case 2:
  388. flowctrl.x_hflag |= RTSXOFF;
  389. flowctrl.x_hflag &= ~CTSXON;
  390. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  391. break;
  392. case 3:
  393. flowctrl.x_hflag |= (RTSXOFF | CTSXON);
  394. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  395. break;
  396. }
  397. shm->Lxonxoff = Ltermio->c_iflag & (IXON | IXOFF);
  398. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  399. ecusetattr(shm->Liofd, TCSETX, &flowctrl);
  400. hx_flag = flowctrl.x_hflag;
  401. #else /* !SVR4 */
  402. #if defined(RTSFLOW) /* only SCO */
  403. switch (flag & 3)
  404. {
  405. case 0:
  406. Ltermio->c_iflag |= (IXOFF);
  407. Ltermio->c_cflag &= ~(RTSFLOW | CTSFLOW);
  408. break;
  409. case 1:
  410. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  411. Ltermio->c_cflag |= CTSFLOW;
  412. Ltermio->c_cflag &= ~RTSFLOW;
  413. break;
  414. case 2:
  415. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  416. Ltermio->c_cflag |= RTSFLOW;
  417. Ltermio->c_cflag &= ~CTSFLOW;
  418. break;
  419. case 3:
  420. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  421. Ltermio->c_cflag |= (RTSFLOW | CTSFLOW);
  422. break;
  423. }
  424. #if defined(CRTSFL)
  425. if (flag & 4)
  426. {
  427. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  428. Ltermio->c_cflag &= ~(RTSFLOW | CTSFLOW);
  429. Ltermio->c_cflag |= CRTSFL;
  430. }
  431. else
  432. {
  433. Ltermio->c_cflag &= ~CRTSFL;
  434. }
  435. #endif
  436. shm->Lxonxoff = Ltermio->c_iflag & (IXON | IXOFF);
  437. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  438. #else
  439. #if defined(CRTSCTS) /* sun */
  440. /*
  441. * as late as Linux 1.1.59, * CRTSCTS was #defined 020000000000 which
  442. * exceeds 32 bits; so do not expect it to work; do expect "warning:
  443. * integer overflow in expression"
  444. */
  445. switch (flag)
  446. {
  447. case 0:
  448. Ltermio->c_iflag |= (IXOFF);
  449. Ltermio->c_cflag &= -1 - CRTSCTS;
  450. break;
  451. default:
  452. Ltermio->c_iflag &= ~(IXON | IXOFF | IXANY);
  453. Ltermio->c_cflag |= CRTSCTS;
  454. break;
  455. }
  456. shm->Lxonxoff = Ltermio->c_iflag & (IXON | IXOFF);
  457. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  458. #endif /* sun */
  459. #endif /* RTSFLOW */
  460. #endif /* SVR4 */
  461. } /* end of lRTSCTS_control */
  462. /*+-------------------------------------------------------------------------
  463. lnew_bitrate(new_bitrate) - set new bit rate if valid
  464. --------------------------------------------------------------------------*/
  465. int
  466. lnew_bitrate(new_bitrate)
  467. UINT new_bitrate;
  468. {
  469. #if defined(CFG_TelnetOption)
  470. if (shm->Ltelnet)
  471. {
  472. if (!new_bitrate) /* disallow zero !!! */
  473. return (1);
  474. shm->Lbitrate = new_bitrate;
  475. return (0);
  476. }
  477. #endif /* defined(CFG_TelnetOption) */
  478. if (valid_baud(new_bitrate) == -1)
  479. return (-1);
  480. if (shm->Lbitrate != new_bitrate)
  481. shm->Lmodem_already_init = 0;
  482. shm->Lbitrate = new_bitrate;
  483. lset_baud(1);
  484. return (0);
  485. } /* end of lnew_bitrate */
  486. /*+-----------------------------------------------------------------------
  487. lset_parity(ioctl_flag)
  488. If 'ioctl_flag' is set, then perform ioctl call
  489. is executed after setting parity
  490. ------------------------------------------------------------------------*/
  491. void
  492. lset_parity(ioctl_flag)
  493. int ioctl_flag;
  494. {
  495. if (shm->Liofd < 0)
  496. return;
  497. if (shm->Ltelnet)
  498. return;
  499. Ltermio->c_cflag &= ~(CS8 | PARENB | PARODD);
  500. switch (to_lower(shm->Lparity))
  501. {
  502. case 'e':
  503. Ltermio->c_cflag |= CS7 | PARENB;
  504. Ltermio->c_iflag |= ISTRIP;
  505. break;
  506. case 'o':
  507. Ltermio->c_cflag |= CS7 | PARENB | PARODD;
  508. Ltermio->c_iflag |= ISTRIP;
  509. break;
  510. default:
  511. ff(se, "invalid parity: '%c' ... defaulting to no parity\r\n",
  512. to_lower(shm->Lparity));
  513. case 'n':
  514. shm->Lparity = 0;
  515. case 0:
  516. Ltermio->c_cflag |= CS8;
  517. Ltermio->c_iflag &= ~(ISTRIP);
  518. shm->Lparity = 0;
  519. break;
  520. }
  521. if (ioctl_flag)
  522. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  523. } /* end of lset_parity */
  524. /*+-------------------------------------------------------------------------
  525. lclear_xmtr_xoff()
  526. --------------------------------------------------------------------------*/
  527. void
  528. lclear_xmtr_xoff()
  529. {
  530. if (shm->Ltelnet)
  531. return;
  532. ecuflow(shm->Liofd, TCOON);
  533. } /* end of lclear_xmtr_xoff */
  534. /*+-------------------------------------------------------------------------
  535. lbreak()
  536. --------------------------------------------------------------------------*/
  537. void
  538. lbreak()
  539. {
  540. if (shm->Ltelnet)
  541. return;
  542. ecubreak(shm->Liofd);
  543. } /* end of lbreak */
  544. /*+-------------------------------------------------------------------------
  545. lopen_failed(sig) - see lopen() below
  546. --------------------------------------------------------------------------*/
  547. void
  548. lopen_failed(sig)
  549. int sig;
  550. {
  551. if (sig != SIGALRM)
  552. ff(se, "error %d in lopen_failed: tell wht@n4hgf\r\n", sig);
  553. longjmp(_insurance_jmpbuf, 1);
  554. } /* end of lopen_failed */
  555. /*+----------------------------------------------------------------------
  556. lopen() - open a line using shm globals for arguments
  557. returns negative LINST_ codes if failure else positive pid using line
  558. else 0 if successful open
  559. ------------------------------------------------------------------------*/
  560. enum linst
  561. lopen()
  562. {
  563. int itmp;
  564. int dummy;
  565. int tries;
  566. enum linst linst;
  567. struct stat line_stat;
  568. SIGPTR sighup_handler;
  569. #ifdef SHARE_DEBUG
  570. vlogevent(getpid(), "LOPEN1 line=%s line_lock_status=%s",
  571. shm->Lline, LINST_text(line_lock_status(shm->Lline)));
  572. #endif
  573. lopen_error_reset(); /* reset any lingering lopen_err_str contents */
  574. shm->Ltelnet = 0;
  575. errno2 = 0;
  576. /*
  577. * system independent checks
  578. */
  579. if (shm->Liofd >= 0)
  580. return (LINST_ALREADY);
  581. if (!strcmp(shm->Lline, "/dev/tty"))
  582. return (LINST_INVALID);
  583. if (stat(shm->Lline, &line_stat) < 0)
  584. {
  585. if (errno == ENOENT)
  586. return (LINST_NODEV);
  587. return (LINST_OPNFAIL);
  588. }
  589. if ((line_stat.st_mode & S_IFMT) != S_IFCHR)
  590. return (LINST_NOTCHR);
  591. if (ulindex(shm->Lline, "pty") > -1)
  592. return (LINST_NOPTY);
  593. /*
  594. * lock the tty
  595. */
  596. if ((linst = lock_tty(shm->Lline)) && (linst != LINST_WEGOTIT))
  597. return (linst);
  598. /*
  599. * if appropriate, make sure we have ungetty'd the line
  600. */
  601. #if defined(CFG_UseUngetty)
  602. if (linst != LINST_WEGOTIT)
  603. {
  604. ungetty_return_all_but(shm->Lline);
  605. if (!in_ungetty_list(shm->Lline))
  606. {
  607. if (linst = ungetty_get_line(shm->Lline))
  608. {
  609. sprintf(lopen_err_str, "ecuungetty: %s", LINST_text(linst));
  610. unlock_tty(shm->Lline);
  611. return (linst);
  612. }
  613. }
  614. }
  615. #endif
  616. /*
  617. * disable SIGHUP for now
  618. */
  619. sighup_handler = signal(SIGHUP, SIG_IGN);
  620. /*
  621. * rarely an open will hang despite our wisdom and prayer
  622. */
  623. if (setjmp(_insurance_jmpbuf))
  624. {
  625. alarm(0);
  626. signal(SIGALRM, SIG_IGN);
  627. errno = EIO;
  628. sprintf(lopen_err_str, "open error: %s", strerror(errno));
  629. unlock_tty(shm->Lline);
  630. signal(SIGHUP, sighup_handler);
  631. return (LINST_OPNFAIL);
  632. }
  633. /*
  634. * open the tty using non-blocking I/O to bypass DCD wait handle
  635. * EAGAIN for SVR4 per kortcs!tim
  636. */
  637. for (tries = 0;; ++tries)
  638. {
  639. signal(SIGALRM, lopen_failed);
  640. #ifdef sun
  641. alarm(10);
  642. #else
  643. alarm(5);
  644. #endif
  645. errno = 0;
  646. if (((shm->Liofd = open(shm->Lline, O_RDWR | O_NDELAY, 0666)) < 0) &&
  647. (errno == EACCES) && (setuid_uucp))
  648. {
  649. errno2 = EACCES;
  650. Setuid(uid_uucp);
  651. shm->Liofd = open(shm->Lline, O_RDWR | O_NDELAY, 0666);
  652. Setuid(uid);
  653. }
  654. alarm(0);
  655. signal(SIGALRM, SIG_IGN);
  656. if (shm->Liofd >= 0)
  657. break;
  658. if ((tries < 5) && (errno == EAGAIN))
  659. {
  660. (void)signal(SIGALRM, SIG_DFL);
  661. alarm(0);
  662. sleep(2);
  663. continue;
  664. }
  665. if ((errno == EACCES) || (errno2 == EACCES))
  666. {
  667. struct passwd *pw = getpwuid(line_stat.st_uid);
  668. endpwent();
  669. if (pw)
  670. {
  671. sprintf(lopen_err_str,
  672. "cannot open line owned by %s (mode=%3o)",
  673. pw->pw_name, line_stat.st_mode & 0777);
  674. }
  675. else
  676. {
  677. sprintf(lopen_err_str,
  678. "open error - try chmod +rw %s", shm->Lline);
  679. }
  680. }
  681. else
  682. sprintf(lopen_err_str, "open error: %s", strerror(errno));
  683. OPNFAIL:
  684. unlock_tty(shm->Lline);
  685. signal(SIGHUP, sighup_handler);
  686. return (LINST_OPNFAIL);
  687. }
  688. if (!isatty(shm->Liofd))
  689. {
  690. close(shm->Liofd);
  691. unlock_tty(shm->Lline);
  692. signal(SIGHUP, sighup_handler);
  693. return (LINST_NOTCHR);
  694. }
  695. /*
  696. * turn off non-blocking I/O and set initial termio, including CLOCAL
  697. * (MUST have CLOCAL on some systems)
  698. */
  699. if ((itmp = fcntl(shm->Liofd, F_GETFL, &dummy)) < 0)
  700. {
  701. sprintf(lopen_err_str, "fcntl() F_GETFL failed: %s", strerror(errno));
  702. close(shm->Liofd);
  703. unlock_tty(shm->Lline);
  704. signal(SIGHUP, sighup_handler);
  705. return (LINST_OPNFAIL);
  706. }
  707. #ifndef O_NONBLOCK
  708. #define O_NONBLOCK 0
  709. #endif
  710. itmp &= ~(O_NDELAY | O_NONBLOCK);
  711. if (fcntl(shm->Liofd, F_SETFL, itmp) < 0)
  712. {
  713. sprintf(lopen_err_str, "fcntl() F_SETFL failed: %s", strerror(errno));
  714. close(shm->Liofd);
  715. goto OPNFAIL;
  716. }
  717. ecugetattr(shm->Liofd, Ltermio);
  718. Ltermio->c_iflag = (IGNPAR | IGNBRK | shm->Lxonxoff);
  719. Ltermio->c_oflag = 0;
  720. Ltermio->c_cflag |= (CLOCAL | CREAD | HUPCL);
  721. Ltermio->c_lflag = 0;
  722. Ltermio->c_cc[VMIN] = 1;
  723. Ltermio->c_cc[VTIME] = 1;
  724. lset_baud(0); /* do not perform ioctl */
  725. lset_parity(0); /* do not perform ioctl */
  726. lRTSCTS_control(shm->Lrtscts_val); /* set hw flow control per
  727. * variable */
  728. /*
  729. * restore SIGHUP handler
  730. */
  731. signal(SIGHUP, sighup_handler);
  732. #if defined(SVR4)
  733. hx_flag = 0; /* hardware flow control "memory" */
  734. #endif
  735. #ifdef SHARE_DEBUG
  736. vlogevent(getpid(),
  737. "LOPEN2 line=%s open on fd=%d", shm->Lline, shm->Liofd);
  738. #endif
  739. lopen_error_reset();
  740. return (LINST_OK);
  741. } /* end of lopen */
  742. /*+-------------------------------------------------------------------------
  743. lclose_failed(sig) - see lclose() below
  744. --------------------------------------------------------------------------*/
  745. void
  746. lclose_failed(sig)
  747. int sig;
  748. {
  749. if (sig != SIGALRM)
  750. ff(se, "error %d in lclose_failed: tell wht@n4hgf\r\n", sig);
  751. longjmp(_insurance_jmpbuf, 1);
  752. } /* end of lclose_failed */
  753. /*+-----------------------------------------------------------------------
  754. lclose() - close the line
  755. The FAS driver and others hang on a close until all output for a line
  756. has drained. Sometimes during a hangup, a noisy XOFF can be received.
  757. Other changeces for failure include a DCE which drops CTS and leaves
  758. it off, locking the line up if there is output waiting to go out.
  759. To make sure the line is actually closed in these situations, a SIGLARM
  760. handler is used.
  761. ------------------------------------------------------------------------*/
  762. void
  763. lclose()
  764. {
  765. struct TERMIO ttio;
  766. SIGPTR sighup_handler;
  767. attempt2 = 0;
  768. #ifdef SHARE_DEBUG
  769. vlogevent(getpid(), "LCLOSE fd=%d tty=%s lock status=%s",
  770. shm->Liofd, shm->Lline,
  771. shm->Ltelnet ? "N/A" : LINST_text(line_lock_status(shm->Lline)));
  772. #endif
  773. if (shm->Liofd < 0)
  774. return;
  775. /*
  776. * telnet intercept
  777. */
  778. #if defined(CFG_TelnetOption)
  779. if (shm->Ltelnet)
  780. {
  781. close(shm->Liofd);
  782. shm->Liofd = -1;
  783. shm->Ltelnet = 0;
  784. return;
  785. }
  786. #endif /* defined(CFG_TelnetOption) */
  787. /*
  788. * disable SIGHUP for now
  789. */
  790. sighup_handler = signal(SIGHUP, SIG_IGN);
  791. /*
  792. * endless loop because we cannot get out anyway unless success
  793. */
  794. attempt2 = 0;
  795. ATTEMPT:
  796. signal(SIGALRM, lclose_failed);
  797. #ifdef sun
  798. alarm(10);
  799. #else
  800. alarm(5);
  801. #endif
  802. if (setjmp(_insurance_jmpbuf))
  803. { /* close failed */
  804. signal(SIGALRM, SIG_IGN);
  805. alarm(0);
  806. ff(se, "\r\nclose failed (remote XOFF?) ... retrying close\r\n");
  807. lclear_xmtr_xoff();
  808. ttio = *Ltermio;
  809. ttio.c_iflag &= ~(IXON | IXOFF);
  810. ttio.c_cflag &= (CSIZE | CSTOPB | CREAD | PARENB | PARODD);
  811. ecusetattr(shm->Liofd, TCSETA, &ttio);
  812. lflush(2);
  813. attempt2 = 1;
  814. goto ATTEMPT;
  815. }
  816. if (!attempt2)
  817. {
  818. lclear_xmtr_xoff();
  819. ldraino(1);
  820. }
  821. lCLOCAL(1);
  822. close(shm->Liofd);
  823. shm->Liofd = -1;
  824. signal(SIGALRM, SIG_IGN);
  825. alarm(0);
  826. unlock_tty(shm->Lline);
  827. shm->Lmodem_already_init = 0;
  828. shm->Lconnected = 0;
  829. /*
  830. * restore SIGHUP handler
  831. */
  832. signal(SIGHUP, sighup_handler);
  833. } /* end of lclose */
  834. /*+-------------------------------------------------------------------------
  835. lflash_dtr() - flash DTR
  836. DTR is lowered for 500 msec and raised again. After raising,
  837. we pause a while for a possibly slow DCE to rereap it's fecal material.
  838. This not long enough for some DCE, but -hey- this isn't an X11 program
  839. with a 50Kb app-defaults file.
  840. expects: Ltermio - current termio status of line
  841. shm->Liofd - current line fd
  842. shm->Lline - /dev/ttyxx name of line
  843. On SVR4, an open/close of the line is required to get DTR back
  844. up. SVR3 does not seem to need this (ISC asy, SCO sio, Uwe Doering's FAS)
  845. but we do it anyway
  846. On SunOS, we use an old mechanism, but one that is very effective
  847. and painless
  848. --------------------------------------------------------------------------*/
  849. void
  850. lflash_dtr()
  851. {
  852. #if defined(ESIXSVR4) /* thanx for fix to yzrnur!rene (Rene Lampe) */
  853. int z = TIOCM_DTR | TIOCM_RTS;
  854. if (shm->Ltelnet)
  855. return;
  856. ioctl(shm->Liofd, TIOCMBIC, &z); /* Clear DTR */
  857. Nap(500L); /* time for DTR to be low */
  858. ioctl(shm->Liofd, TIOCMBIS, &z); /* Set DTR */
  859. Nap(300L); /* nap to give a lazy DCE some time */
  860. #else
  861. #if defined(TIOCCDTR) && defined(TIOCSDTR) /* sun */
  862. if (shm->Ltelnet)
  863. return;
  864. ioctl(shm->Liofd, TIOCCDTR, 0); /* drop DTR */
  865. #ifndef sun
  866. Nap(500L); /* sun takes forEVER */
  867. #endif
  868. ioctl(shm->Liofd, TIOCSDTR, 0); /* raise DTR */
  869. #ifndef sun
  870. Nap(100L);
  871. #endif
  872. #else /* not BSD-style */
  873. #undef NEED_REOPEN
  874. #if defined(SVR4)
  875. #define NEED_REOPEN
  876. int tempfd;
  877. #endif
  878. struct TERMIO b0t;
  879. if (shm->Ltelnet)
  880. return;
  881. /*
  882. * copy termio but CBAUD to B0
  883. */
  884. b0t = *Ltermio;
  885. b0t.c_cflag &= ~CBAUD; /* B0 */
  886. /*
  887. * drop DTR for a while
  888. */
  889. ecusetattr(shm->Liofd, TCSETA, &b0t); /* drop DTR */
  890. /*
  891. * DTR will not come back on some systems without open/close line
  892. */
  893. #ifdef NEED_REOPEN
  894. if (((tempfd = open(shm->Lline, O_NDELAY | O_RDWR, 0666)) < 0) &&
  895. (errno == EACCES) && (setuid_uucp))
  896. {
  897. Setuid(uid_uucp);
  898. tempfd = open(shm->Lline, O_NDELAY | O_RDWR, 0666);
  899. Setuid(uid);
  900. }
  901. if (tempfd != -1)
  902. close(tempfd);
  903. else
  904. {
  905. int save_errno = errno;
  906. char s128[128];
  907. sprintf(s128, "FLASH DTR line reopen failed (%.90s)",
  908. strerror(errno));
  909. logevent(shm->xmtr_pid, s128);
  910. pputs(s128);
  911. pputs("\n");
  912. errno = save_errno;
  913. termecu(TERMECU_LINE_OPEN_ERROR);
  914. }
  915. #else
  916. /*
  917. * ensure DTR low for 500 msec (the tempfd open/close takes plenty
  918. * long enough)
  919. */
  920. Nap(500L);
  921. #endif
  922. /*
  923. * reestablish bit rate (raise DTR if the open/close line did not do
  924. * it)
  925. */
  926. ecusetattr(shm->Liofd, TCSETA, Ltermio); /* raise DTR */
  927. Nap(300L); /* nap to give a lazy DCE some time */
  928. #undef NEED_REOPEN
  929. #endif /* defined(TIOCCDTR) && defined(TIOCSDTR) */
  930. #endif /* defined(ESIXSVR4) */
  931. } /* end of lflash_dtr */
  932. /*+-------------------------------------------------------------------------
  933. lxon_xoff(flag)
  934. IXON specifies whether or not we respond to xon/xoff characters
  935. IXOFF specifies whether or not we generate XON/XOFF characters
  936. --------------------------------------------------------------------------*/
  937. void
  938. lxon_xoff(flag)
  939. int flag;
  940. {
  941. if (shm->Ltelnet)
  942. return;
  943. if (flag & IXON)
  944. Ltermio->c_iflag |= IXON;
  945. else
  946. Ltermio->c_iflag &= ~IXON;
  947. if (flag & IXOFF)
  948. Ltermio->c_iflag |= IXOFF;
  949. else
  950. Ltermio->c_iflag &= ~IXOFF;
  951. shm->Lxonxoff = Ltermio->c_iflag & (IXON | IXOFF);
  952. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  953. } /* end of lflash_dtr */
  954. /*+-------------------------------------------------------------------------
  955. lget_xon_xoff(ixon,ixoff)
  956. --------------------------------------------------------------------------*/
  957. void
  958. lget_xon_xoff(ixon, ixoff)
  959. int *ixon;
  960. int *ixoff;
  961. {
  962. #if defined(CFG_TelnetOption)
  963. if (shm->Ltelnet)
  964. {
  965. *ixon = 0;
  966. *ixoff = 0;
  967. return;
  968. }
  969. #endif /* defined(CFG_TelnetOption) */
  970. *ixon = Ltermio->c_iflag & IXON;
  971. *ixoff = Ltermio->c_iflag & IXOFF;
  972. } /* end of lget_xon_xoff */
  973. /*+-------------------------------------------------------------------------
  974. set_xon_xoff_by_arg(arg)
  975. --------------------------------------------------------------------------*/
  976. int
  977. set_xon_xoff_by_arg(arg)
  978. char *arg;
  979. {
  980. if (ulcmpb(arg, "on") < 0)
  981. shm->Lxonxoff = IXON | IXOFF;
  982. else if (ulcmpb(arg, "off") < 0)
  983. shm->Lxonxoff = 0;
  984. else if (ulcmpb(arg, "out") < 0)
  985. shm->Lxonxoff = IXON;
  986. else if (ulcmpb(arg, "in") < 0)
  987. shm->Lxonxoff = IXOFF;
  988. else
  989. return (-1);
  990. if (shm->Ltelnet)
  991. return (0);
  992. if (shm->Liofd < 0)
  993. return (0);
  994. Ltermio->c_iflag &= ~(IXON | IXOFF);
  995. Ltermio->c_iflag |= shm->Lxonxoff;
  996. ecusetattr(shm->Liofd, TCSETA, Ltermio);
  997. return (0);
  998. } /* end of set_xon_xoff_by_arg */
  999. /*+-------------------------------------------------------------------------
  1000. xon_status()
  1001. --------------------------------------------------------------------------*/
  1002. char *
  1003. xon_status()
  1004. {
  1005. #if defined(CFG_TelnetOption)
  1006. if (shm->Ltelnet)
  1007. return ("telnet");
  1008. #endif /* defined(CFG_TelnetOption) */
  1009. switch (shm->Lxonxoff)
  1010. {
  1011. case 0:
  1012. return ("off");
  1013. case IXON:
  1014. return ("in off, out on");
  1015. case IXOFF:
  1016. return ("in on, out off");
  1017. case IXON | IXOFF:
  1018. return ("on");
  1019. }
  1020. return ("logic error");
  1021. } /* end of xon_status */
  1022. /*+-------------------------------------------------------------------------
  1023. lCLOCAL(flag) - set line CLOCAL state
  1024. flag == 0: turn off CLOCAL to catch DCD loss
  1025. == 1: turn on CLOCAL to ignore modem signals
  1026. does not let CLOCAL be turned off if not Lconnected
  1027. also resets global zero_length_read_detected
  1028. --------------------------------------------------------------------------*/
  1029. void
  1030. lCLOCAL(flag)
  1031. int flag;
  1032. {
  1033. if (shm->Ltelnet)
  1034. return;
  1035. if (flag)
  1036. Ltermio->c_cflag |= CLOCAL;
  1037. else if (shm->Lconnected)
  1038. Ltermio->c_cflag &= ~CLOCAL;
  1039. else
  1040. Ltermio->c_cflag |= CLOCAL;
  1041. zero_length_read_detected = 0;
  1042. lreset_ksr(); /* do the ioctl */
  1043. #ifdef CLOCAL_DEBUG
  1044. {
  1045. char s128[128];
  1046. sprintf(s128, "lCLOCAL(%d) connected=%c CLOCAL set %o",
  1047. flag, shm->Lconnected ? 'y' : 'n', Ltermio->c_cflag & CLOCAL ? 1 : 0);
  1048. logevent((int)xmtr_pid, s128);
  1049. pprintf("%s\n", s128);
  1050. }
  1051. #endif
  1052. } /* end of lCLOCAL */
  1053. /*+-------------------------------------------------------------------------
  1054. ldcdwatch(flag) - set DCD watcher state
  1055. --------------------------------------------------------------------------*/
  1056. void
  1057. ldcdwatch(flag)
  1058. int flag;
  1059. {
  1060. shm->Ldcdwatch = flag;
  1061. dcdwatch_set = 1;
  1062. lCLOCAL(!flag);
  1063. } /* end of ldcdwatch */
  1064. /*+-------------------------------------------------------------------------
  1065. ldcdwatch_str(flagstr) - string version of ldcdwatch
  1066. return 0 if successful or -1 if bad flagstr
  1067. --------------------------------------------------------------------------*/
  1068. int
  1069. ldcdwatch_str(flagstr)
  1070. char *flagstr;
  1071. {
  1072. static STR_CLASSIFY sc[] =
  1073. {
  1074. {"1", 1, DCDW_ON},
  1075. {"yes", 1, DCDW_ON},
  1076. {"on", 2, DCDW_ON},
  1077. {"0", 1, DCDW_ON},
  1078. {"no", 1, DCDW_OFF},
  1079. {"off", 3, DCDW_OFF},
  1080. {"terminate", 1, DCDW_TERMINATE},
  1081. {(char *)0, 0, -1}
  1082. };
  1083. int token;
  1084. if ((token = str_classify(sc, flagstr)) < 0)
  1085. return (-1);
  1086. ldcdwatch(token);
  1087. return (0);
  1088. } /* end of ldcdwatch_str */
  1089. /*+-------------------------------------------------------------------------
  1090. lzero_length_read_detected() - read from line returned zero length
  1091. This must mean CLOCAL was off and DCD is/went low. We do different things
  1092. depending in the xmtr and rcvr process
  1093. If we return, the condition has ben handled and reads may be retried
  1094. safely or other appropriate operations performed; otherwise ECU is
  1095. terminated.
  1096. --------------------------------------------------------------------------*/
  1097. void
  1098. lzero_length_read_detected()
  1099. {
  1100. zero_length_read_detected = 1;
  1101. if (getpid() == xmtr_pid)/* if we are in the transmitter */
  1102. {
  1103. #ifdef CLOCAL_DEBUG
  1104. logevent((int)xmtr_pid, "lzero xmtr");
  1105. pprintf("lzero xmtr\n");
  1106. #endif
  1107. if (!shm->Lconnected)
  1108. lCLOCAL(1);
  1109. else
  1110. {
  1111. extern UINT32 colors_current;
  1112. UINT32 colors_at_entry = colors_current;
  1113. fputs("\r\n", se);
  1114. setcolor(colors_notify);
  1115. fputs("[connection terminated]", se);
  1116. setcolor(colors_at_entry);
  1117. fputs("\r\n", se);
  1118. DCE_now_on_hook(); /* does a lCLOCAL(1); */
  1119. }
  1120. Nap(1000L);
  1121. lflush(2);
  1122. if (shm->Ldcdwatch == DCDW_TERMINATE)
  1123. termecu(TERMECU_OK);
  1124. shmx_unpause_rcvr();
  1125. }
  1126. else
  1127. {
  1128. /*
  1129. * we are in the receiver
  1130. */
  1131. #ifdef CLOCAL_DEBUG
  1132. logevent((int)xmtr_pid, "lzero rcvr");
  1133. pprintf("lzero rcvr\n");
  1134. #endif
  1135. /*
  1136. * make line "safe" to read from immediately; however, if CLOCAL
  1137. * was set and we get a zero length read, we are in some kind of
  1138. * unknown trouble
  1139. */
  1140. if (Ltermio->c_cflag & CLOCAL) /* zero len read with CLOCAL? */
  1141. { /* then die ECU */
  1142. #ifdef linux
  1143. termecu(TERMECU_OK); /* exit gracefully */
  1144. #else
  1145. errno = EIO;
  1146. termecu(TERMECU_LINE_READ_ERROR);
  1147. #endif
  1148. }
  1149. lCLOCAL(1);
  1150. shmr_notify_xmtr_of_DCD_loss();
  1151. pause(); /* wait for unpause */
  1152. }
  1153. } /* end of lzero_length_read_detected */