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