1 /* CTC_LCS.C    (c) Copyright James A. Pierson, 2002-2012            */
2 /*              (c) Copyright "Fish" (David B. Trout), 2002-2011     */
3 /*              Hercules LAN Channel Station Support                 */
4 
5 #include "hstdinc.h"
6 
7 /* jbs 10/27/2007 added _SOLARIS_ */
8 #if !defined(__SOLARIS__)
9 
10 #include "hercules.h"
11 #include "ctcadpt.h"
12 #include "tuntap.h"
13 #include "hercifc.h"
14 #include "opcode.h"
15 #include "herc_getopt.h"
16 #if defined(OPTION_W32_CTCI)
17 #include "tt32api.h"
18 #endif
19 
20 //-----------------------------------------------------------------------------
21 // Debugging...
22 
23 //#define NO_LCS_OPTIMIZE     // #undef for Release, #define while testing
24 
25 #if !defined( DEBUG) && !defined( _DEBUG )  // only needed for Release builds
26   #ifdef NO_LCS_OPTIMIZE                    // for reliable breakpoints and instr stepping
27     #pragma optimize( "", off )             // disable optimizations for reliable breakpoints
28     #pragma warning( push )                 // save current settings
29     #pragma warning( disable: 4748 )        // C4748:  /GS can not ... because optimizations are disabled...
30   #endif // NO_LCS_OPTIMIZE
31 #endif // !defined( DEBUG) && !defined( _DEBUG )
32 
33 #ifdef NO_LCS_OPTIMIZE
34 
35   #undef  ASSERT
36   #undef  VERIFY
37 
38   #ifdef _MSVC_
39 
40     #define ASSERT(a) \
41       do \
42       { \
43         if (!(a)) \
44         { \
45           logmsg("HHCxx999W *** Assertion Failed! *** %s(%d); function: %s\n",__FILE__,__LINE__,__FUNCTION__); \
46           if (IsDebuggerPresent()) DebugBreak();   /* (break into debugger) */ \
47         } \
48       } \
49       while(0)
50 
51   #else // ! _MSVC_
52 
53     #define ASSERT(a) \
54       do \
55       { \
56         if (!(a)) \
57         { \
58           logmsg("HHCxx999W *** Assertion Failed! *** %s(%d)\n",__FILE__,__LINE__); \
59         } \
60       } \
61       while(0)
62 
63   #endif // _MSVC_
64 
65   #define VERIFY(a)   ASSERT((a))
66 
67 #endif // NO_LCS_OPTIMIZE
68 
69 //-----------------------------------------------------------------------------
70 /* CCW Codes 0x03 & 0xC3 are immediate commands */
71 
72 static BYTE  CTC_Immed_Commands [256] =
73 {
74 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
75    0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 00 */
76    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10 */
77    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20 */
78    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 30 */
79    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */
80    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
81    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */
82    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
83    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
84    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */
85    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */
86    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */
87    0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */
88    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
89    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
90    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  /* F0 */
91 };
92 
93 // ====================================================================
94 //                       Declarations
95 // ====================================================================
96 
97 static void     LCS_Startup       ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
98 static void     LCS_Shutdown      ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
99 static void     LCS_StartLan      ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
100 static void     LCS_StopLan       ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
101 static void     LCS_QueryIPAssists( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
102 static void     LCS_LanStats      ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
103 static void     LCS_DefaultCmdProc( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame );
104 
105 static void*    LCS_PortThread( PLCSPORT pLCSPORT );
106 
107 static int      LCS_EnqueueEthFrame( PLCSDEV pLCSDEV, BYTE   bPort,
108                                      BYTE*   pData,   size_t iSize );
109 
110 static int      LCS_EnqueueReplyFrame( PLCSDEV pLCSDEV, PLCSCMDHDR pReply,
111                                                         size_t     iSize );
112 
113 static int      BuildOAT( char* pszOATName, PLCSBLK pLCSBLK );
114 static char*    ReadOAT( char* pszOATName, FILE* fp, char* pszBuff );
115 static int      ParseArgs( DEVBLK* pDEVBLK, PLCSBLK pLCSBLK,
116                            int argc, char** argv );
117 
118 // ====================================================================
119 //                       Helper macros
120 // ====================================================================
121 
122 #define INIT_REPLY_FRAME( reply, pCmdFrame )                \
123                                                             \
124     memset( &(reply), 0, sizeof( reply ));                  \
125     memcpy( &(reply), (pCmdFrame), sizeof( LCSCMDHDR ));    \
126     STORE_HW( (reply).bLCSCmdHdr.hwReturnCode, 0x0000 )
127 
128 #define ENQUEUE_REPLY_FRAME( pLCSDEV, reply )                               \
129                                                                             \
130     while                                                                   \
131     (1                                                                      \
132         && LCS_EnqueueReplyFrame( (pLCSDEV), (PLCSCMDHDR) &(reply),         \
133                                                     sizeof( reply )) != 0   \
134         &&  (pLCSDEV)->pLCSBLK->Port[(pLCSDEV)->bPort].fd != -1             \
135         && !(pLCSDEV)->pLCSBLK->Port[(pLCSDEV)->bPort].fCloseInProgress     \
136     )                                                                       \
137     {                                                                       \
138         TRACE("** ENQUEUE_REPLY_FRAME() failed...\n");                      \
139         SLEEP( 1 );                                                         \
140     }
141 
142 // ====================================================================
143 //                    find_group_device
144 // ====================================================================
145 
find_group_device(DEVGRP * group,U16 devnum)146 static DEVBLK * find_group_device(DEVGRP *group, U16 devnum)
147 {
148     int i;
149 
150     for(i = 0; i < group->acount; i++)
151         if( group->memdev[i]->devnum == devnum )
152             return group->memdev[i];
153 
154     return NULL;
155 }
156 
157 // ====================================================================
158 //                          LCS_Init
159 // ====================================================================
160 
LCS_Init(DEVBLK * pDEVBLK,int argc,char * argv[])161 int  LCS_Init( DEVBLK* pDEVBLK, int argc, char *argv[] )
162 {
163     PLCSBLK     pLCSBLK;
164     PLCSDEV     pLCSDev;
165     int         i;
166 
167     struct in_addr  addr;               // Work area for addresses
168 
169     pDEVBLK->devtype = 0x3088;
170 
171     // Return when an existing group has been joined but is still incomplete
172     if(!group_device(pDEVBLK, 0) && pDEVBLK->group)
173         return 0;
174 
175     // We need to create a group, and as such determine the number of devices
176     if(!pDEVBLK->group)
177     {
178 
179         // Housekeeping
180         pLCSBLK = malloc( sizeof( LCSBLK ) );
181         if( !pLCSBLK )
182         {
183             logmsg( _("HHCLC001E %4.4X unable to allocate LCSBLK\n"),
184                     pDEVBLK->devnum );
185             return -1;
186         }
187         memset( pLCSBLK, 0, sizeof( LCSBLK ) );
188 
189         for( i = 0; i < LCS_MAX_PORTS; i++ )
190         {
191             memset( &pLCSBLK->Port[i], 0, sizeof ( LCSPORT ) );
192 
193             pLCSBLK->Port[i].bPort   = i;
194             pLCSBLK->Port[i].pLCSBLK = pLCSBLK;
195 
196             // Initialize locking and event mechanisms
197             initialize_lock( &pLCSBLK->Port[i].Lock );
198             initialize_lock( &pLCSBLK->Port[i].EventLock );
199             initialize_condition( &pLCSBLK->Port[i].Event );
200         }
201 
202         // Parse configuration file statement
203         if( ParseArgs( pDEVBLK, pLCSBLK, argc, (char**)argv ) != 0 )
204         {
205             free( pLCSBLK );
206             pLCSBLK = NULL;
207             return -1;
208         }
209 
210         if( pLCSBLK->pszOATFilename )
211         {
212             // If an OAT file was specified, Parse it and build the
213             // OAT table.
214             if( BuildOAT( pLCSBLK->pszOATFilename, pLCSBLK ) != 0 )
215             {
216                 free( pLCSBLK );
217                 pLCSBLK = NULL;
218                 return -1;
219             }
220         }
221         else
222         {
223             // Otherwise, build an OAT based on the address specified
224             // in the config file with an assumption of IP mode.
225             pLCSBLK->pDevices = malloc( sizeof( LCSDEV ) );
226 
227             memset( pLCSBLK->pDevices, 0, sizeof( LCSDEV ) );
228 
229             if( pLCSBLK->pszIPAddress )
230                 inet_aton( pLCSBLK->pszIPAddress, &addr );
231 
232             pLCSBLK->pDevices->sAddr        = pDEVBLK->devnum;
233             pLCSBLK->pDevices->bMode        = LCSDEV_MODE_IP;
234             pLCSBLK->pDevices->bPort        = 0;
235             pLCSBLK->pDevices->bType        = 0;
236             pLCSBLK->pDevices->lIPAddress   = addr.s_addr; // (network byte order)
237             pLCSBLK->pDevices->pszIPAddress = pLCSBLK->pszIPAddress;
238             pLCSBLK->pDevices->pNext        = NULL;
239 
240             pLCSBLK->icDevices = 2;
241         }
242 
243         // Now we must create the group
244         if(!group_device(pDEVBLK, pLCSBLK->icDevices))
245         {
246             pDEVBLK->group->grp_data = pLCSBLK;
247             return 0;
248         }
249         else
250             pDEVBLK->group->grp_data = pLCSBLK;
251 
252     }
253     else
254         pLCSBLK = pDEVBLK->group->grp_data;
255 
256     // When this code is reached the last devblk has been allocated...
257     //
258     // Now build the LCSDEV's.
259     // If an OAT is specified, the addresses that were specified in the
260     // hercules.cnf file must match those that are specified in the OAT.
261 
262     for( pLCSDev = pLCSBLK->pDevices; pLCSDev; pLCSDev = pLCSDev->pNext )
263     {
264         pLCSDev->pDEVBLK[0] = find_group_device(pDEVBLK->group, pLCSDev->sAddr);
265 
266         if( !pLCSDev->pDEVBLK[0] )
267         {
268             logmsg(D_("HHCLC040E %4.4X LCSDEV %4.4X not in configuration\n"),
269                 pDEVBLK->group->memdev[0]->devnum, pLCSDev->sAddr );
270             return -1;
271         }
272 
273         // Establish SENSE ID and Command Information Word data.
274         SetSIDInfo( pLCSDev->pDEVBLK[0], 0x3088, 0x60, 0x3088, 0x01 );
275 //      SetCIWInfo( pLCSDev->pDEVBLK[0], 0, 0, 0x72, 0x0080 );
276 //      SetCIWInfo( pLCSDev->pDEVBLK[0], 1, 1, 0x83, 0x0004 );
277 //      SetCIWInfo( pLCSDev->pDEVBLK[0], 2, 2, 0x82, 0x0040 );
278 
279         pLCSDev->pDEVBLK[0]->ctctype  = CTC_LCS;
280         pLCSDev->pDEVBLK[0]->ctcxmode = 1;
281         pLCSDev->pDEVBLK[0]->dev_data = pLCSDev;
282         pLCSDev->pLCSBLK              = pLCSBLK;
283         strcpy( pLCSDev->pDEVBLK[0]->filename, pLCSBLK->pszTUNDevice );
284 
285         // If this is an IP Passthru address, we need a write address
286         if( pLCSDev->bMode == LCSDEV_MODE_IP )
287         {
288             pLCSDev->pDEVBLK[1] = find_group_device(pDEVBLK->group, pLCSDev->sAddr^1);
289 
290             if( !pLCSDev->pDEVBLK[1] )
291             {
292                 logmsg(D_("HHCLC040E %4.4X LCSDEV %4.4X not in configuration\n"),
293                     pDEVBLK->group->memdev[0]->devnum, pLCSDev->sAddr^1 );
294                 return -1;
295             }
296 
297             // Establish SENSE ID and Command Information Word data.
298             SetSIDInfo( pLCSDev->pDEVBLK[1], 0x3088, 0x60, 0x3088, 0x01 );
299 //          SetCIWInfo( pLCSDev->pDEVBLK[1], 0, 0, 0x72, 0x0080 );
300 //          SetCIWInfo( pLCSDev->pDEVBLK[1], 1, 1, 0x83, 0x0004 );
301 //          SetCIWInfo( pLCSDev->pDEVBLK[1], 2, 2, 0x82, 0x0040 );
302 
303             pLCSDev->pDEVBLK[1]->ctctype  = CTC_LCS;
304             pLCSDev->pDEVBLK[1]->ctcxmode = 1;
305             pLCSDev->pDEVBLK[1]->dev_data = pLCSDev;
306 
307             strcpy( pLCSDev->pDEVBLK[1]->filename, pLCSBLK->pszTUNDevice );
308         }
309 
310         // Indicate that the DEVBLK(s) have been create sucessfully
311         pLCSDev->fCreated = 1;
312 
313         // Initialize locking and event mechanisms
314         initialize_lock( &pLCSDev->Lock );
315         initialize_lock( &pLCSDev->EventLock );
316         initialize_condition( &pLCSDev->Event );
317 
318         // Create the TAP interface (if not already created by a
319         // previous pass. More than one interface can exist on a port.
320         if( !pLCSBLK->Port[pLCSDev->bPort].fCreated )
321         {
322             int   rc;
323 
324             rc = TUNTAP_CreateInterface( pLCSBLK->pszTUNDevice,
325                                          IFF_TAP | IFF_NO_PI,
326                                          &pLCSBLK->Port[pLCSDev->bPort].fd,
327                                          pLCSBLK->Port[pLCSDev->bPort].szNetDevName );
328 
329             logmsg(_("HHCLC073I %4.4X: TAP device %s opened\n"),
330                       pLCSDev->pDEVBLK[0]->devnum,
331                       pLCSBLK->Port[pLCSDev->bPort].szNetDevName);
332 
333 #if defined(OPTION_W32_CTCI)
334 
335             // Set the specified driver/dll i/o buffer sizes..
336             {
337                 struct tt32ctl tt32ctl;
338 
339                 memset( &tt32ctl, 0, sizeof(tt32ctl) );
340                 strlcpy( tt32ctl.tt32ctl_name, pLCSBLK->Port[pLCSDev->bPort].szNetDevName, sizeof(tt32ctl.tt32ctl_name) );
341 
342                 tt32ctl.tt32ctl_devbuffsize = pLCSBLK->iKernBuff;
343                 if( TUNTAP_IOCtl( pLCSBLK->Port[pLCSDev->bPort].fd, TT32SDEVBUFF, (char*)&tt32ctl ) != 0  )
344                 {
345                     logmsg( _("HHCLC074W TT32SDEVBUFF failed for device %s: %s.\n"),
346                             pLCSBLK->Port[pLCSDev->bPort].szNetDevName, strerror( errno ) );
347                 }
348 
349                 tt32ctl.tt32ctl_iobuffsize = pLCSBLK->iIOBuff;
350                 if( TUNTAP_IOCtl( pLCSBLK->Port[pLCSDev->bPort].fd, TT32SIOBUFF, (char*)&tt32ctl ) != 0  )
351                 {
352                     logmsg( _("HHCLC075W TT32SIOBUFF failed for device %s: %s.\n"),
353                             pLCSBLK->Port[pLCSDev->bPort].szNetDevName, strerror( errno ) );
354                 }
355             }
356 #endif
357 
358             // Indicate that the port is used.
359             pLCSBLK->Port[pLCSDev->bPort].fUsed    = 1;
360             pLCSBLK->Port[pLCSDev->bPort].fCreated = 1;
361 
362             create_thread( &pLCSBLK->Port[pLCSDev->bPort].tid,
363                            JOINABLE, LCS_PortThread,
364                            &pLCSBLK->Port[pLCSDev->bPort],
365                            "LCS_PortThread" );
366 
367             /* Identify the thread ID with the devices on which they are active */
368             pLCSDev->pDEVBLK[0]->tid = pLCSBLK->Port[pLCSDev->bPort].tid;
369             if (pLCSDev->pDEVBLK[1])
370                 pLCSDev->pDEVBLK[1]->tid = pLCSBLK->Port[pLCSDev->bPort].tid;
371         }
372 
373         // Add these devices to the ports device list.
374         pLCSBLK->Port[pLCSDev->bPort].icDevices++;
375         pLCSDev->pDEVBLK[0]->fd = pLCSBLK->Port[pLCSDev->bPort].fd;
376 
377         if( pLCSDev->pDEVBLK[1] )
378             pLCSDev->pDEVBLK[1]->fd = pLCSBLK->Port[pLCSDev->bPort].fd;
379     }
380 
381     return 0;
382 }
383 
384 // ====================================================================
385 //                      LCS_ExecuteCCW
386 // ====================================================================
387 
LCS_ExecuteCCW(DEVBLK * pDEVBLK,BYTE bCode,BYTE bFlags,BYTE bChained,U16 sCount,BYTE bPrevCode,int iCCWSeq,BYTE * pIOBuf,BYTE * pMore,BYTE * pUnitStat,U16 * pResidual)388 void  LCS_ExecuteCCW( DEVBLK* pDEVBLK, BYTE  bCode,
389                       BYTE    bFlags,  BYTE  bChained,
390                       U16     sCount,  BYTE  bPrevCode,
391                       int     iCCWSeq, BYTE* pIOBuf,
392                       BYTE*   pMore,   BYTE* pUnitStat,
393                       U16*    pResidual )
394 {
395     int             iNum;               // Number of bytes to move
396     BYTE            bOpCode;            // CCW opcode with modifier
397                                         //   bits masked off
398 
399     UNREFERENCED( bFlags    );
400     UNREFERENCED( bChained  );
401     UNREFERENCED( bPrevCode );
402     UNREFERENCED( iCCWSeq   );
403 
404     // Intervention required if the device file is not open
405     if( pDEVBLK->fd < 0 &&
406         !IS_CCW_SENSE( bCode ) &&
407         !IS_CCW_CONTROL( bCode ) )
408     {
409         pDEVBLK->sense[0] = SENSE_IR;
410         *pUnitStat = CSW_CE | CSW_DE | CSW_UC;
411         return;
412     }
413 
414     // Mask off the modifier bits in the CCW bOpCode
415     if( ( bCode & 0x07 ) == 0x07 )
416         bOpCode = 0x07;
417     else if( ( bCode & 0x03 ) == 0x02 )
418         bOpCode = 0x02;
419     else if( ( bCode & 0x0F ) == 0x0C )
420         bOpCode = 0x0C;
421     else if( ( bCode & 0x03 ) == 0x01 )
422         bOpCode = pDEVBLK->ctcxmode ? ( bCode & 0x83 ) : 0x01;
423     else if( ( bCode & 0x1F ) == 0x14 )
424         bOpCode = 0x14;
425     else if( ( bCode & 0x47 ) == 0x03 )
426         bOpCode = 0x03;
427     else if( ( bCode & 0xC7 ) == 0x43 )
428         bOpCode = 0x43;
429 #if 0
430     // Special case for LCS CIW's
431     else if( ( bCode == 72 || bCode == 82 || bCode == 83 ) )
432         bOpCode == bCode;
433 #endif
434     else
435         bOpCode = bCode;
436 
437 
438     // Process depending on CCW bOpCode
439     switch (bOpCode)
440     {
441     case 0x01:  // 0MMMMM01  WRITE
442         //------------------------------------------------------------
443         // WRITE
444         //------------------------------------------------------------
445 
446         // Return normal status if CCW count is zero
447         if( sCount == 0 )
448         {
449             *pUnitStat = CSW_CE | CSW_DE;
450             break;
451         }
452 
453         LCS_Write( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual );
454 
455         break;
456 
457     case 0x81:  // 1MMMMM01  WEOF
458         //------------------------------------------------------------
459         // WRITE EOF
460         //------------------------------------------------------------
461 
462         // Return normal status
463         *pUnitStat = CSW_CE | CSW_DE;
464         break;
465 
466     case 0x02:  // MMMMMM10  READ
467     case 0x0C:  // MMMM1100  RDBACK
468         // -----------------------------------------------------------
469         // READ & READ BACKWARDS
470         // -----------------------------------------------------------
471 
472         // Read data and set unit status and residual byte count
473         LCS_Read( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual, pMore );
474 
475         break;
476 
477     case 0x07:  // MMMMM111  CTL
478         // -----------------------------------------------------------
479         // CONTROL
480         // -----------------------------------------------------------
481 
482         *pUnitStat = CSW_CE | CSW_DE;
483         break;
484 
485     case 0x03:  // M0MMM011  NOP
486         // -----------------------------------------------------------
487         // CONTROL NO-OPERATON
488         // -----------------------------------------------------------
489 
490         *pUnitStat = CSW_CE | CSW_DE;
491         break;
492 
493     case 0x43:  // 00XXX011  SBM
494         // -----------------------------------------------------------
495         // SET BASIC MODE
496         // -----------------------------------------------------------
497 
498         // Command reject if in basic mode
499         if( pDEVBLK->ctcxmode == 0 )
500         {
501             pDEVBLK->sense[0] = SENSE_CR;
502             *pUnitStat        = CSW_CE | CSW_DE | CSW_UC;
503 
504             break;
505         }
506 
507         // Reset extended mode and return normal status
508         pDEVBLK->ctcxmode = 0;
509 
510         *pResidual = 0;
511         *pUnitStat = CSW_CE | CSW_DE;
512 
513         break;
514 
515     case 0xC3:  // 11000011  SEM
516         // -----------------------------------------------------------
517         // SET EXTENDED MODE
518         // -----------------------------------------------------------
519 
520         pDEVBLK->ctcxmode = 1;
521 
522         *pResidual = 0;
523         *pUnitStat = CSW_CE | CSW_DE;
524 
525         break;
526 
527     case 0xE3:  // 11100011
528         // -----------------------------------------------------------
529         // PREPARE (PREP)
530         // -----------------------------------------------------------
531 
532         *pUnitStat = CSW_CE | CSW_DE;
533 
534         break;
535 
536     case 0x14:  // XXX10100  SCB
537         // -----------------------------------------------------------
538         // SENSE COMMAND BYTE
539         // -----------------------------------------------------------
540 
541         *pUnitStat = CSW_CE | CSW_DE;
542         break;
543 
544     case 0x04:  // 00000100  SENSE
545       // -----------------------------------------------------------
546       // SENSE
547       // -----------------------------------------------------------
548 
549         // Command reject if in basic mode
550         if( pDEVBLK->ctcxmode == 0 )
551         {
552             pDEVBLK->sense[0] = SENSE_CR;
553             *pUnitStat        = CSW_CE | CSW_DE | CSW_UC;
554             break;
555         }
556 
557         // Calculate residual byte count
558         iNum = ( sCount < pDEVBLK->numsense ) ?
559             sCount : pDEVBLK->numsense;
560 
561         *pResidual = sCount - iNum;
562 
563         if( sCount < pDEVBLK->numsense )
564             *pMore = 1;
565 
566         // Copy device sense bytes to channel I/O buffer
567         memcpy( pIOBuf, pDEVBLK->sense, iNum );
568 
569         // Clear the device sense bytes
570         memset( pDEVBLK->sense, 0, sizeof( pDEVBLK->sense ) );
571 
572         // Return unit status
573         *pUnitStat = CSW_CE | CSW_DE;
574 
575         break;
576 
577     case 0xE4:  //  11100100  SID
578         // -----------------------------------------------------------
579         // SENSE ID
580         // -----------------------------------------------------------
581 
582         // Calculate residual byte count
583         iNum = ( sCount < pDEVBLK->numdevid ) ?
584             sCount : pDEVBLK->numdevid;
585 
586         *pResidual = sCount - iNum;
587 
588         if( sCount < pDEVBLK->numdevid )
589             *pMore = 1;
590 
591         // Copy device identifier bytes to channel I/O buffer
592         memcpy( pIOBuf, pDEVBLK->devid, iNum );
593 
594         // Return unit status
595         *pUnitStat = CSW_CE | CSW_DE;
596 
597         break;
598 
599 #if 0
600     case 0x72: // 0111010   RCD
601         // ------------------------------------------------------------
602         // READ CONFIGURATION DATA
603         // ------------------------------------------------------------
604 
605     case 0x82: // 10000010  SID
606         // ------------------------------------------------------------
607         // SET INTERFACE IDENTIFER
608         // ------------------------------------------------------------
609 
610     case 0x83: // 10000011 RID
611         // ------------------------------------------------------------
612         // READ NODE IDENTIFER
613         // ------------------------------------------------------------
614 
615         LCS_SDC( pDEVBLK, bOpCode, sCount, pIOBuf,
616                  pUnitStat, pResidual, pMore );
617 
618         break;
619 #endif
620 
621     default:
622         // ------------------------------------------------------------
623         // INVALID OPERATION
624         // ------------------------------------------------------------
625 
626         // Set command reject sense byte, and unit check status
627         pDEVBLK->sense[0] = SENSE_CR;
628         *pUnitStat        = CSW_CE | CSW_DE | CSW_UC;
629     }
630 }
631 
632 // ====================================================================
633 //                           LCS_Close
634 // ====================================================================
635 
LCS_Close(DEVBLK * pDEVBLK)636 int  LCS_Close( DEVBLK* pDEVBLK )
637 {
638     PLCSDEV     pLCSDEV;
639     PLCSBLK     pLCSBLK;
640     PLCSPORT    pLCSPORT;
641 
642     if (!(pLCSDEV = (PLCSDEV)pDEVBLK->dev_data))
643         return 0; // (was incomplete group)
644 
645     pLCSBLK  = pLCSDEV->pLCSBLK;
646     pLCSPORT = &pLCSBLK->Port[pLCSDEV->bPort];
647 
648     pLCSPORT->icDevices--;
649 
650     // Is this the last device on the port?
651     if( !pLCSPORT->icDevices )
652     {
653         // PROGRAMMING NOTE: there's currently no way to interrupt
654         // the "LCS_PortThread"s TUNTAP_Read of the adapter. Thus
655         // we must simply wait for LCS_PortThread to eventually
656         // notice that we're doing a close (via our setting of the
657         // fCloseInProgress flag). Its TUNTAP_Read will eventually
658         // timeout after a few seconds (currently 5, which is dif-
659         // ferent than the CTC_READ_TIMEOUT_SECS timeout value the
660         // CTCI_Read function uses) and will then do the close of
661         // the adapter for us (TUNTAP_Close) so we don't have to.
662         // All we need to do is ask it to exit (via our setting of
663         // the fCloseInProgress flag) and then wait for it to exit
664         // (which, as stated, could take up to a max of 5 seconds).
665 
666         // All of this is simply because it's poor form to close a
667         // device from one thread while another thread is reading
668         // from it. Attempting to do so could trip a race condition
669         // wherein the internal i/o buffers used to process the
670         // read request could have been freed (by the close call)
671         // by the time the read request eventually gets serviced.
672 
673         if( pLCSPORT->fd >= 0 )
674         {
675             TID tid = pLCSPORT->tid;
676             obtain_lock( &pLCSPORT->EventLock );
677             {
678                 pLCSPORT->fStarted = 0;
679                 pLCSPORT->fCloseInProgress = 1;
680                 signal_condition( &pLCSPORT->Event );
681             }
682             release_lock( &pLCSPORT->EventLock );
683             signal_thread( tid, SIGUSR2 );
684             join_thread( tid, NULL );
685             detach_thread( tid );
686         }
687 
688         if( pLCSDEV->pDEVBLK[0] && pLCSDEV->pDEVBLK[0]->fd >= 0 )
689             pLCSDEV->pDEVBLK[0]->fd = -1;
690         if( pLCSDEV->pDEVBLK[1] && pLCSDEV->pDEVBLK[1]->fd >= 0 )
691             pLCSDEV->pDEVBLK[1]->fd = -1;
692     }
693 
694     // Housekeeping
695     if( pLCSDEV->pDEVBLK[0] == pDEVBLK )
696         pLCSDEV->pDEVBLK[0] = NULL;
697     if( pLCSDEV->pDEVBLK[1] == pDEVBLK )
698         pLCSDEV->pDEVBLK[1] = NULL;
699 
700     if( !pLCSDEV->pDEVBLK[0] &&
701         !pLCSDEV->pDEVBLK[1] )
702     {
703         // Remove this LCS Device from the chain...
704 
705         PLCSDEV  pCurrLCSDev  = NULL;
706         PLCSDEV* ppPrevLCSDev = &pLCSBLK->pDevices;
707 
708         for( pCurrLCSDev = pLCSBLK->pDevices; pCurrLCSDev; pCurrLCSDev = pCurrLCSDev->pNext )
709         {
710             if( pCurrLCSDev == pLCSDEV )
711             {
712                 *ppPrevLCSDev = pCurrLCSDev->pNext;
713 
714                 if( pCurrLCSDev->pszIPAddress )
715                 {
716                     free( pCurrLCSDev->pszIPAddress );
717                     pCurrLCSDev->pszIPAddress = NULL;
718                 }
719 
720                 free( pLCSDEV );
721                 pLCSDEV = NULL;
722                 break;
723             }
724 
725             ppPrevLCSDev = &pCurrLCSDev->pNext;
726         }
727     }
728 
729     if( !pLCSBLK->pDevices )
730     {
731         if( pLCSBLK->pszTUNDevice   ) { free( pLCSBLK->pszTUNDevice   ); pLCSBLK->pszTUNDevice   = NULL; }
732         if( pLCSBLK->pszOATFilename ) { free( pLCSBLK->pszOATFilename ); pLCSBLK->pszOATFilename = NULL; }
733 //      if( pLCSBLK->pszIPAddress   ) { free( pLCSBLK->pszIPAddress   ); pLCSBLK->pszIPAddress   = NULL; }
734         if( pLCSBLK->pszMACAddress  ) { free( pLCSBLK->pszMACAddress  ); pLCSBLK->pszMACAddress  = NULL; }
735 
736         if( pLCSBLK->pszOATFilename )
737         {
738             if( pLCSBLK->pszIPAddress )
739             {
740                 free( pLCSBLK->pszIPAddress );
741                 pLCSBLK->pszIPAddress = NULL;
742             }
743         }
744 
745         free( pLCSBLK );
746         pLCSBLK = NULL;
747     }
748 
749     pDEVBLK->dev_data = NULL;
750 
751     return 0;
752 }
753 
754 // ====================================================================
755 //                         LCS_Query
756 // ====================================================================
757 
LCS_Query(DEVBLK * pDEVBLK,char ** ppszClass,int iBufLen,char * pBuffer)758 void  LCS_Query( DEVBLK* pDEVBLK, char** ppszClass,
759                  int     iBufLen, char*  pBuffer )
760 {
761     char *sType[] = { "", " Pri", " Sec" };
762 
763     LCSDEV*  pLCSDEV;
764 
765     BEGIN_DEVICE_CLASS_QUERY( "CTCA", pDEVBLK, ppszClass, iBufLen, pBuffer );
766 
767     pLCSDEV = (LCSDEV*) pDEVBLK->dev_data;
768 
769     if(!pLCSDEV)
770     {
771         strlcpy(pBuffer,"*Uninitialized",iBufLen);
772         return;
773     }
774 
775     snprintf( pBuffer, iBufLen, "LCS Port %2.2X %s%s (%s)%s",
776               pLCSDEV->bPort,
777               pLCSDEV->bMode == LCSDEV_MODE_IP ? "IP" : "SNA",
778               sType[pLCSDEV->bType],
779               pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort].szNetDevName,
780               pLCSDEV->pLCSBLK->fDebug ? " -d" : "" );
781 }
782 
783 // ====================================================================
784 //                         LCS_Read
785 // ====================================================================
786 // The guest o/s is issuing a Read CCW for our LCS device. Return to
787 // it all available LCS Frames that we have buffered up in our buffer.
788 // --------------------------------------------------------------------
789 
LCS_Read(DEVBLK * pDEVBLK,U16 sCount,BYTE * pIOBuf,BYTE * pUnitStat,U16 * pResidual,BYTE * pMore)790 void  LCS_Read( DEVBLK* pDEVBLK,   U16   sCount,
791                 BYTE*   pIOBuf,    BYTE* pUnitStat,
792                 U16*    pResidual, BYTE* pMore )
793 {
794     PLCSHDR     pLCSHdr;
795     PLCSDEV     pLCSDEV = (PLCSDEV)pDEVBLK->dev_data;
796     size_t      iLength = 0;
797     int         rc      = 0;
798 
799     // FIXME: we currently don't support data-chaining but
800     // probably should if real LCS devices do (I was unable
801     // to determine whether they do or not). -- Fish
802 
803     for (;;)
804     {
805         // Wait for some LCS Frames to arrive in our buffer...
806 
807         obtain_lock( &pLCSDEV->Lock );
808 
809         if( !( pLCSDEV->fDataPending || pLCSDEV->fReplyPending ) )
810         {
811             struct timespec waittime;
812             struct timeval  now;
813 
814             release_lock( &pLCSDEV->Lock );
815 
816             // Wait 5 seconds then check for channel conditions
817 
818             gettimeofday( &now, NULL );
819 
820             waittime.tv_sec  = now.tv_sec  + CTC_READ_TIMEOUT_SECS;
821             waittime.tv_nsec = now.tv_usec * 1000;
822 
823             obtain_lock( &pLCSDEV->EventLock );
824 
825             rc = timed_wait_condition( &pLCSDEV->Event,
826                                        &pLCSDEV->EventLock,
827                                        &waittime );
828 
829             release_lock( &pLCSDEV->EventLock );
830 
831             // If we didn't receive any, keep waiting...
832 
833             if( rc == ETIMEDOUT || rc == EINTR )
834             {
835                 // check for halt condition
836                 if( pDEVBLK->scsw.flag2 & SCSW2_FC_HALT ||
837                     pDEVBLK->scsw.flag2 & SCSW2_FC_CLEAR )
838                 {
839                     if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep )
840                         logmsg( _("HHCLC002I %4.4X: Halt or Clear Recognized\n"),
841                                 pDEVBLK->devnum );
842 
843                     *pUnitStat = CSW_CE | CSW_DE;
844                     *pResidual = sCount;
845                     return;
846                 }
847                 continue;   // (keep waiting)
848             }
849 
850             // We received some LCS Frames...
851 
852             obtain_lock( &pLCSDEV->Lock );
853         }
854 
855         // Point to the end of all buffered LCS Frames...
856         // (where the next Frame *would* go if there was one)
857 
858         pLCSHdr = (PLCSHDR)( pLCSDEV->bFrameBuffer +
859                              pLCSDEV->iFrameOffset );
860 
861         // Mark the end of this batch of LCS Frames by setting
862         // the "offset to NEXT frame" LCS Header field to zero.
863         // (a zero "next Frame offset" is like an "EOF" flag)
864 
865         STORE_HW( pLCSHdr->hwOffset, 0x0000 );
866 
867         // Calculate how much data we're going to be giving them.
868 
869         // Since 'iFrameOffset' points to the next available LCS
870         // Frame slot in our buffer, the total amount of LCS Frame
871         // data we have is exactly that amount. We give them two
872         // extra bytes however so that they can optionally chase
873         // the "hwOffset" field in each LCS Frame's LCS Header to
874         // eventually reach our zero hwOffset "EOF" flag).
875 
876         iLength = pLCSDEV->iFrameOffset + sizeof(pLCSHdr->hwOffset);
877 
878         // (calculate residual and set memcpy amount)
879 
880         // FIXME: we currently don't support data-chaining but
881         // probably should if real LCS devices do (I was unable
882         // to determine whether they do or not). -- Fish
883 
884         if( sCount < iLength )
885         {
886             *pMore     = 1;
887             *pResidual = 0;
888 
889             iLength = sCount;
890 
891             // PROGRAMMING NOTE: As a result of the caller asking
892             // for less data than we actually have available, the
893             // remainder of their unread data they didn't ask for
894             // will end up being silently discarded. Refer to the
895             // other NOTEs and FIXME's sprinkled throughout this
896             // function...
897         }
898         else
899         {
900             *pMore      = 0;
901             *pResidual -= iLength;
902         }
903 
904         *pUnitStat = CSW_CE | CSW_DE;
905 
906         memcpy( pIOBuf, pLCSDEV->bFrameBuffer, iLength );
907 
908         // Trace the i/o if requested...
909 
910         if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep )
911         {
912             logmsg( _("HHCLC003I %4.4X: LCS Read:\n"),
913                     pDEVBLK->devnum );
914             packet_trace( pIOBuf, iLength );
915         }
916 
917         // Reset frame buffer to empty...
918 
919         // PROGRAMMING NOTE: even though not all available data
920         // may have been read by the guest, we don't currently
921         // support data-chaining. Thus any unread data is always
922         // discarded by resetting both of the iFrameOffset and
923         // fDataPending fields to 0 so that the next read always
924         // grabs a new batch of LCS Frames starting at the very
925         // beginning of our frame buffer again. (I was unable
926         // to determine whether real LCS devices support data-
927         // chaining or not, but if they do we should fix this).
928 
929         pLCSDEV->iFrameOffset  = 0;
930         pLCSDEV->fReplyPending = 0;
931         pLCSDEV->fDataPending  = 0;
932 
933         release_lock( &pLCSDEV->Lock );
934 
935         return;
936     }
937 }
938 
939 // ====================================================================
940 //                         LCS_Write
941 // ====================================================================
942 
LCS_Write(DEVBLK * pDEVBLK,U16 sCount,BYTE * pIOBuf,BYTE * pUnitStat,U16 * pResidual)943 void  LCS_Write( DEVBLK* pDEVBLK,   U16   sCount,
944                  BYTE*   pIOBuf,    BYTE* pUnitStat,
945                  U16*    pResidual )
946 {
947     PLCSDEV     pLCSDEV      = (PLCSDEV)pDEVBLK->dev_data;
948     PLCSHDR     pLCSHDR      = NULL;
949     PLCSCMDHDR  pCmdFrame    = NULL;
950     PLCSETHFRM  pLCSEthFrame = NULL;
951     PETHFRM     pEthFrame    = NULL;
952     U16         iOffset      = 0;
953     U16         iPrevOffset  = 0;
954     U16         iLength      = 0;
955     U16         iEthLen      = 0;
956 
957     UNREFERENCED( sCount );
958 
959     // Process each frame in the buffer...
960 
961     while( 1 )
962     {
963         // Fix-up the LCS header pointer to the current frame
964         pLCSHDR = (PLCSHDR)( pIOBuf + iOffset );
965 
966         // Save current offset so we can tell how big next frame is
967         iPrevOffset = iOffset;
968 
969         // Get the next frame offset, exit loop if 0
970         FETCH_HW( iOffset, pLCSHDR->hwOffset );
971 
972         if( iOffset == 0 )   // ("EOF")
973             break;
974 
975         // Calculate size of this LCS Frame
976         iLength = iOffset - iPrevOffset;
977 
978         switch( pLCSHDR->bType )
979         {
980         case LCS_FRMTYP_CMD:    // LCS Command Frame
981 
982             pCmdFrame = (PLCSCMDHDR)pLCSHDR;
983 
984             // Trace received command frame...
985             if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep )
986             {
987                 logmsg( _("HHCLC051I %4.4X: Cmd Packet...\n"),
988                         pDEVBLK->devnum );
989                 packet_trace( (BYTE*)pCmdFrame, iLength );
990             }
991 
992             // FIXME: what is this all about? I'm not saying it's wrong,
993             // only that we need to document via comments the purpose of
994             // this test. What's it doing? Why ignore "initiator 1"? etc.
995             // PLEASE EXPLAIN! -- Fish
996             if( pCmdFrame->bInitiator == 0x01 )
997                 break;
998 
999             switch( pCmdFrame->bCmdCode )
1000             {
1001             case LCS_CMD_STARTUP:       // Start Host
1002                 if( pLCSDEV->pLCSBLK->fDebug )
1003                     logmsg( _("HHCLC043I %4.4X: Startup\n"),pDEVBLK->devnum);
1004                 LCS_Startup( pLCSDEV, pCmdFrame );
1005                 break;
1006 
1007             case LCS_CMD_SHUTDOWN:      // Shutdown Host
1008                 if( pLCSDEV->pLCSBLK->fDebug )
1009                     logmsg( _("HHCLC044I %4.4X: Shutdown\n"),pDEVBLK->devnum);
1010                 LCS_Shutdown( pLCSDEV, pCmdFrame );
1011                 break;
1012 
1013             case LCS_CMD_STRTLAN:       // Start LAN
1014                 if( pLCSDEV->pLCSBLK->fDebug )
1015                     logmsg( _("HHCLC045I %4.4X: Start LAN\n"),pDEVBLK->devnum);
1016                 LCS_StartLan( pLCSDEV, pCmdFrame );
1017                 break;
1018 
1019             case LCS_CMD_STOPLAN:       // Stop  LAN
1020                 if( pLCSDEV->pLCSBLK->fDebug )
1021                     logmsg( _("HHCLC046I %4.4X: Stop LAN\n"),pDEVBLK->devnum);
1022                 LCS_StopLan( pLCSDEV, pCmdFrame );
1023                 break;
1024 
1025             case LCS_CMD_QIPASSIST:     // Query IP Assists
1026                 if( pLCSDEV->pLCSBLK->fDebug )
1027                     logmsg( _("HHCLC047I %4.4X: Query IP Assists\n"),pDEVBLK->devnum);
1028                 LCS_QueryIPAssists( pLCSDEV, pCmdFrame );
1029                 break;
1030 
1031             case LCS_CMD_LANSTAT:       // LAN Stats
1032                 if( pLCSDEV->pLCSBLK->fDebug )
1033                     logmsg( _("HHCLC048I %4.4X: Statistics\n"),pDEVBLK->devnum);
1034                 LCS_LanStats( pLCSDEV, pCmdFrame );
1035                 break;
1036 
1037             // ZZ FIXME: Once multicasting support is confirmed in tuntap
1038             // and/or TunTap32, we need to add support in Herc by handling
1039             // the below LCS_CMD_SETIPM and LCS_CMD_DELIPM frames and then
1040             // issuing an ioctl( SIOCADDMULTI ) to tuntap/TunTap32...
1041 
1042             case LCS_CMD_SETIPM:        // Set IP Multicast
1043             case LCS_CMD_DELIPM:        // Delete IP Multicast
1044             case LCS_CMD_GENSTAT:       // General Stats
1045             case LCS_CMD_LISTLAN:       // List LAN
1046             case LCS_CMD_LISTLAN2:      // List LAN (another version)
1047             case LCS_CMD_TIMING:        // Timing request
1048             default:
1049                 LCS_DefaultCmdProc( pLCSDEV, pCmdFrame );
1050                 break;
1051 
1052             } // end switch( LCS Command Frame cmd code )
1053             break; // end case LCS_FRMTYP_CMD
1054 
1055         case LCS_FRMTYP_ENET:   // Ethernet Passthru
1056         case LCS_FRMTYP_TR:     // Token Ring
1057         case LCS_FRMTYP_FDDI:   // FDDI
1058         case LCS_FRMTYP_AUTO:   // auto-detect
1059 
1060             pLCSEthFrame = (PLCSETHFRM)pLCSHDR;
1061             pEthFrame    = (PETHFRM)pLCSEthFrame->bData;
1062             iEthLen      = iLength - sizeof(LCSETHFRM);
1063 
1064             // Trace Ethernet frame before sending to TAP device
1065             if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep )
1066             {
1067                 logmsg( _("HHCLC004I %4.4X: Sending packet to %s:\n"),
1068                         pDEVBLK->devnum, pDEVBLK->filename );
1069                 packet_trace( (BYTE*)pEthFrame, iEthLen );
1070             }
1071 
1072             // Write the Ethernet frame to the TAP device
1073             if( TUNTAP_Write( pDEVBLK->fd,
1074                               (BYTE*)pEthFrame, iEthLen ) != iEthLen )
1075             {
1076                 logmsg( _("HHCLC005E %4.4X: Error writing to %s: %s\n"),
1077                         pDEVBLK->devnum, pDEVBLK->filename,
1078                         strerror( errno ) );
1079                 pDEVBLK->sense[0] = SENSE_EC;
1080                 *pUnitStat = CSW_CE | CSW_DE | CSW_UC;
1081                 return;
1082             }
1083             break;
1084 
1085         default:
1086             logmsg( _("HHCLC050E %4.4X: LCS_Write: Unsupported frame type 0x%2.2X\n"),
1087                     pDEVBLK->devnum, pDEVBLK->filename );
1088             ASSERT( FALSE );
1089             pDEVBLK->sense[0] = SENSE_EC;
1090             *pUnitStat = CSW_CE | CSW_DE | CSW_UC;
1091             return;
1092 
1093         } // end switch( LCS Frame type )
1094 
1095     } // end while (1)
1096 
1097     *pResidual = 0;
1098     *pUnitStat = CSW_CE | CSW_DE;
1099 
1100     if( pLCSDEV->fReplyPending )
1101     {
1102         if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep )
1103             logmsg( _("HHCLC006I %4.4X Triggering Event.\n"),
1104                     pDEVBLK->devnum );
1105 
1106         obtain_lock( &pLCSDEV->EventLock );
1107         signal_condition( &pLCSDEV->Event );
1108         release_lock( &pLCSDEV->EventLock );
1109     }
1110 }
1111 
1112 #if 0
1113 // ====================================================================
1114 //                         LCS_SDC
1115 // ====================================================================
1116 
1117 void  LCS_SDC( DEVBLK* pDEVBLK,   BYTE   bOpCode,
1118                U16     sCount,    BYTE*  pIOBuf,
1119                BYTE*   UnitStat,  U16*   pResidual,
1120                BYTE*   pMore )
1121 {
1122     PLCSDEV     pLCSDEV     = (PLCSDEV)pDEVBLK->dev_data;
1123     PLCSBLK     pLCSBLK     = pLCSDEV->pLCSBLK;
1124 
1125     switch( bOpCode )
1126     {
1127     case 0x72: // 0111010   RCD
1128         // ------------------------------------------------------------
1129         // READ CONFIGURATION DATA
1130         // ------------------------------------------------------------
1131 
1132         SDC_CreateNED( pIOBuf, 0,
1133                        NED_EMULATION,
1134                        NED_TYPE_DEV,
1135                        NED_CLASS_CTCA,
1136                        0,
1137                        "003088", "001",
1138                        "", "", "", 0 );
1139 
1140         SDC_CreateNED( pIOBuf, 1,
1141                        NED_SERIAL_VALID,
1142                        NED_TYPE_DEV,
1143                        NED_CLASS_UNSPECIFIED,
1144                        0,
1145                        "003172", "000",
1146                        "HDG", "00",
1147                        pLCSBLK->szSerialNumber,
1148                        pLCSDEV->bPort );
1149 
1150         SDC_CreateGeneralNEQ( pIOBuf, 2,
1151                               0,        // Interface ID
1152                               60,       // Timeout
1153                               NULL );   // Extended Info
1154 
1155         SDC_CreateNED( pIOBuf, 3,
1156                        NED_TOKEN | NED_SERIAL_UNIQUE,
1157                        NED_TYPE_DEV,
1158                        NED_CLASS_UNSPECIFIED,
1159                        0,
1160                        "003172", "000",
1161                        "HDG", "00",
1162                        pLCSBLK->szSerialNumber,
1163                        0 );
1164         break;
1165 
1166     case 0x82: // 10000010  SID
1167         // ------------------------------------------------------------
1168         // SET INTERFACE IDENTIFER
1169         // ------------------------------------------------------------
1170         break;
1171 
1172     case 0x83: // 10000011 RID
1173         // ------------------------------------------------------------
1174         // READ NODE IDENTIFER
1175         // ------------------------------------------------------------
1176         break;
1177     }
1178 }
1179 #endif
1180 
1181 // ====================================================================
1182 //                         LCS_Startup
1183 // ====================================================================
1184 
LCS_Startup(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1185 static void  LCS_Startup( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1186 {
1187     LCSSTRTFRM  reply;
1188     PLCSPORT    pLCSPORT;
1189     U16         iOrigMaxFrameBufferSize;
1190 
1191     INIT_REPLY_FRAME( reply, pCmdFrame );
1192 
1193     reply.bLCSCmdHdr.bLanType      = LCS_FRMTYP_ENET;
1194     reply.bLCSCmdHdr.bRelAdapterNo = pLCSDEV->bPort;
1195 
1196     // Save the max buffer size parameter
1197     iOrigMaxFrameBufferSize = pLCSDEV->iMaxFrameBufferSize;
1198     FETCH_HW( pLCSDEV->iMaxFrameBufferSize, ((PLCSSTRTFRM)pCmdFrame)->hwBufferSize );
1199 
1200     // Make sure it doesn't exceed our compiled maximum
1201     if (pLCSDEV->iMaxFrameBufferSize > sizeof(pLCSDEV->bFrameBuffer))
1202     {
1203         logmsg( _("HHCLC049W %4.4X: LCS_Startup: Requested frame buffer size of 0x%4.4X "
1204                   "larger than compiled size of 0x%4.4X; requested size ignored.\n"),
1205                   pLCSDEV->pDEVBLK[1]->devnum,
1206                   pLCSDEV->iMaxFrameBufferSize,
1207                   sizeof( pLCSDEV->bFrameBuffer ) );
1208         pLCSDEV->iMaxFrameBufferSize = iOrigMaxFrameBufferSize;
1209     }
1210 
1211     // Make sure it's not smaller than the compiled minimum size
1212     if (pLCSDEV->iMaxFrameBufferSize < CTC_MIN_FRAME_BUFFER_SIZE)
1213     {
1214         logmsg( _("HHCLC054W %4.4X: LCS_Startup: Requested frame buffer size of 0x%4.4X "
1215                   "smaller than compiled minimum size of 0x%4.4X; requested size ignored.\n"),
1216                   pLCSDEV->pDEVBLK[1]->devnum,
1217                   pLCSDEV->iMaxFrameBufferSize,
1218                   CTC_MIN_FRAME_BUFFER_SIZE );
1219         pLCSDEV->iMaxFrameBufferSize = iOrigMaxFrameBufferSize;
1220     }
1221 
1222     pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort];
1223 
1224     VERIFY( TUNTAP_SetIPAddr( pLCSPORT->szNetDevName, "0.0.0.0" ) == 0 );
1225     VERIFY( TUNTAP_SetMTU   ( pLCSPORT->szNetDevName,  "1500"   ) == 0 );
1226 
1227 #ifdef OPTION_TUNTAP_SETMACADDR
1228     if (pLCSPORT->fLocalMAC)
1229     {
1230         VERIFY( TUNTAP_SetMACAddr( pLCSPORT->szNetDevName,
1231                                    pLCSPORT->szMACAddress ) == 0 );
1232     }
1233 #endif // OPTION_TUNTAP_SETMACADDR
1234 
1235     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1236 
1237     pLCSDEV->fStarted = 1;
1238 }
1239 
1240 // ====================================================================
1241 //                         LCS_Shutdown
1242 // ====================================================================
1243 
LCS_Shutdown(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1244 static void  LCS_Shutdown( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1245 {
1246     LCSSTDFRM   reply;
1247 
1248     INIT_REPLY_FRAME( reply, pCmdFrame );
1249 
1250     reply.bLCSCmdHdr.bLanType      = LCS_FRMTYP_ENET;
1251     reply.bLCSCmdHdr.bRelAdapterNo = pLCSDEV->bPort;
1252 
1253     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1254 
1255     pLCSDEV->fStarted = 0;
1256 }
1257 
1258 // ====================================================================
1259 //                         LCS_StartLan
1260 // ====================================================================
1261 
LCS_StartLan(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1262 static void  LCS_StartLan( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1263 {
1264     LCSSTDFRM   reply;
1265     PLCSPORT    pLCSPORT;
1266 #ifdef OPTION_TUNTAP_DELADD_ROUTES
1267     PLCSRTE     pLCSRTE;
1268 #endif // OPTION_TUNTAP_DELADD_ROUTES
1269     int         nIFFlags;
1270 
1271     INIT_REPLY_FRAME( reply, pCmdFrame );
1272 
1273     pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort];
1274 
1275     // Serialize access to eliminate ioctl errors
1276     obtain_lock( &pLCSPORT->Lock );
1277 
1278     // Configure the TAP interface if used
1279     if( pLCSPORT->fUsed && pLCSPORT->fCreated && !pLCSPORT->fStarted )
1280     {
1281         nIFFlags =              // Interface flags
1282             0
1283             | IFF_UP            // (interface is being enabled)
1284             | IFF_BROADCAST     // (interface broadcast addr is valid)
1285             ;
1286 
1287 #if defined( TUNTAP_IFF_RUNNING_NEEDED )
1288 
1289         nIFFlags |=             // ADDITIONAL Interface flags
1290             0
1291             | IFF_RUNNING       // (interface is ALSO operational)
1292             ;
1293 
1294 #endif /* defined( TUNTAP_IFF_RUNNING_NEEDED ) */
1295 
1296         // Enable the interface by turning on the IFF_UP flag...
1297         VERIFY( TUNTAP_SetFlags( pLCSPORT->szNetDevName, nIFFlags ) == 0 );
1298 
1299 #ifdef OPTION_TUNTAP_DELADD_ROUTES
1300 
1301         // Add any needed extra routing entries the
1302         // user may have specified in their OAT file
1303         // to the host's routing table...
1304 
1305         for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE; pLCSRTE = pLCSRTE->pNext )
1306         {
1307             VERIFY( TUNTAP_AddRoute( pLCSPORT->szNetDevName,
1308                              pLCSRTE->pszNetAddr,
1309                              pLCSRTE->pszNetMask,
1310                              NULL,
1311                              RTF_UP ) == 0 );
1312         }
1313 #endif // OPTION_TUNTAP_DELADD_ROUTES
1314 
1315         obtain_lock( &pLCSPORT->EventLock );
1316         pLCSPORT->fStarted = 1;
1317         signal_condition( &pLCSPORT->Event );
1318         release_lock( &pLCSPORT->EventLock );
1319         usleep( 250*1000 );
1320     }
1321 
1322     release_lock( &pLCSPORT->Lock );
1323 
1324 #ifdef OPTION_TUNTAP_DELADD_ROUTES
1325 
1326     // Add a Point-To-Point routing entry to the
1327     // host's routing table for our interface...
1328 
1329     if( pLCSDEV->pszIPAddress )
1330     {
1331         VERIFY( TUNTAP_AddRoute( pLCSPORT->szNetDevName,
1332                          pLCSDEV->pszIPAddress,
1333                          "255.255.255.255",
1334                          NULL,
1335                          RTF_UP | RTF_HOST ) == 0 );
1336     }
1337 #endif // OPTION_TUNTAP_DELADD_ROUTES
1338 
1339     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1340 }
1341 
1342 // ====================================================================
1343 //                         LCS_StopLan
1344 // ====================================================================
1345 
LCS_StopLan(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1346 static void  LCS_StopLan( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1347 {
1348     LCSSTDFRM   reply;
1349     PLCSPORT    pLCSPORT;
1350 #ifdef OPTION_TUNTAP_DELADD_ROUTES
1351     PLCSRTE     pLCSRTE;
1352 #endif // OPTION_TUNTAP_DELADD_ROUTES
1353 
1354     INIT_REPLY_FRAME( reply, pCmdFrame );
1355 
1356     pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort];
1357 
1358     // Serialize access to eliminate ioctl errors
1359     obtain_lock( &pLCSPORT->Lock );
1360 
1361     obtain_lock( &pLCSPORT->EventLock );
1362     pLCSPORT->fStarted = 0;
1363     signal_condition( &pLCSPORT->Event );
1364     release_lock( &pLCSPORT->EventLock );
1365     usleep( 250*1000 );
1366 
1367     // Disable the interface by turning off the IFF_UP flag...
1368     VERIFY( TUNTAP_SetFlags( pLCSPORT->szNetDevName, 0 ) == 0 );
1369 
1370 #ifdef OPTION_TUNTAP_DELADD_ROUTES
1371 
1372     // Remove routing entries from host's routing table...
1373 
1374     // First, remove the Point-To-Point routing entry
1375     // we added when we brought the interface IFF_UP...
1376 
1377     if( pLCSDEV->pszIPAddress )
1378     {
1379         VERIFY( TUNTAP_DelRoute( pLCSPORT->szNetDevName,
1380                          pLCSDEV->pszIPAddress,
1381                          "255.255.255.255",
1382                          NULL,
1383                          RTF_HOST ) == 0 );
1384     }
1385 
1386     // Next, remove any extra routing entries
1387     // (specified by the user in their OAT file)
1388     // that we may have also added...
1389 
1390     for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE; pLCSRTE = pLCSRTE->pNext )
1391     {
1392         VERIFY( TUNTAP_DelRoute( pLCSPORT->szNetDevName,
1393                          pLCSRTE->pszNetAddr,
1394                          pLCSRTE->pszNetMask,
1395                          NULL,
1396                          RTF_UP ) == 0 );
1397     }
1398 #endif // OPTION_TUNTAP_DELADD_ROUTES
1399 
1400     release_lock( &pLCSPORT->Lock );
1401 
1402     // FIXME: Really need to iterate through the devices and close
1403     //        the TAP interface if all devices have been stopped.
1404 
1405     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1406 }
1407 
1408 // ====================================================================
1409 //                      LCS_QueryIPAssists
1410 // ====================================================================
1411 
LCS_QueryIPAssists(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1412 static void  LCS_QueryIPAssists( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1413 {
1414     LCSQIPFRM   reply;
1415     PLCSPORT    pLCSPORT;
1416 
1417     INIT_REPLY_FRAME( reply, pCmdFrame );
1418 
1419     pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort];
1420 
1421 #if defined( WIN32 )
1422 
1423     // FIXME: TunTap32 *does* support TCP/IP checksum offloading
1424     // (for both inbound and outbound packets), but Microsoft's
1425     // latest NDIS 6.0 release has broken it, so until I can get
1426     // it straightened out we can't support it. Sorry! -- Fish
1427 
1428     // The other assists however, TunTap32 does not yet support.
1429 
1430     pLCSPORT->sIPAssistsSupported =
1431         0
1432 //      | LCS_INBOUND_CHECKSUM_SUPPORT
1433 //      | LCS_OUTBOUND_CHECKSUM_SUPPORT
1434 //      | LCS_ARP_PROCESSING
1435 //      | LCS_IP_FRAG_REASSEMBLY
1436 //      | LCS_IP_FILTERING
1437 //      | LCS_IP_V6_SUPPORT
1438 //      | LCS_MULTICAST_SUPPORT
1439         ;
1440 
1441     pLCSPORT->sIPAssistsEnabled =
1442         0
1443 //      | LCS_INBOUND_CHECKSUM_SUPPORT
1444 //      | LCS_OUTBOUND_CHECKSUM_SUPPORT
1445 //      | LCS_ARP_PROCESSING
1446 //      | LCS_IP_FRAG_REASSEMBLY
1447 //      | LCS_IP_FILTERING
1448 //      | LCS_IP_V6_SUPPORT
1449 //      | LCS_MULTICAST_SUPPORT
1450         ;
1451 
1452 #else // !WIN32 (Linux, Apple, etc)
1453 
1454     // Linux/Apple/etc 'tuntap' driver DOES support
1455     // certain types of assists?? (task offloading)
1456 
1457     pLCSPORT->sIPAssistsSupported =
1458         0
1459 //      | LCS_INBOUND_CHECKSUM_SUPPORT
1460 //      | LCS_OUTBOUND_CHECKSUM_SUPPORT
1461 //      | LCS_ARP_PROCESSING
1462         | LCS_IP_FRAG_REASSEMBLY
1463 //      | LCS_IP_FILTERING
1464 //      | LCS_IP_V6_SUPPORT
1465         | LCS_MULTICAST_SUPPORT
1466         ;
1467 
1468     pLCSPORT->sIPAssistsEnabled =
1469         0
1470 //      | LCS_INBOUND_CHECKSUM_SUPPORT
1471 //      | LCS_OUTBOUND_CHECKSUM_SUPPORT
1472 //      | LCS_ARP_PROCESSING
1473         | LCS_IP_FRAG_REASSEMBLY
1474 //      | LCS_IP_FILTERING
1475 //      | LCS_IP_V6_SUPPORT
1476         | LCS_MULTICAST_SUPPORT
1477         ;
1478 
1479 #endif // WIN32
1480 
1481     STORE_HW( reply.hwNumIPPairs,         0x0000 );
1482     STORE_HW( reply.hwIPAssistsSupported, pLCSPORT->sIPAssistsSupported );
1483     STORE_HW( reply.hwIPAssistsEnabled,   pLCSPORT->sIPAssistsEnabled   );
1484     STORE_HW( reply.hwIPVersion,          0x0004 );
1485 
1486     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1487 }
1488 
1489 // ====================================================================
1490 //                         LCS_LanStats
1491 // ====================================================================
1492 
LCS_LanStats(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1493 static void  LCS_LanStats( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1494 {
1495     LCSLSTFRM    reply;
1496     PLCSPORT     pLCSPORT;
1497     int          fd;
1498     struct ifreq ifr;
1499     BYTE*        pPortMAC;
1500     BYTE*        pIFaceMAC;
1501 
1502     INIT_REPLY_FRAME( reply, pCmdFrame );
1503 
1504     pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort];
1505 
1506     fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP );
1507 
1508     if( fd == -1 )
1509     {
1510         logmsg( _("HHCLC007E Error in call to socket: %s.\n"),
1511                 strerror( HSO_errno ) );
1512         // FIXME: we should probably be returning a non-zero hwReturnCode
1513         // STORE_HW( reply.bLCSCmdHdr.hwReturnCode, 0x0001 );
1514         return;
1515     }
1516 
1517     memset( &ifr, 0, sizeof( ifr ) );
1518 
1519     strcpy( ifr.ifr_name, pLCSPORT->szNetDevName );
1520 
1521     pPortMAC  = (BYTE*) &pLCSPORT->MAC_Address;
1522 
1523     /* Not all systems can return the hardware address of an interface. */
1524 #if defined(SIOCGIFHWADDR)
1525 
1526     if( TUNTAP_IOCtl( fd, SIOCGIFHWADDR, (char*)&ifr ) != 0  )
1527     {
1528         logmsg( _("HHCLC008E ioctl error on device %s: %s.\n"),
1529                 pLCSPORT->szNetDevName, strerror( errno ) );
1530         // FIXME: we should probably be returning a non-zero hwReturnCode
1531         // STORE_HW( reply.bLCSCmdHdr.hwReturnCode, 0x0002 );
1532         return;
1533     }
1534     pIFaceMAC  = (BYTE*) ifr.ifr_hwaddr.sa_data;
1535 
1536 #else // !defined(SIOCGIFHWADDR)
1537 
1538     pIFaceMAC  = pPortMAC;
1539 
1540 #endif // defined(SIOCGIFHWADDR)
1541 
1542     /* Report what MAC address we will really be using */
1543     logmsg( _("HHCLC055I %s using MAC %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n"),
1544             pLCSPORT->szNetDevName, *(pIFaceMAC+0),*(pIFaceMAC+1),
1545                                     *(pIFaceMAC+2),*(pIFaceMAC+3),
1546                                     *(pIFaceMAC+4),*(pIFaceMAC+5));
1547 
1548     /* Issue warning if different from specified value */
1549     if (memcmp( pPortMAC, pIFaceMAC, IFHWADDRLEN ) != 0)
1550     {
1551         logmsg( _("HHCLC056W %s NOT using MAC %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n"),
1552                 pLCSPORT->szNetDevName, *(pPortMAC+0),*(pPortMAC+1),
1553                                         *(pPortMAC+2),*(pPortMAC+3),
1554                                         *(pPortMAC+4),*(pPortMAC+5));
1555 
1556         memcpy( pPortMAC, pIFaceMAC, IFHWADDRLEN );
1557 
1558         snprintf(pLCSPORT->szMACAddress, sizeof(pLCSPORT->szMACAddress)-1,
1559             "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", *(pPortMAC+0), *(pPortMAC+1),
1560             *(pPortMAC+2), *(pPortMAC+3), *(pPortMAC+4), *(pPortMAC+5));
1561     }
1562 
1563     memcpy( reply.MAC_Address, pIFaceMAC, IFHWADDRLEN );
1564 
1565     /* Respond with a different MAC address for the LCS side */
1566     /* unless the TAP mechanism is designed as such          */
1567     /* cf : hostopts.h for an explanation                    */
1568 #if !defined(OPTION_TUNTAP_LCS_SAME_ADDR)
1569 
1570     reply.MAC_Address[5]++;
1571 
1572 #endif
1573 
1574     // FIXME: Really should read /proc/net/dev to retrieve actual stats
1575 
1576     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1577 }
1578 
1579 // ====================================================================
1580 //                       LCS_DefaultCmdProc
1581 // ====================================================================
1582 
LCS_DefaultCmdProc(PLCSDEV pLCSDEV,PLCSCMDHDR pCmdFrame)1583 static void  LCS_DefaultCmdProc( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame )
1584 {
1585     LCSSTDFRM   reply;
1586 
1587     INIT_REPLY_FRAME( reply, pCmdFrame );
1588 
1589     reply.bLCSCmdHdr.bLanType      = LCS_FRMTYP_ENET;
1590     reply.bLCSCmdHdr.bRelAdapterNo = pLCSDEV->bPort;
1591 
1592     ENQUEUE_REPLY_FRAME( pLCSDEV, reply );
1593 }
1594 
1595 // ====================================================================
1596 //                       LCS_PortThread
1597 // ====================================================================
1598 
LCS_PortThread(PLCSPORT pLCSPORT)1599 static void*  LCS_PortThread( PLCSPORT pLCSPORT )
1600 {
1601     PLCSDEV     pLCSDev;
1602     PLCSDEV     pPrimaryLCSDEV;
1603     PLCSDEV     pSecondaryLCSDEV;
1604     PLCSDEV     pMatchingLCSDEV;
1605     PLCSRTE     pLCSRTE;
1606     PETHFRM     pEthFrame;
1607     PIP4FRM     pIPFrame   = NULL;
1608     PARPFRM     pARPFrame  = NULL;
1609     int         iLength;
1610     U16         hwEthernetType;
1611     U32         lIPAddress;             // (network byte order)
1612     BYTE*       pMAC;
1613     BYTE        szBuff[2048];
1614     char        bReported = 0;
1615 
1616     pLCSPORT->pid = getpid();
1617 
1618     for (;;)
1619     {
1620         obtain_lock( &pLCSPORT->EventLock );
1621         {
1622             // Don't read unless/until port is enabled...
1623 
1624             while (1
1625                 && !(pLCSPORT->fd < 0)
1626                 && !pLCSPORT->fCloseInProgress
1627                 && !pLCSPORT->fStarted
1628             )
1629             {
1630                 timed_wait_condition_relative_usecs
1631                 (
1632                     &pLCSPORT->Event,      // ptr to condition to wait on
1633                     &pLCSPORT->EventLock,  // ptr to controlling lock (must be held!)
1634                     250*1000,           // max #of microseconds to wait
1635                     NULL                // [OPTIONAL] ptr to tod value (may be NULL)
1636                 );
1637             }
1638         }
1639         release_lock( &pLCSPORT->EventLock );
1640 
1641         // Exit when told...
1642 
1643         if ( pLCSPORT->fd < 0 || pLCSPORT->fCloseInProgress )
1644             break;
1645 
1646         // Read an IP packet from the TAP device
1647         iLength = TUNTAP_Read( pLCSPORT->fd, szBuff, sizeof( szBuff ) );
1648 
1649         if( iLength == 0 )      // (probably EINTR; ignore)
1650             continue;
1651 
1652         // Check for other error condition
1653         if( iLength < 0 )
1654         {
1655             if( pLCSPORT->fd < 0 || pLCSPORT->fCloseInProgress )
1656                 break;
1657             logmsg( _("HHCLC042E Port %2.2X: Read error: %s\n"),
1658                 pLCSPORT->bPort, strerror( errno ) );
1659             break;
1660         }
1661 
1662         if( pLCSPORT->pLCSBLK->fDebug )
1663         {
1664             // Trace the frame
1665             logmsg( _("HHCLC009I Port %2.2X: Read Buffer:\n"),
1666                     pLCSPORT->bPort );
1667             packet_trace( szBuff, iLength );
1668 
1669             bReported = 0;
1670         }
1671 
1672         pEthFrame = (PETHFRM)szBuff;
1673 
1674         FETCH_HW( hwEthernetType, pEthFrame->hwEthernetType );
1675 
1676         // Housekeeping
1677         pPrimaryLCSDEV   = NULL;
1678         pSecondaryLCSDEV = NULL;
1679         pMatchingLCSDEV  = NULL;
1680 
1681         // Attempt to find the device that this frame belongs to
1682         for( pLCSDev = pLCSPORT->pLCSBLK->pDevices; pLCSDev; pLCSDev = pLCSDev->pNext )
1683         {
1684             // Only process devices that are on this port
1685             if( pLCSDev->bPort == pLCSPORT->bPort )
1686             {
1687                 if( hwEthernetType == ETH_TYPE_IP )
1688                 {
1689                     pIPFrame   = (PIP4FRM)pEthFrame->bData;
1690                     lIPAddress = pIPFrame->lDstIP;  // (network byte order)
1691 
1692                     if( pLCSPORT->pLCSBLK->fDebug && !bReported )
1693                     {
1694                         logmsg( _("HHCLC010I Port %2.2X: "
1695                                   "IPV4 frame for %8.8X\n"),
1696                                 pLCSPORT->bPort, ntohl(lIPAddress) );
1697 
1698                         bReported = 1;
1699                     }
1700 
1701                     // If this is an exact match use it
1702                     // otherwise look for primary and secondary
1703                     // default devices
1704                     if( pLCSDev->lIPAddress == lIPAddress )
1705                     {
1706                         pMatchingLCSDEV = pLCSDev;
1707                         break;
1708                     }
1709                     else if( pLCSDev->bType == LCSDEV_TYPE_PRIMARY )
1710                         pPrimaryLCSDEV = pLCSDev;
1711                     else if( pLCSDev->bType == LCSDEV_TYPE_SECONDARY )
1712                         pSecondaryLCSDEV = pLCSDev;
1713                 }
1714                 else if( hwEthernetType == ETH_TYPE_ARP )
1715                 {
1716                     pARPFrame  = (PARPFRM)pEthFrame->bData;
1717                     lIPAddress = pARPFrame->lTargIPAddr; // (network byte order)
1718 
1719                     if( pLCSPORT->pLCSBLK->fDebug && !bReported )
1720                     {
1721                         logmsg( _("HHCLC011I Port %2.2X: "
1722                                   "ARP frame for %8.8X\n"),
1723                                 pLCSPORT->bPort, ntohl(lIPAddress) );
1724 
1725                         bReported = 1;
1726                     }
1727 
1728                     // If this is an exact match use it
1729                     // otherwise look for primary and secondary
1730                     // default devices
1731                     if( pLCSDev->lIPAddress == lIPAddress )
1732                     {
1733                         pMatchingLCSDEV = pLCSDev;
1734                         break;
1735                     }
1736                     else if( pLCSDev->bType == LCSDEV_TYPE_PRIMARY )
1737                         pPrimaryLCSDEV = pLCSDev;
1738                     else if( pLCSDev->bType == LCSDEV_TYPE_SECONDARY )
1739                         pSecondaryLCSDEV = pLCSDev;
1740                 }
1741                 else if( hwEthernetType == ETH_TYPE_RARP )
1742                 {
1743                     pARPFrame  = (PARPFRM)pEthFrame->bData;
1744                     pMAC = pARPFrame->bTargEthAddr;
1745 
1746                     if( pLCSPORT->pLCSBLK->fDebug && !bReported )
1747                     {
1748                         logmsg
1749                         (
1750                             _("HHCLC011I Port %2.2X: RARP frame for "
1751                               "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n")
1752 
1753                             ,pLCSPORT->bPort
1754                             ,*(pMAC+0)
1755                             ,*(pMAC+1)
1756                             ,*(pMAC+2)
1757                             ,*(pMAC+3)
1758                             ,*(pMAC+4)
1759                             ,*(pMAC+5)
1760                         );
1761 
1762                         bReported = 1;
1763                     }
1764 
1765                     // If this is an exact match use it
1766                     // otherwise look for primary and secondary
1767                     // default devices
1768                     if( memcmp( pMAC, pLCSPORT->MAC_Address, IFHWADDRLEN ) == 0 )
1769                     {
1770                         pMatchingLCSDEV = pLCSDev;
1771                         break;
1772                     }
1773                     else if( pLCSDev->bType == LCSDEV_TYPE_PRIMARY )
1774                         pPrimaryLCSDEV = pLCSDev;
1775                     else if( pLCSDev->bType == LCSDEV_TYPE_SECONDARY )
1776                         pSecondaryLCSDEV = pLCSDev;
1777                 }
1778                 else if( hwEthernetType == ETH_TYPE_SNA )
1779                 {
1780                     if( pLCSPORT->pLCSBLK->fDebug && !bReported )
1781                     {
1782                         logmsg( _("HHCLC012I Port %2.2X: SNA frame\n"),
1783                                 pLCSPORT->bPort );
1784 
1785                         bReported = 1;
1786                     }
1787 
1788                     if( pLCSDev->bMode == LCSDEV_MODE_SNA )
1789                     {
1790                         pMatchingLCSDEV = pLCSDev;
1791                         break;
1792                     }
1793                 }
1794             }
1795         }
1796 
1797         // If the matching device is not started
1798         // nullify the pointer and pass frame to one
1799         // of the defaults if present
1800         if( pMatchingLCSDEV && !pMatchingLCSDEV->fStarted )
1801             pMatchingLCSDEV = NULL;
1802 
1803         // Match not found, check for default devices
1804         // If one is defined and started, use it
1805         if( !pMatchingLCSDEV )
1806         {
1807             if( pPrimaryLCSDEV && pPrimaryLCSDEV->fStarted )
1808             {
1809                 pMatchingLCSDEV = pPrimaryLCSDEV;
1810 
1811                 if( pLCSPORT->pLCSBLK->fDebug )
1812                     logmsg( _("HHCLC013I Port %2.2X: "
1813                               "No match found - "
1814                               "selecting primary %4.4X\n"),
1815                             pLCSPORT->bPort, pMatchingLCSDEV->sAddr );
1816             }
1817             else if( pSecondaryLCSDEV && pSecondaryLCSDEV->fStarted )
1818             {
1819                 pMatchingLCSDEV = pSecondaryLCSDEV;
1820 
1821                 if( pLCSPORT->pLCSBLK->fDebug )
1822                     logmsg( _("HHCLC014I Port %2.2X: "
1823                               "No match found - "
1824                               "selecting secondary %4.4X\n"),
1825                             pLCSPORT->bPort, pMatchingLCSDEV->sAddr );
1826             }
1827         }
1828 
1829         // No match found, discard frame
1830         if( !pMatchingLCSDEV )
1831         {
1832             if( pLCSPORT->pLCSBLK->fDebug )
1833                 logmsg( _("HHCLC015I Port %2.2X: "
1834                           "No match found - Discarding frame\n"),
1835                         pLCSPORT->bPort );
1836 
1837             continue;
1838         }
1839 
1840         if( pLCSPORT->pLCSBLK->fDebug )
1841             logmsg( _("HHCLC016I Port %2.2X: "
1842                       "Enqueing frame to device %4.4X (%8.8X)\n"),
1843                     pLCSPORT->bPort, pMatchingLCSDEV->sAddr,
1844                     ntohl(pMatchingLCSDEV->lIPAddress) );
1845 
1846         // Match was found.
1847         // Enqueue frame on buffer, if buffer is full, keep trying
1848 
1849         while( LCS_EnqueueEthFrame( pMatchingLCSDEV, pLCSPORT->bPort, szBuff, iLength ) < 0
1850             && pLCSPORT->fd != -1 && !pLCSPORT->fCloseInProgress )
1851         {
1852             if (EMSGSIZE == errno)
1853             {
1854                 if( pLCSPORT->pLCSBLK->fDebug )
1855                     logmsg( _("HHCLC041W Port %2.2X: "
1856                         "Frame too big; discarded.\n"),
1857                         pLCSPORT->bPort );
1858                 break;
1859             }
1860             ASSERT( ENOBUFS == errno );
1861             usleep( CTC_DELAY_USECS );
1862         }
1863     } // end for(;;)
1864 
1865     // We must do the close since we were the one doing the i/o...
1866 
1867     VERIFY( pLCSPORT->fd == -1 || TUNTAP_Close( pLCSPORT->fd ) == 0 );
1868 
1869     // Housekeeping - Cleanup Port Block
1870 
1871     memset( pLCSPORT->MAC_Address,  0, sizeof( MAC ) );
1872     memset( pLCSPORT->szNetDevName, 0, IFNAMSIZ );
1873     memset( pLCSPORT->szMACAddress, 0, 32 );
1874 
1875     for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE; pLCSRTE = pLCSPORT->pRoutes )
1876     {
1877         pLCSPORT->pRoutes = pLCSRTE->pNext;
1878         free( pLCSRTE );
1879         pLCSRTE = NULL;
1880     }
1881 
1882     pLCSPORT->sIPAssistsSupported = 0;
1883     pLCSPORT->sIPAssistsEnabled   = 0;
1884 
1885     pLCSPORT->fUsed       = 0;
1886     pLCSPORT->fLocalMAC   = 0;
1887     pLCSPORT->fCreated    = 0;
1888     pLCSPORT->fStarted    = 0;
1889     pLCSPORT->fRouteAdded = 0;
1890     pLCSPORT->fd          = -1;
1891 
1892     return NULL;
1893 
1894 } // end of LCS_PortThread
1895 
1896 // ====================================================================
1897 //                       LCS_EnqueueEthFrame
1898 // ====================================================================
1899 //
1900 // Places the provided ethernet frame in the next available frame
1901 // slot in the adapter buffer.
1902 //
1903 //   pData       points the the Ethernet packet just received
1904 //   iSize       is the size of the Ethernet packet
1905 //
1906 // Returns:
1907 //
1908 //  0 == Success
1909 // -1 == Failure; errno = ENOBUFS:  No buffer space available
1910 //                        EMSGSIZE: Message too long
1911 //
1912 // --------------------------------------------------------------------
1913 
LCS_EnqueueEthFrame(PLCSDEV pLCSDEV,BYTE bPort,BYTE * pData,size_t iSize)1914 static int  LCS_EnqueueEthFrame( PLCSDEV pLCSDEV, BYTE   bPort,
1915                                  BYTE*   pData,   size_t iSize )
1916 {
1917     PLCSETHFRM  pLCSEthFrame;
1918 
1919     // Will frame NEVER fit into buffer??
1920     if( iSize > MAX_LCS_ETH_FRAME_SIZE( pLCSDEV ) )
1921     {
1922         errno = EMSGSIZE;   // Message too long
1923         return -1;          // (-1==failure)
1924     }
1925 
1926     obtain_lock( &pLCSDEV->Lock );
1927 
1928     // Ensure we dont overflow the buffer
1929     if( ( pLCSDEV->iFrameOffset +                   // Current buffer Offset
1930           sizeof( LCSETHFRM ) +                     // Size of Frame Header
1931           iSize +                                   // Size of Ethernet packet
1932           sizeof(pLCSEthFrame->bLCSHdr.hwOffset) )  // Size of Frame terminator
1933         > pLCSDEV->iMaxFrameBufferSize )            // Size of Frame buffer
1934     {
1935         release_lock( &pLCSDEV->Lock );
1936         errno = ENOBUFS;    // No buffer space available
1937         return -1;          // (-1==failure)
1938     }
1939 
1940     // Point to next available LCS Frame slot in our buffer
1941     pLCSEthFrame = (PLCSETHFRM)( pLCSDEV->bFrameBuffer +
1942                                  pLCSDEV->iFrameOffset );
1943 
1944     // Increment offset to NEXT available slot (after ours)
1945     pLCSDEV->iFrameOffset += (U16)(sizeof(LCSETHFRM) + iSize);
1946 
1947     // Plug updated offset to next frame into our frame header
1948     STORE_HW( pLCSEthFrame->bLCSHdr.hwOffset, pLCSDEV->iFrameOffset );
1949 
1950     // Finish building the LCS Ethernet Passthru frame header
1951     pLCSEthFrame->bLCSHdr.bType = LCS_FRMTYP_ENET;
1952     pLCSEthFrame->bLCSHdr.bSlot = bPort;
1953 
1954     // Copy Ethernet packet to LCS Ethernet Passthru frame
1955     memcpy( pLCSEthFrame->bData, pData, iSize );
1956 
1957     // Tell "LCS_Read" function that data is available for reading
1958     pLCSDEV->fDataPending = 1;
1959 
1960     release_lock( &pLCSDEV->Lock );
1961 
1962     // (wake up "LCS_Read" function)
1963     obtain_lock( &pLCSDEV->EventLock );
1964     signal_condition( &pLCSDEV->Event );
1965     release_lock( &pLCSDEV->EventLock );
1966 
1967     return 0;       // (success)
1968 }
1969 
1970 // ====================================================================
1971 //                       LCS_EnqueueReplyFrame
1972 // ====================================================================
1973 //
1974 // Copy a pre-built LCS Command Frame reply frame of iSize bytes
1975 // to the next available frame slot. Returns 0 on success, -1 and
1976 // errno set to ENOBUFS on failure (no room (yet) in o/p buffer).
1977 // The LCS device lock must NOT be held when called.
1978 //
1979 // --------------------------------------------------------------------
1980 
LCS_EnqueueReplyFrame(PLCSDEV pLCSDEV,PLCSCMDHDR pReply,size_t iSize)1981 static int  LCS_EnqueueReplyFrame( PLCSDEV pLCSDEV, PLCSCMDHDR pReply,
1982                                                     size_t     iSize )
1983 {
1984     PLCSCMDHDR  pReplyCmdFrame;
1985 
1986     obtain_lock( &pLCSDEV->Lock );
1987 
1988     // Ensure we dont overflow the buffer
1989     if( ( pLCSDEV->iFrameOffset +           // Current buffer Offset
1990           iSize +                           // Size of reply frame
1991           sizeof(pReply->bLCSHdr.hwOffset)) // Size of Frame terminator
1992         > pLCSDEV->iMaxFrameBufferSize )    // Size of Frame buffer
1993     {
1994         release_lock( &pLCSDEV->Lock );
1995         errno = ENOBUFS;                    // No buffer space available
1996         return -1;                          // (-1==failure)
1997     }
1998 
1999     // Point to next available LCS Frame slot in our buffer...
2000     pReplyCmdFrame = (PLCSCMDHDR)( pLCSDEV->bFrameBuffer +
2001                                    pLCSDEV->iFrameOffset );
2002 
2003     // Copy the reply frame into the frame buffer slot...
2004     memcpy( pReplyCmdFrame, pReply, iSize );
2005 
2006     // Increment buffer offset to NEXT next-available-slot...
2007     pLCSDEV->iFrameOffset += (U16) iSize;
2008 
2009     // Store offset of next frame
2010     STORE_HW( pReplyCmdFrame->bLCSHdr.hwOffset, pLCSDEV->iFrameOffset );
2011 
2012     // Mark reply pending
2013     pLCSDEV->fReplyPending = 1;
2014 
2015     release_lock( &pLCSDEV->Lock );
2016 
2017     return 0;   // success
2018 }
2019 
2020 // ====================================================================
2021 //                         ParseArgs
2022 // ====================================================================
2023 
ParseArgs(DEVBLK * pDEVBLK,PLCSBLK pLCSBLK,int argc,char ** argv)2024 int  ParseArgs( DEVBLK* pDEVBLK, PLCSBLK pLCSBLK,
2025                 int argc, char** argv )
2026 {
2027     struct in_addr  addr;               // Work area for addresses
2028     MAC             mac;
2029     int             i;
2030 #if defined(OPTION_W32_CTCI)
2031     int             iKernBuff;
2032     int             iIOBuff;
2033 #endif
2034 
2035     // Housekeeping
2036     memset( &addr, 0, sizeof( struct in_addr ) );
2037 
2038     // Set some initial defaults
2039 #if defined( WIN32 )
2040     pLCSBLK->pszTUNDevice   = strdup( tt32_get_default_iface() );
2041 #else
2042     pLCSBLK->pszTUNDevice   = strdup( HERCTUN_DEV );
2043 #endif
2044     pLCSBLK->pszOATFilename = NULL;
2045     pLCSBLK->pszIPAddress   = NULL;
2046     pLCSBLK->pszMACAddress  = NULL;
2047 #if defined( OPTION_W32_CTCI )
2048     pLCSBLK->iKernBuff = DEF_CAPTURE_BUFFSIZE;
2049     pLCSBLK->iIOBuff   = DEF_PACKET_BUFFSIZE;
2050 #endif
2051 
2052     // Initialize getopt's counter. This is necessary in the case
2053     // that getopt was used previously for another device.
2054     optind = 0;
2055 
2056     // Build new argv list.
2057     // getopt_long used to work on old format configuration statements
2058     // because LCS was the first argument passed to the device
2059     // initialization routine (and was interpreted by getopt*
2060     // as the program name and ignored). Now that argv[0] is a valid
2061     // argument, we need to shift the arguments and insert a dummy
2062     // argv[0];
2063 
2064     // Don't allow us to exceed the allocated storage (sanity check)
2065     if( argc > (MAX_ARGS-1))
2066         argc = (MAX_ARGS-1);
2067 
2068     for( i = argc; i > 0; i-- )
2069         argv[i] = argv[i - 1];
2070 
2071     argc++;
2072     argv[0] = pDEVBLK->typname;
2073 
2074     // Parse the optional arguments
2075 
2076     OPTRESET();
2077     optind=0;
2078     while( 1 )
2079     {
2080         int     c;
2081 
2082 #if defined(HAVE_GETOPT_LONG)
2083         int     iOpt;
2084 
2085         static struct option options[] =
2086         {
2087             { "dev",   1, NULL, 'n' },
2088 #if defined(OPTION_W32_CTCI)
2089             { "kbuff", 1, NULL, 'k' },
2090             { "ibuff", 1, NULL, 'i' },
2091 #endif
2092             { "oat",   1, NULL, 'o' },
2093             { "mac",   1, NULL, 'm' },
2094             { "debug", 0, NULL, 'd' },
2095             { NULL,    0, NULL, 0   }
2096         };
2097 
2098         c = getopt_long( argc, argv,
2099                          "n"
2100 #if defined( OPTION_W32_CTCI )
2101                          ":k:i"
2102 #endif
2103                          ":o:m:d", options, &iOpt );
2104 #else /* defined(HAVE_GETOPT_LONG) */
2105         c = getopt( argc, argv, "n"
2106 #if defined( OPTION_W32_CTCI )
2107             ":k:i"
2108 #endif
2109             ":o:m:d" );
2110 #endif /* defined(HAVE_GETOPT_LONG) */
2111 
2112         if( c == -1 )
2113             break;
2114 
2115         switch( c )
2116         {
2117         case 'n':
2118             if( strlen( optarg ) > sizeof( pDEVBLK->filename ) - 1 )
2119             {
2120                 logmsg( _("HHCLC017E %4.4X invalid device name %s\n"),
2121                         pDEVBLK->devnum, optarg );
2122                 return -1;
2123             }
2124 
2125             pLCSBLK->pszTUNDevice = strdup( optarg );
2126 
2127             break;
2128 
2129 #if defined( OPTION_W32_CTCI )
2130         case 'k':     // Kernel Buffer Size (Windows only)
2131             iKernBuff = atoi( optarg );
2132 
2133             if( iKernBuff * 1024 < MIN_CAPTURE_BUFFSIZE    ||
2134                 iKernBuff * 1024 > MAX_CAPTURE_BUFFSIZE )
2135             {
2136                 logmsg( _("HHCLC052E %4.4X: Invalid kernel buffer size %s\n"),
2137                     pDEVBLK->devnum, optarg );
2138                 return -1;
2139             }
2140 
2141             pLCSBLK->iKernBuff = iKernBuff * 1024;
2142             break;
2143 
2144         case 'i':     // I/O Buffer Size (Windows only)
2145             iIOBuff = atoi( optarg );
2146 
2147             if( iIOBuff * 1024 < MIN_PACKET_BUFFSIZE    ||
2148                 iIOBuff * 1024 > MAX_PACKET_BUFFSIZE )
2149             {
2150                 logmsg( _("HHCLC053E %4.4X: Invalid DLL I/O buffer size %s\n"),
2151                     pDEVBLK->devnum, optarg );
2152                 return -1;
2153             }
2154 
2155             pLCSBLK->iIOBuff = iIOBuff * 1024;
2156             break;
2157 #endif // defined( OPTION_W32_CTCI )
2158 
2159         case 'o':
2160             pLCSBLK->pszOATFilename = strdup( optarg );
2161             break;
2162 
2163         case 'm':
2164             if( ParseMAC( optarg, mac ) != 0 )
2165             {
2166                 logmsg( _("HHCLC018E %4.4X invalid MAC address %s\n"),
2167                         pDEVBLK->devnum, optarg );
2168                 return -1;
2169             }
2170 
2171             strcpy( pLCSBLK->Port[0].szMACAddress, optarg );
2172             pLCSBLK->Port[0].fLocalMAC = TRUE;
2173 
2174             break;
2175 
2176         case 'd':
2177             pLCSBLK->fDebug = TRUE;
2178             break;
2179 
2180         default:
2181             break;
2182         }
2183     }
2184 
2185     argc -= optind;
2186     argv += optind;
2187 
2188     if( argc > 1 )
2189     {
2190         logmsg( _("HHCLC019E %4.4X too many arguments in statement.\n"),
2191                 pDEVBLK->devnum );
2192         return -1;
2193     }
2194 
2195     // If an argument is left, it is the optional IP Address
2196     if( argc )
2197     {
2198         if( inet_aton( *argv, &addr ) == 0 )
2199         {
2200             logmsg( _("HHCLC020E %4.4X invalid IP address %s\n"),
2201                     pDEVBLK->devnum, *argv );
2202             return -1;
2203         }
2204 
2205         if ( pLCSBLK->pszIPAddress )
2206         {
2207             free( pLCSBLK->pszIPAddress );
2208             pLCSBLK->pszIPAddress = NULL;
2209         }
2210 
2211         pLCSBLK->pszIPAddress = strdup( *argv );
2212     }
2213 
2214     return 0;
2215 }
2216 
2217 // ====================================================================
2218 //                           BuildOAT
2219 // ====================================================================
2220 
BuildOAT(char * pszOATName,PLCSBLK pLCSBLK)2221 static int  BuildOAT( char* pszOATName, PLCSBLK pLCSBLK )
2222 {
2223     FILE*       fp;
2224     char        szBuff[255];
2225 
2226     int         i;
2227     char        c;                      // Character work area
2228     char*       pszStatement = NULL;    // -> Resolved statement
2229     char*       pszKeyword;             // -> Statement keyword
2230     char*       pszOperand;             // -> Statement operand
2231     int         argc;                   // Number of args
2232     char*       argv[MAX_ARGS];         // Argument array
2233 
2234     PLCSPORT    pLCSPORT;
2235     PLCSDEV     pLCSDev;
2236     PLCSRTE     pLCSRTE;
2237 
2238     U16         sPort;
2239     BYTE        bMode;
2240     U16         sDevNum;
2241     BYTE        bType;
2242     U32         lIPAddr      = 0;       // (network byte order)
2243     char*       pszIPAddress = NULL;
2244     char*       pszNetAddr   = NULL;
2245     char*       pszNetMask   = NULL;
2246 
2247     struct in_addr  addr;               // Work area for addresses
2248     char        pathname[MAX_PATH];     // pszOATName in host path format
2249 
2250     // Open the configuration file
2251     hostpath(pathname, pszOATName, sizeof(pathname));
2252     fp = fopen( pathname, "r" );
2253     if( !fp )
2254     {
2255         logmsg( _("HHCLC039E Cannot open file %s: %s\n"),
2256                 pszOATName, strerror( errno ) );
2257         return -1;
2258     }
2259 
2260     for(;;)
2261     {
2262         /* This IF statement block was relocated from below     @PJJ */
2263         /* the next IF statement block as otherwise the last    @PJJ */
2264         /* FREE will never take place.                          @PJJ */
2265         if (pszStatement)
2266         {
2267             free(pszStatement);
2268             pszStatement = NULL;
2269         }
2270 
2271         // Read next record from the OAT file
2272         if( !ReadOAT( pszOATName, fp, szBuff ) )
2273         {
2274             fclose( fp );
2275             return 0;
2276         }
2277 
2278 //      if( pszStatement )                                   /* @PJJ */
2279 //      {                                                    /* @PJJ */
2280 //          free( pszStatement );                            /* @PJJ */
2281 //          pszStatement = NULL;                             /* @PJJ */
2282 //      }                                                    /* @PJJ */
2283 
2284 #if defined(OPTION_CONFIG_SYMBOLS)
2285         // Make a copy of the OAT statement with symbols resolved
2286         pszStatement = resolve_symbol_string( szBuff );
2287 #else
2288         // Make a copy of the OAT statement
2289         pszStatement = strdup( szBuff );
2290 #endif
2291 
2292         sPort        = 0;
2293         bMode        = 0;
2294         sDevNum      = 0;
2295         bType        = 0;
2296         pszIPAddress = NULL;
2297         pszNetAddr   = NULL;
2298         pszNetMask   = NULL;
2299 
2300         memset( &addr, 0, sizeof( addr ) );
2301 
2302         // Split the statement into keyword and first operand
2303         pszKeyword = strtok( pszStatement, " \t" );
2304         pszOperand = strtok( NULL,   " \t" );
2305 
2306         // Extract any arguments
2307         for( argc = 0;
2308              argc < MAX_ARGS &&
2309                  ( argv[argc] = strtok( NULL, " \t" ) ) != NULL &&
2310                  argv[argc][0] != '#';
2311              argc++ );
2312 
2313         // Clear any unused argument pointers
2314         for( i = argc; i < MAX_ARGS; i++ )
2315             argv[i] = NULL;
2316 
2317         if( strcasecmp( pszKeyword, "HWADD" ) == 0 )
2318         {
2319             if( !pszOperand        ||
2320                 argc       != 1    ||
2321                 sscanf( pszOperand, "%hi%c", &sPort, &c ) != 1 )
2322             {
2323                 logmsg( _("HHCLC021E Invalid HWADD statement in %s: %s\n"),
2324                         pszOATName, szBuff );
2325                 return -1;
2326             }
2327 
2328             pLCSPORT = &pLCSBLK->Port[sPort];
2329 
2330             if( ParseMAC( argv[0], pLCSPORT->MAC_Address ) != 0 )
2331             {
2332                 logmsg( _("HHCLC022E Invalid MAC in HWADD statement "
2333                           "in %s: %s (%s)\n "),
2334                         pszOATName, szBuff, argv[0] );
2335 
2336                 memset( pLCSPORT->MAC_Address, 0, sizeof(MAC) );
2337                 return -1;
2338             }
2339 
2340             strcpy( pLCSPORT->szMACAddress, argv[0] );
2341             pLCSPORT->fLocalMAC = TRUE;
2342         }
2343         else if( strcasecmp( pszKeyword, "ROUTE" ) == 0 )
2344         {
2345             if( !pszOperand        ||
2346                 argc       != 2    ||
2347                 sscanf( pszOperand, "%hi%c", &sPort, &c ) != 1 )
2348             {
2349                 logmsg( _("HHCLC023E Invalid ROUTE statement in %s: %s\n"),
2350                         pszOATName, szBuff );
2351                 return -1;
2352             }
2353 
2354             if( inet_aton( argv[0], &addr ) == 0 )
2355             {
2356                 logmsg( _("HHCLC024E Invalid net address in ROUTE %s: %s (%s)\n"),
2357                         pszOATName, szBuff, argv[0] );
2358                 return -1;
2359             }
2360 
2361             pszNetAddr = strdup( argv[0] );
2362 
2363             if( inet_aton( argv[1], &addr ) == 0 )
2364             {
2365                 free(pszNetAddr);
2366                 logmsg( _("HHCLC025E Invalid net mask in ROUTE %s: %s (%s)\n"),
2367                         pszOATName, szBuff, argv[1] );
2368                 return -1;
2369             }
2370 
2371             pszNetMask = strdup( argv[1] );
2372 
2373             pLCSPORT = &pLCSBLK->Port[sPort];
2374 
2375             if( !pLCSPORT->pRoutes )
2376             {
2377                 pLCSPORT->pRoutes = malloc( sizeof( LCSRTE ) );
2378                 pLCSRTE = pLCSPORT->pRoutes;
2379             }
2380             else
2381             {
2382                 for( pLCSRTE = pLCSPORT->pRoutes;
2383                      pLCSRTE->pNext;
2384                      pLCSRTE = pLCSRTE->pNext );
2385 
2386                 pLCSRTE->pNext = malloc( sizeof( LCSRTE ) );
2387                 pLCSRTE = pLCSRTE->pNext;
2388             }
2389 
2390             pLCSRTE->pszNetAddr = pszNetAddr;
2391             pLCSRTE->pszNetMask = pszNetMask;
2392             pLCSRTE->pNext      = NULL;
2393         }
2394         else // (presumed OAT file device statement)
2395         {
2396             if( !pszKeyword || !pszOperand )
2397             {
2398                 logmsg( _("HHCLC026E Error in %s: "
2399                           "Missing device number or mode\n"),
2400                         pszOATName );
2401                 return -1;
2402             }
2403 
2404             if( strlen( pszKeyword ) > 4 ||
2405                 sscanf( pszKeyword, "%hx%c", &sDevNum, &c ) != 1 )
2406             {
2407                 logmsg( _("HHCLC027E Error in %s: %s: "
2408                           "Invalid device number\n"),
2409                         pszOATName, pszKeyword );
2410                 return -1;
2411             }
2412 
2413             if( strcasecmp( pszOperand, "IP" ) == 0 )
2414             {
2415                 bMode = LCSDEV_MODE_IP;
2416 
2417                 if( argc < 1 )
2418                 {
2419                     logmsg( _("HHCLC028E Error in %s: %s:"
2420                               "Missing PORT number\n"),
2421                             pszOATName, szBuff );
2422                     return -1;
2423                 }
2424 
2425                 if( sscanf( argv[0], "%hi%c", &sPort, &c ) != 1 )
2426                 {
2427                     logmsg( _("HHCLC029E Error in %s: %s: "
2428                               "Invalid PORT number\n"),
2429                             pszOATName, argv[0] );
2430                     return -1;
2431                 }
2432 
2433                 if( argc > 1 )
2434                 {
2435                     if( strcasecmp( argv[1], "PRI" ) == 0 )
2436                         bType = LCSDEV_TYPE_PRIMARY;
2437                     else if( strcasecmp( argv[1], "SEC" ) == 0 )
2438                         bType = LCSDEV_TYPE_SECONDARY;
2439                     else if( strcasecmp( argv[1], "NO" ) == 0 )
2440                         bType = LCSDEV_TYPE_NONE;
2441                     else
2442                     {
2443                         logmsg( _("HHCLC031E Error in %s: %s: "
2444                                   "Invalid entry starting at %s\n"),
2445                                 pszOATName, szBuff, argv[1] );
2446                         return -1;
2447                     }
2448 
2449                     if( argc > 2 )
2450                     {
2451                         pszIPAddress = strdup( argv[2] );
2452 
2453                         if( inet_aton( pszIPAddress, &addr ) == 0 )
2454                         {
2455                             logmsg( _("HHCLC032E Error in %s: %s: "
2456                                       "Invalid IP address (%s)\n"),
2457                                     pszOATName, szBuff, pszIPAddress );
2458                             return -1;
2459                         }
2460 
2461                         lIPAddr = addr.s_addr;  // (network byte order)
2462                     }
2463                 }
2464             }
2465             else if( strcasecmp( pszOperand, "SNA" ) == 0 )
2466             {
2467                 bMode = LCSDEV_MODE_SNA;
2468 
2469                 if( argc < 1 )
2470                 {
2471                     logmsg( _("HHCLC033E Error in %s: %s: "
2472                               "Missing PORT number\n"),
2473                             pszOATName, szBuff );
2474                     return -1;
2475                 }
2476 
2477                 if( sscanf( argv[0], "%hi%c", &sPort, &c ) != 1 )
2478                 {
2479                     logmsg( _("HHCLC034E Error in %s: %s:"
2480                               "Invalid PORT number\n"),
2481                             pszOATName, argv[0] );
2482                     return -1;
2483                 }
2484 
2485                 if( argc > 1 )
2486                 {
2487                     logmsg( _("HHCLC035E Error in %s: %s: "
2488                             "SNA does not accept any arguments\n"),
2489                             pszOATName, szBuff );
2490                     return -1;
2491                 }
2492             }
2493             else
2494             {
2495                 logmsg( _("HHCLC036E Error in %s: %s: "
2496                           "Invalid MODE\n"),
2497                         pszOATName, pszOperand );
2498                 return -1;
2499             }
2500 
2501             // Create new LCS Device...
2502 
2503             pLCSDev = malloc( sizeof( LCSDEV ) );
2504             memset( pLCSDev, 0, sizeof( LCSDEV ) );
2505 
2506             pLCSDev->sAddr        = sDevNum;
2507             pLCSDev->bMode        = bMode;
2508             pLCSDev->bPort        = sPort;
2509             pLCSDev->bType        = bType;
2510             pLCSDev->lIPAddress   = lIPAddr;   // (network byte order)
2511             pLCSDev->pszIPAddress = pszIPAddress;
2512             pLCSDev->pNext        = NULL;
2513 
2514             // Add it to end of chain...
2515 
2516             if( !pLCSBLK->pDevices )
2517                 pLCSBLK->pDevices = pLCSDev; // (first link in chain)
2518             else
2519             {
2520                 PLCSDEV pOldLastLCSDEV;
2521                 // (find last link in chain)
2522                 for( pOldLastLCSDEV = pLCSBLK->pDevices;
2523                      pOldLastLCSDEV->pNext;
2524                      pOldLastLCSDEV = pOldLastLCSDEV->pNext );
2525                 // (add new link to end of chain)
2526                 pOldLastLCSDEV->pNext = pLCSDev;
2527             }
2528 
2529             // Count it...
2530 
2531             if(pLCSDev->bMode == LCSDEV_MODE_IP)
2532                 pLCSBLK->icDevices += 2;
2533             else
2534                 pLCSBLK->icDevices += 1;
2535 
2536         } // end OAT file statement
2537 
2538     } // end for(;;)
2539 
2540     return 0;
2541 }
2542 
2543 // ====================================================================
2544 //                           ReadOAT
2545 // ====================================================================
2546 
ReadOAT(char * pszOATName,FILE * fp,char * pszBuff)2547 static char*  ReadOAT( char* pszOATName, FILE* fp, char* pszBuff )
2548 {
2549     int     c;                          // Character work area
2550     int     iLine = 0;                  // Statement number
2551     int     iLen;                       // Statement length
2552 
2553     while( 1 )
2554     {
2555         // Increment statement number
2556         iLine++;
2557 
2558         // Read next statement from OAT
2559         for( iLen = 0; ; )
2560         {
2561             // Read character from OAT
2562             c = fgetc( fp );
2563 
2564             // Check for I/O error
2565             if( ferror( fp ) )
2566             {
2567                 logmsg( _("HHCLC037E Error reading file %s line %d: %s\n"),
2568                         pszOATName, iLine, strerror( errno ) );
2569                 return NULL;
2570             }
2571 
2572             // Check for end of file
2573             if( iLen == 0 && ( c == EOF || c == '\x1A' ) )
2574                 return NULL;
2575 
2576             // Check for end of line
2577             if( c == '\n' || c == EOF || c == '\x1A' )
2578                 break;
2579 
2580             // Ignore leading blanks and tabs
2581             if( iLen == 0 && ( c == ' ' || c == '\t' ) )
2582                 continue;
2583 
2584             // Ignore nulls and carriage returns
2585             if( c == '\0' || c == '\r' )
2586                 continue;
2587 
2588             // Check that statement does not overflow bufffer
2589             if( iLen >= 255 )
2590             {
2591                 logmsg( _("HHCLC038E File %s line %d is too long\n"),
2592                         pszOATName, iLine );
2593                 exit(1);
2594             }
2595 
2596             // Append character to buffer
2597             pszBuff[iLen++] = c;
2598         }
2599 
2600         // Remove trailing blanks and tabs
2601         while( iLen > 0 &&
2602                ( pszBuff[iLen-1] == ' '  ||
2603                  pszBuff[iLen-1] == '\t' ) )
2604             iLen--;
2605 
2606         pszBuff[iLen] = '\0';
2607 
2608         // Ignore comments and null statements
2609         if( iLen == 0 || pszBuff[0] == '*' || pszBuff[0] == '#' )
2610             continue;
2611 
2612         break;
2613     }
2614 
2615     return pszBuff;
2616 }
2617 
2618 // ====================================================================
2619 //                 Device Handler Information
2620 // ====================================================================
2621 
2622 /* NOTE : lcs_device_hndinfo is NEVER static as it is referenced by the CTC meta driver */
2623 DEVHND lcs_device_hndinfo =
2624 {
2625         &LCS_Init,                    /* Device Initialisation      */
2626         &LCS_ExecuteCCW,              /* Device CCW execute         */
2627         &LCS_Close,                   /* Device Close               */
2628         &LCS_Query,                   /* Device Query               */
2629         NULL,                          /* Device Start channel pgm   */
2630         NULL,                          /* Device End channel pgm     */
2631         NULL,                          /* Device Resume channel pgm  */
2632         NULL,                          /* Device Suspend channel pgm */
2633         NULL,                          /* Device Read                */
2634         NULL,                          /* Device Write               */
2635         NULL,                          /* Device Query used          */
2636         NULL,                          /* Device Reserve             */
2637         NULL,                          /* Device Release             */
2638         NULL,                          /* Device Attention           */
2639         CTC_Immed_Commands,            /* Immediate CCW Codes        */
2640         NULL,                          /* Signal Adapter Input       */
2641         NULL,                          /* Signal Adapter Output      */
2642         NULL,                          /* Hercules suspend           */
2643         NULL                           /* Hercules resume            */
2644 };
2645 
2646 
2647 /* Libtool static name colision resolution */
2648 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
2649 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
2650 #define hdl_ddev hdt3088_LTX_hdl_ddev
2651 #define hdl_depc hdt3088_LTX_hdl_depc
2652 #define hdl_reso hdt3088_LTX_hdl_reso
2653 #define hdl_init hdt3088_LTX_hdl_init
2654 #define hdl_fini hdt3088_LTX_hdl_fini
2655 #endif
2656 
2657 #if defined(OPTION_DYNAMIC_LOAD)
2658 HDL_DEPENDENCY_SECTION;
2659 {
2660      HDL_DEPENDENCY(HERCULES);
2661      HDL_DEPENDENCY(DEVBLK);
2662 }
2663 END_DEPENDENCY_SECTION
2664 
2665 HDL_REGISTER_SECTION;       // ("Register" our entry-points)
2666 
2667 //             Hercules's        Our
2668 //             registered        overriding
2669 //             entry-point       entry-point
2670 //             name              value
2671 
2672 #if defined( WIN32 )
2673   HDL_REGISTER ( debug_tt32_stats,   display_tt32_stats        );
2674   HDL_REGISTER ( debug_tt32_tracing, enable_tt32_debug_tracing );
2675 #endif
2676 
2677 END_REGISTER_SECTION
2678 
2679 
2680 HDL_DEVICE_SECTION;
2681 {
2682     HDL_DEVICE(LCS, lcs_device_hndinfo );
2683 
2684 // ZZ the following device types should be moved to
2685 // ZZ their own loadable modules
2686     HDL_DEVICE(3088, ctcadpt_device_hndinfo );
2687     HDL_DEVICE(CTCI, ctci_device_hndinfo    );
2688     HDL_DEVICE(CTCT, ctct_device_hndinfo    );
2689     HDL_DEVICE(CTCE, ctce_device_hndinfo    );
2690     HDL_DEVICE(VMNET,vmnet_device_hndinfo   );
2691 #if defined(WIN32)
2692     HDL_DEVICE(CTCI-W32,ctci_device_hndinfo );
2693 #endif
2694 }
2695 END_DEVICE_SECTION
2696 #endif
2697 
2698 //-----------------------------------------------------------------------------
2699 // Debugging...
2700 
2701 #if !defined( DEBUG) && !defined( _DEBUG )  // only needed for Release builds
2702   #ifdef NO_LCS_OPTIMIZE                    // for reliable breakpoints and instr stepping
2703     #pragma warning( pop )                  // restore previous settings
2704     #pragma optimize( "", on )              // restore previous settings
2705   #endif // NO_LCS_OPTIMIZE
2706 #endif // !defined( DEBUG) && !defined( _DEBUG )
2707 
2708 //-----------------------------------------------------------------------------
2709 
2710 #endif /* !defined(__SOLARIS__)  jbs 10/2007 10/2007 */
2711