mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-07-26 02:29:51 +02:00
9693 lines
369 KiB
C
9693 lines
369 KiB
C
/* CTC_PTP.C (C) Copyright Ian Shorter, 2011-2012 */
|
|
/* (C) and others 2013-2021 */
|
|
/* MPC Point-To-Point (PTP) */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/* This module contains device handling functions for the */
|
|
/* MPCPTP and/or MPCPTP6 emulated connection */
|
|
/* */
|
|
/* Device module hdtptp */
|
|
/* */
|
|
/* hercules.cnf: */
|
|
/* 0E20-0E21 PTP <optional parameters> */
|
|
/* See README.NETWORKING for details. */
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h"
|
|
#include "ctcadpt.h"
|
|
#include "tuntap.h"
|
|
#include "resolve.h"
|
|
#include "ctc_ptp.h"
|
|
#include "mpc.h"
|
|
#include "opcode.h"
|
|
#include "herc_getopt.h" /* getopt dynamic linking kludge */
|
|
|
|
#if !defined( OPTION_W32_CTCI )
|
|
#include <ifaddrs.h>
|
|
#if defined( __sun__ )
|
|
#include <sys/sockio.h>
|
|
#endif
|
|
#endif
|
|
|
|
DISABLE_GCC_UNUSED_SET_WARNING;
|
|
|
|
#if defined(WIN32) && !defined(_MSVC_) && !defined(HDL_USE_LIBTOOL)
|
|
SYSBLK *psysblk;
|
|
#define sysblk (*psysblk)
|
|
#endif
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Various constants used in this module, of which the significance */
|
|
/* isn't clear. */
|
|
/* See also the process identifiers later in the source. */
|
|
/* ------------------------------------------------------------------ */
|
|
#define PTPHX0_SEQNUM 0x00050010 // !!! //
|
|
#define MPC_TH_UNKNOWN10 0x0FFC // !!! // |
|
|
#define XDATALEN1 0x0FFC // !!! // | Are these related?
|
|
#define LEN_OF_PAGE_ONE 4092 // // |
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Function Declarations */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
static int ptp_init( DEVBLK* pDEVBLK, int argc, char *argv[] );
|
|
|
|
static void ptp_execute_ccw( DEVBLK* pDEVBLK, BYTE bCode,
|
|
BYTE bFlags, BYTE bChained,
|
|
U32 uCount, BYTE bPrevCode,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static int ptp_close( DEVBLK* pDEVBLK );
|
|
|
|
static void ptp_query( DEVBLK* pDEVBLK, char** ppszClass,
|
|
int iBufLen, char* pBuffer );
|
|
|
|
static void ptp_write( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static void write_th( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static int write_rrh_8108( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH );
|
|
|
|
static void ptp_halt_or_clear( DEVBLK* pDEVBLK );
|
|
|
|
static void ptp_read( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static void read_read_buffer( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual, PTPHDR* pPTPHDR );
|
|
|
|
static void read_chain_buffer( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual, PTPHDR* pPTPHDR );
|
|
|
|
static void* ptp_read_thread( void* arg /* PTPBLK* pPTPBLK */ );
|
|
|
|
static void* add_buffer_to_chain_and_signal_event( PTPATH* pPTPATH, PTPHDR* pPTPHDR );
|
|
static void* add_buffer_to_chain( PTPATH* pPTPATH, PTPHDR* pPTPHDR );
|
|
static PTPHDR* remove_buffer_from_chain( PTPATH* pPTPATH );
|
|
static void* remove_and_free_any_buffers_on_chain( PTPATH* pPTPATH );
|
|
|
|
static PTPHDR* alloc_ptp_buffer( DEVBLK* pDEVBLK, int iSize );
|
|
static void* alloc_storage( DEVBLK* pDEVBLK, int iSize );
|
|
|
|
|
|
static int parse_conf_stmt( DEVBLK* pDEVBLK, PTPBLK* pPTPBLK,
|
|
int argc, char** argv );
|
|
static int get_preconfigured_value( DEVBLK* pDEVBLK, PTPBLK* pPTPBLK );
|
|
static int check_specified_value( DEVBLK* pDEVBLK, PTPBLK* pPTPBLK );
|
|
|
|
static int raise_unsol_int( DEVBLK* pDEVBLK, BYTE bStatus, int iDelay );
|
|
|
|
static void* ptp_unsol_int_thread( void* arg /* PTPINT* pPTPINT */ );
|
|
|
|
static void ptp_get_tod_clock( BYTE* TodClock );
|
|
|
|
static void get_subarea_address( BYTE* SAaddress );
|
|
|
|
static void write_hx0_01( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static void write_hx0_00( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static void write_hx2( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual );
|
|
|
|
static PTPHSV* point_CSVcv( DEVBLK* pDEVBLK, PTPHX2* pPTPHX2 );
|
|
|
|
static int write_rrh_417E( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH );
|
|
|
|
static PTPHDR* build_417E_cm_enable( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH,
|
|
MPC_PUS* pMPC_PUS, u_int* fxSideWins );
|
|
static PTPHDR* build_417E_cm_setup( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH );
|
|
static PTPHDR* build_417E_cm_confirm( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH );
|
|
static PTPHDR* build_417E_ulp_enable( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH,
|
|
MPC_PUS* pMPC_PUS, u_int* fxSideWins );
|
|
static PTPHDR* build_417E_ulp_setup( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH );
|
|
static PTPHDR* build_417E_ulp_confirm( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH );
|
|
static PTPHDR* build_417E_dm_act( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRH );
|
|
|
|
static int write_rrh_C17E( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH );
|
|
|
|
static int write_rrh_C108( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH );
|
|
|
|
static PTPHDR* build_C108_will_you_start_4( DEVBLK* pDEVBLK );
|
|
static PTPHDR* build_C108_will_you_start_6( DEVBLK* pDEVBLK );
|
|
static PTPHDR* build_C108_i_will_start_4( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIX, U16 uRCode );
|
|
static PTPHDR* build_C108_i_will_start_6( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIX, U16 uRCode );
|
|
static PTPHDR* build_C108_my_address_4( DEVBLK* pDEVBLK );
|
|
static PTPHDR* build_C108_my_address_6( DEVBLK* pDEVBLK, u_int fLL );
|
|
static PTPHDR* build_C108_your_address_4( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIX, U16 uRCode );
|
|
static PTPHDR* build_C108_your_address_6( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIX, U16 uRCode );
|
|
static PTPHDR* build_C108_will_you_stop_4( DEVBLK* pDEVBLK );
|
|
static PTPHDR* build_C108_will_you_stop_6( DEVBLK* pDEVBLK );
|
|
static PTPHDR* build_C108_i_will_stop_4( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIX );
|
|
static PTPHDR* build_C108_i_will_stop_6( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIX );
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
static void build_8108_icmpv6_packets( DEVBLK* pDEVBLK );
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
static void gen_csv_sid( BYTE* pClock1, BYTE* pClock2, BYTE* pToken );
|
|
|
|
static void shift_left_dbl( U32* even, U32* odd, int number );
|
|
static void shift_right_dbl( U32* even, U32* odd, int number );
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
static void calculate_icmpv6_checksum( PIP6FRM pIP6FRM, BYTE* pIcmpHdr, int iIcmpLen );
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Ivan Warren 20040227 */
|
|
/* This table is used by channel.c to determine if a CCW code is an */
|
|
/* immediate command or not */
|
|
/* The table is addressed in the DEVHND structure as 'DEVIMM immed' */
|
|
/* 0 : Command is NOT an immediate command */
|
|
/* 1 : Command is an immediate command */
|
|
/* Note : An immediate command is defined as a command which returns */
|
|
/* CE (channel end) during initialisation (that is, no data is */
|
|
/* actually transferred). In this case, IL is not indicated for a CCW */
|
|
/* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */
|
|
/* effect */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
static BYTE ptp_immed_commands[256] =
|
|
{
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
|
|
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* 1x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9x */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Ax */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Bx */
|
|
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* Cx */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Dx */
|
|
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* Ex */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* Fx */
|
|
};
|
|
|
|
// 0x03 No Operation
|
|
// 0x17 Control
|
|
// 0xC3 Set Extended Mode
|
|
// 0xE3 Prepare
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Device Handler Information Block */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
DEVHND ptp_device_hndinfo =
|
|
{
|
|
&ptp_init, /* Device Initialization */
|
|
&ptp_execute_ccw, /* Device CCW execute */
|
|
&ptp_close, /* Device Close */
|
|
&ptp_query, /* Device Query */
|
|
NULL, /* Device Extended Query */
|
|
NULL, /* Device Start channel pgm */
|
|
NULL, /* Device End channel pgm */
|
|
NULL, /* Device Resume channel pgm */
|
|
NULL, /* Device Suspend channel pgm */
|
|
&ptp_halt_or_clear, /* Device Halt channel pgm */
|
|
NULL, /* Device Read */
|
|
NULL, /* Device Write */
|
|
NULL, /* Device Query used */
|
|
NULL, /* Device Reserve */
|
|
NULL, /* Device Release */
|
|
NULL, /* Device Attention */
|
|
ptp_immed_commands, /* Immediate CCW Codes */
|
|
NULL, /* Signal Adapter Input */
|
|
NULL, /* Signal Adapter Output */
|
|
NULL, /* Signal Adapter Sync */
|
|
NULL, /* Signal Adapter Output Mult */
|
|
NULL, /* QDIO subsys desc */
|
|
NULL, /* QDIO set subchan ind */
|
|
NULL, /* Hercules suspend */
|
|
NULL /* Hercules resume */
|
|
};
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Constants */
|
|
/* ------------------------------------------------------------------ */
|
|
static const BYTE VTAM_ebcdic[4] = { 0xE5,0xE3,0xC1,0xD4 };
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Process Identifiers */
|
|
/* ------------------------------------------------------------------ */
|
|
// When the connection is being started it seems that the connecting
|
|
// VTAMs set up a pair of processes (or channels or threads or
|
|
// subtasks or paths or ...). I don't know what they should be called,
|
|
// but I have called them processes, hence process identifiers.
|
|
//
|
|
// All of the identifiers that have been seen are 5-bytes in length,
|
|
// with the first byte containing 0x05, the second and third bytes
|
|
// containing 0x0001, and the fourth and fifth bytes containing a
|
|
// non-consecutive value that increases with each restart of the
|
|
// connection. Is the first byte (0x05) a length field, or something
|
|
// else entirely? Are the second and third bytes (0x0001) part of
|
|
// the identifier, or something else entirely?
|
|
//
|
|
// It has been assumed that the first byte is a length field, and
|
|
// the second to fifth bytes are a 4-byte (32-bit) identifier.
|
|
//
|
|
// Whenever a connection is being started the identifiers are copied
|
|
// from these static fields, and then the static fields are
|
|
// incremented by a fixed value. This ensures that each connection
|
|
// uses a unique set of values. Empirical evidence suggests that if
|
|
// the connection is restarted by the y-side guest and the x-side
|
|
// does not change its values the restart is not successful, perhaps
|
|
// because the y-side VTAM has a memory of the values previously
|
|
// used. Or there may be another cause yet to be discovered. Anyway,
|
|
// a VTAM to VTAM connection uses different values, so we will to.
|
|
// Additionally, if there are multiple connections to the same
|
|
// guest, the possibility of confusion for the guest is reduced if
|
|
// each connection uses different values.
|
|
|
|
static LOCK TokenLock;
|
|
static int TokenLockInitialized = FALSE;
|
|
static U32 uTokenIssuerRm = 0x00011001;
|
|
static U32 uTokenCmFilter = 0x00011002;
|
|
static U32 uTokenCmConnection = 0x00011003;
|
|
static U32 uTokenUlpFilter = 0x00011004;
|
|
static U32 uTokenUlpConnection = 0x00011005;
|
|
|
|
#define INCREMENT_TOKEN 0x00000010
|
|
|
|
|
|
/* ================================================================== */
|
|
/* ptp_init() */
|
|
/* ================================================================== */
|
|
|
|
// ptp_init is called once for each of the device addresses specified
|
|
// on the configuration statement. When ptp_init is called the number
|
|
// of device addresses specified on the configuration statement or
|
|
// whether the device addresses are contiguous is unknown to ptp_init.
|
|
// ptp_init is called by function attach_device() in config.c
|
|
|
|
int ptp_init( DEVBLK* pDEVBLK, int argc, char *argv[] )
|
|
{
|
|
PTPBLK* pPTPBLK; // PTPBLK
|
|
PTPATH* pPTPATHre; // PTPATH Read
|
|
PTPATH* pPTPATHwr; // PTPATH Write
|
|
// int nIFType; // Interface type
|
|
int nIFFlags; // Interface flags
|
|
int rc = 0; // Return code
|
|
int i;
|
|
char thread_name[32]; // ptp_read_thread
|
|
|
|
|
|
// nIFType = // Interface type
|
|
// 0
|
|
// | IFF_TUN // ("TUN", not "tap")
|
|
// | IFF_NO_PI // (no packet info)
|
|
// ;
|
|
|
|
nIFFlags = // Interface flags
|
|
0
|
|
| IFF_UP // (interface is being enabled)
|
|
| IFF_BROADCAST // (interface broadcast addr is valid)
|
|
;
|
|
|
|
#if defined( TUNTAP_IFF_RUNNING_NEEDED )
|
|
|
|
nIFFlags |= // ADDITIONAL Interface flags
|
|
0
|
|
| IFF_RUNNING // (interface is ALSO operational)
|
|
;
|
|
|
|
#endif /* defined( TUNTAP_IFF_RUNNING_NEEDED ) */
|
|
|
|
// Initialize fields in the DEVBLK that are referenced by commands.
|
|
pDEVBLK->devtype = 0x3088;
|
|
pDEVBLK->excps = 0;
|
|
|
|
// Initialize locking for the tokens, if necessary.
|
|
if (!TokenLockInitialized)
|
|
{
|
|
TokenLockInitialized = TRUE;
|
|
initialize_lock( &TokenLock );
|
|
}
|
|
|
|
// PTP is a group device, with two devices in the group. The first
|
|
// device is deemed to be the read device, the second device is deemed
|
|
// to be the write device. (Function group_device() is in config.c)
|
|
if (!group_device( pDEVBLK, PTP_GROUP_SIZE ))
|
|
return 0;
|
|
|
|
// Allocate the PTPBLK.
|
|
pPTPBLK = alloc_storage( pDEVBLK, (int)sizeof(PTPBLK) );
|
|
if (!pPTPBLK)
|
|
return -1;
|
|
|
|
// Allocate the PTPATH Read.
|
|
pPTPATHre = alloc_storage( pDEVBLK, (int)sizeof(PTPATH) );
|
|
if (!pPTPATHre)
|
|
{
|
|
free( pPTPBLK );
|
|
return -1;
|
|
}
|
|
|
|
// Allocate the PTPATH Write.
|
|
pPTPATHwr = alloc_storage( pDEVBLK, (int)sizeof(PTPATH) );
|
|
if (!pPTPATHwr)
|
|
{
|
|
free( pPTPATHre );
|
|
free( pPTPBLK );
|
|
return -1;
|
|
}
|
|
|
|
// Parse configuration file statement.
|
|
if (parse_conf_stmt( pDEVBLK, pPTPBLK, argc, (char**) argv ) != 0)
|
|
{
|
|
free( pPTPATHwr );
|
|
free( pPTPATHre );
|
|
free( pPTPBLK );
|
|
return -1;
|
|
}
|
|
|
|
// Connect the DEVBLKs, the PTPATHs and the PTPBLK together.
|
|
pPTPBLK->pPTPATHRead = pPTPATHre; // Make the PTPBLK point
|
|
pPTPBLK->pPTPATHWrite = pPTPATHwr; // to the two PTPATHs.
|
|
|
|
pPTPBLK->pDEVBLKRead = pDEVBLK->group->memdev[0]; // Make the PTPBLK point
|
|
pPTPBLK->pDEVBLKWrite = pDEVBLK->group->memdev[1]; // to the two DEVBLKs.
|
|
|
|
pPTPATHre->pPTPBLK = pPTPBLK; // Make each PTPATH point
|
|
pPTPATHwr->pPTPBLK = pPTPBLK; // to the PTPBLK.
|
|
|
|
pPTPATHre->pDEVBLK = pPTPBLK->pDEVBLKRead; // Make each PTPATH point
|
|
pPTPATHwr->pDEVBLK = pPTPBLK->pDEVBLKWrite; // to the appropriate DEVBLK
|
|
|
|
pPTPBLK->pDEVBLKRead->dev_data = pPTPATHre; // Make each DEVBLK point
|
|
pPTPBLK->pDEVBLKWrite->dev_data = pPTPATHwr; // to the appropriate PTPATH.
|
|
|
|
pDEVBLK->group->grp_data = pPTPBLK; // Make DEVGRP point to PTPBLK
|
|
|
|
// Initialize various fields in the DEVBLKs.
|
|
SetSIDInfo( pPTPBLK->pDEVBLKRead, 0x3088, 0x08, 0x3088, 0x01 );
|
|
SetSIDInfo( pPTPBLK->pDEVBLKWrite, 0x3088, 0x08, 0x3088, 0x01 );
|
|
|
|
pPTPBLK->pDEVBLKRead->ctctype = CTC_PTP;
|
|
pPTPBLK->pDEVBLKRead->ctcxmode = 1;
|
|
|
|
pPTPBLK->pDEVBLKWrite->ctctype = CTC_PTP;
|
|
pPTPBLK->pDEVBLKWrite->ctcxmode = 1;
|
|
|
|
strlcpy( pPTPBLK->pDEVBLKRead->filename,
|
|
pPTPBLK->szTUNCharDevName,
|
|
sizeof(pPTPBLK->pDEVBLKRead->filename) );
|
|
strlcpy( pPTPBLK->pDEVBLKWrite->filename,
|
|
pPTPBLK->szTUNCharDevName,
|
|
sizeof(pPTPBLK->pDEVBLKWrite->filename) );
|
|
|
|
// Initialize various fields in the PTPATHs.
|
|
pPTPATHre->bDLCtype = DLCTYPE_READ; // Read path
|
|
pPTPATHwr->bDLCtype = DLCTYPE_WRITE; // write path
|
|
|
|
// Initialize various fields in the PTPBLK.
|
|
pPTPBLK->fd = -1;
|
|
|
|
pPTPBLK->xDataLen1 = XDATALEN1; // !!! //
|
|
|
|
pPTPBLK->xMaxReadLen = ( pPTPBLK->iMaxBfru * 4096 ) - 4;
|
|
// xMaxReadLen = 20476 (0x4FFC) when iMaxBfru = 5
|
|
// xMaxReadLen = 65532 (0xFFFC) when iMaxBfru = 16
|
|
|
|
pPTPBLK->xActMTU = ( ( pPTPBLK->iMaxBfru - 1 ) * 4096 ) - 2048;
|
|
// xActMTU = 14336 (0x3800) when iMaxBfru = 5
|
|
// xActMTU = 59392 (0xE800) when iMaxBfru = 16
|
|
|
|
ptp_get_tod_clock( pPTPBLK->xStartTime ); // x-side's start time
|
|
|
|
for( i = 0; i <= 7; i++ )
|
|
pPTPBLK->xFirstCsvSID2[i] = pPTPBLK->xStartTime[i] ^ 0xAA;
|
|
|
|
get_subarea_address( pPTPBLK->xSAaddress ); // x-side's subarea address
|
|
|
|
// Initialize locking and event mechanisms in the PTPBLK and the PTPATHs.
|
|
initialize_lock( &pPTPBLK->ReadBufferLock );
|
|
initialize_lock( &pPTPBLK->ReadEventLock );
|
|
initialize_condition( &pPTPBLK->ReadEvent );
|
|
initialize_lock( &pPTPBLK->UnsolListLock );
|
|
initialize_lock( &pPTPBLK->UpdateLock );
|
|
|
|
initialize_lock( &pPTPATHre->ChainLock );
|
|
initialize_lock( &pPTPATHre->UnsolEventLock );
|
|
initialize_condition( &pPTPATHre->UnsolEvent );
|
|
|
|
initialize_lock( &pPTPATHwr->ChainLock );
|
|
initialize_lock( &pPTPATHwr->UnsolEventLock );
|
|
initialize_condition( &pPTPATHwr->UnsolEvent );
|
|
|
|
// Create the TUN interface.
|
|
rc = TUNTAP_CreateInterface( pPTPBLK->szTUNCharDevName,
|
|
#if defined(BUILD_HERCIFC)
|
|
(pPTPBLK->fPreconfigured ? IFF_NO_HERCIFC : 0) |
|
|
#endif //defined(BUILD_HERCIFC)
|
|
IFF_TUN | IFF_NO_PI,
|
|
&pPTPBLK->fd,
|
|
pPTPBLK->szTUNIfName,
|
|
&pPTPBLK->internal );
|
|
if (rc < 0)
|
|
{
|
|
// Disconnect the DEVGRP from the PTPBLK.
|
|
pDEVBLK->group->grp_data = NULL;
|
|
// Disconnect the DEVBLKs from the PTPATHs.
|
|
pPTPBLK->pDEVBLKRead->dev_data = NULL;
|
|
pPTPBLK->pDEVBLKWrite->dev_data = NULL;
|
|
// Free the PTPATHs and PTPBLK
|
|
free( pPTPATHwr );
|
|
free( pPTPATHre );
|
|
free( pPTPBLK );
|
|
return -1;
|
|
}
|
|
// HHC00901 "%1d:%04X %s: interface %s, type %s opened"
|
|
WRMSG(HHC00901, "I", SSID_TO_LCSS(pPTPBLK->pDEVBLKRead->ssid), pPTPBLK->pDEVBLKRead->devnum,
|
|
pPTPBLK->pDEVBLKRead->typname, pPTPBLK->szTUNIfName, "TUN" );
|
|
|
|
// Copy the fd to make panel.c happy
|
|
pPTPBLK->pDEVBLKRead->fd =
|
|
pPTPBLK->pDEVBLKWrite->fd = pPTPBLK->fd;
|
|
|
|
/* */
|
|
if (!pPTPBLK->fPreconfigured) {
|
|
|
|
// Set various values for the TUN interface.
|
|
#if defined(OPTION_W32_CTCI)
|
|
{
|
|
struct tt32ctl tt32ctl;
|
|
|
|
memset( &tt32ctl, 0, sizeof(tt32ctl) );
|
|
STRLCPY( tt32ctl.tt32ctl_name, pPTPBLK->szTUNIfName );
|
|
|
|
// Set the specified driver/dll i/o buffer sizes..
|
|
tt32ctl.tt32ctl_devbuffsize = pPTPBLK->iKernBuff;
|
|
if (TUNTAP_IOCtl( pPTPBLK->fd, TT32SDEVBUFF, (char*)&tt32ctl ) != 0)
|
|
{
|
|
// HHC00902 "%1d:%04X %s: ioctl '%s' failed for device '%s': '%s'"
|
|
WRMSG(HHC00902, "W", SSID_TO_LCSS(pPTPBLK->pDEVBLKRead->ssid),
|
|
pPTPBLK->pDEVBLKRead->devnum, pPTPBLK->pDEVBLKRead->typname,
|
|
"TT32SDEVBUFF", pPTPBLK->szTUNIfName, strerror( errno ) );
|
|
}
|
|
|
|
tt32ctl.tt32ctl_iobuffsize = pPTPBLK->iIOBuff;
|
|
if (TUNTAP_IOCtl( pPTPBLK->fd, TT32SIOBUFF, (char*)&tt32ctl ) != 0)
|
|
{
|
|
// HHC00902 "%1d:%04X %s: ioctl '%s' failed for device '%s': '%s'"
|
|
WRMSG(HHC00902, "W", SSID_TO_LCSS(pPTPBLK->pDEVBLKRead->ssid),
|
|
pPTPBLK->pDEVBLKRead->devnum, pPTPBLK->pDEVBLKRead->typname,
|
|
"TT32SIOBUFF", pPTPBLK->szTUNIfName, strerror( errno ) );
|
|
}
|
|
}
|
|
|
|
#ifdef OPTION_TUNTAP_SETMACADDR
|
|
VERIFY( TUNTAP_SetMACAddr( pPTPBLK->szTUNIfName, pPTPBLK->szMACAddress ) == 0 );
|
|
#endif /* OPTION_TUNTAP_SETMACADDR */
|
|
|
|
#ifdef OPTION_TUNTAP_CLRIPADDR
|
|
VERIFY( TUNTAP_ClrIPAddr ( pPTPBLK->szTUNIfName ) == 0 );
|
|
#endif /* OPTION_TUNTAP_CLRIPADDR */
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
VERIFY( TUNTAP_SetIPAddr( pPTPBLK->szTUNIfName, pPTPBLK->szDriveIPAddr4 ) == 0 );
|
|
|
|
VERIFY( TUNTAP_SetDestAddr( pPTPBLK->szTUNIfName, pPTPBLK->szGuestIPAddr4 ) == 0 );
|
|
|
|
#ifdef OPTION_TUNTAP_SETNETMASK
|
|
VERIFY( TUNTAP_SetNetMask( pPTPBLK->szTUNIfName, pPTPBLK->szNetMask ) == 0 );
|
|
#endif /* OPTION_TUNTAP_SETNETMASK */
|
|
}
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
VERIFY( TUNTAP_SetIPAddr6( pPTPBLK->szTUNIfName,
|
|
pPTPBLK->szDriveLLAddr6,
|
|
pPTPBLK->szDriveLLxSiz6 ) == 0 );
|
|
|
|
VERIFY( TUNTAP_SetIPAddr6( pPTPBLK->szTUNIfName,
|
|
pPTPBLK->szDriveIPAddr6,
|
|
pPTPBLK->szDrivePfxSiz6 ) == 0 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
VERIFY( TUNTAP_SetMTU( pPTPBLK->szTUNIfName, pPTPBLK->szMTU ) == 0 );
|
|
|
|
VERIFY( TUNTAP_SetFlags( pPTPBLK->szTUNIfName, nIFFlags ) == 0 );
|
|
|
|
}
|
|
|
|
// Create the read thread.
|
|
MSGBUF( thread_name, "%s %4.4X ReadThread",
|
|
pPTPBLK->pDEVBLKRead->typname,
|
|
pPTPBLK->pDEVBLKRead->devnum);
|
|
rc = create_thread( &pPTPBLK->tid, JOINABLE, ptp_read_thread, pPTPBLK, thread_name );
|
|
if (rc)
|
|
{
|
|
// Report the bad news.
|
|
// HHC00102 "Error in function create_thread(): %s"
|
|
WRMSG(HHC00102, "E", strerror(rc));
|
|
// Close the TUN interface.
|
|
VERIFY( pPTPBLK->fd == -1 || TUNTAP_Close( pPTPBLK->fd, pPTPBLK->internal ) == 0 );
|
|
pPTPBLK->fd = -1;
|
|
// Disconnect the DEVGRP from the PTPBLK.
|
|
pDEVBLK->group->grp_data = NULL;
|
|
// Disconnect the DEVBLKs from the PTPATHs.
|
|
pPTPBLK->pDEVBLKRead->dev_data = NULL;
|
|
pPTPBLK->pDEVBLKWrite->dev_data = NULL;
|
|
// Free the PTPATHs and PTPBLK
|
|
free( pPTPATHwr );
|
|
free( pPTPATHre );
|
|
free( pPTPBLK );
|
|
return -1;
|
|
}
|
|
pPTPBLK->pDEVBLKRead->tid = pPTPBLK->tid;
|
|
pPTPBLK->pDEVBLKWrite->tid = pPTPBLK->tid;
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPCONFVALUE)
|
|
{
|
|
#if defined(OPTION_W32_CTCI)
|
|
// HHC03952 "%1d:%04X PTP: MAC: %s"
|
|
WRMSG(HHC03952, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szMACAddress );
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
// HHC03953 "%1d:%04X PTP: IPv4: Drive %s/%s (%s): Guest %s"
|
|
WRMSG(HHC03953, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szDriveIPAddr4,
|
|
pPTPBLK->szDrivePfxSiz4,
|
|
pPTPBLK->szNetMask,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
// HHC03954 "%1d:%04X PTP: IPv6: Drive %s/%s %s/%s: Guest %s"
|
|
WRMSG(HHC03954, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szDriveLLAddr6,
|
|
pPTPBLK->szDriveLLxSiz6,
|
|
pPTPBLK->szDriveIPAddr6,
|
|
pPTPBLK->szDrivePfxSiz6,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
|
|
return 0;
|
|
} /* End function ptp_init() */
|
|
|
|
|
|
/* ================================================================== */
|
|
/* ptp_execute_ccw() */
|
|
/* ================================================================== */
|
|
// bCode, bFlags and uCount are from the executing CCW.
|
|
// bChained, bPrevCode and iCCWSeq are only meaningful for the second
|
|
// or subsequent CCWs of a chain. bChained contains 0x40, pPrevCode
|
|
// contains the opcode of the previous CCW in the chain and iCCWSeq
|
|
// contains the sequence number of the CCW in the chain (0 = first,
|
|
// 1 = second, 2 = third, etc).
|
|
|
|
void ptp_execute_ccw( DEVBLK* pDEVBLK, BYTE bCode,
|
|
BYTE bFlags, BYTE bChained,
|
|
U32 uCount, BYTE bPrevCode,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
int iNum; // Number of bytes to move
|
|
|
|
UNREFERENCED( bFlags );
|
|
UNREFERENCED( bChained );
|
|
UNREFERENCED( bPrevCode );
|
|
|
|
|
|
// Intervention required if the device file is not open
|
|
if (pDEVBLK->fd < 0)
|
|
{
|
|
pDEVBLK->sense[0] = SENSE_IR;
|
|
*pUnitStat = CSW_CE | CSW_DE | CSW_UC;
|
|
return;
|
|
}
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPCCW)
|
|
{
|
|
// HHC03992 "%1d:%04X %s: Code %02X: Flags %02X: Count %08X: Chained %02X: PrevCode %02X: CCWseq %d"
|
|
WRMSG(HHC03992, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
bCode, bFlags, uCount, bChained, bPrevCode, iCCWSeq );
|
|
}
|
|
|
|
// Process depending on CCW bCode
|
|
switch (bCode)
|
|
{
|
|
case 0x01: // 0MMMMM01 WRITE
|
|
//------------------------------------------------------------
|
|
// WRITE
|
|
//------------------------------------------------------------
|
|
|
|
// Return normal status if CCW count is zero
|
|
if (uCount == 0)
|
|
{
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
break;
|
|
}
|
|
|
|
// Process the Write data
|
|
ptp_write( pDEVBLK, uCount, iCCWSeq, pIOBuf, pMore, pUnitStat, pResidual );
|
|
|
|
break;
|
|
|
|
case 0x02: // MMMMMM10 READ
|
|
/* ---------------------------------------------------------- */
|
|
/* READ */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
// Process the Read depending on the current State
|
|
ptp_read( pDEVBLK, uCount, iCCWSeq, pIOBuf, pMore, pUnitStat, pResidual );
|
|
|
|
break;
|
|
|
|
case 0xE3: // 11100011 PREPARE
|
|
/* ---------------------------------------------------------- */
|
|
/* PREPARE */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
break;
|
|
|
|
case 0x17: // MMMMM111 CONTROL
|
|
/* ---------------------------------------------------------- */
|
|
/* CONTROL */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
break;
|
|
|
|
case 0x14: // XXX10100 SENSE COMMAND BYTE
|
|
/* ---------------------------------------------------------- */
|
|
/* SENSE COMMAND BYTE */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
// We will assume that we (i.e. the x-side) raised an Attention
|
|
// interrupt earlier and that the y-side is determining why.
|
|
// Normally this will only occur during the handshake sequence.
|
|
// Return CCW opcode, residual byte count and unit status.
|
|
*pIOBuf = pPTPATH->bAttnCode;
|
|
*pResidual = uCount - 1;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
// Clear the CCW opcode.
|
|
pPTPATH->bAttnCode = 0x00;
|
|
|
|
break;
|
|
|
|
case 0x04: // 00000100 SENSE ADAPTOR STATE
|
|
/* ---------------------------------------------------------- */
|
|
/* SENSE ADAPTER STATE */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
// Calculate residual byte count
|
|
iNum = ( uCount < pDEVBLK->numsense ) ? uCount : pDEVBLK->numsense;
|
|
|
|
*pResidual = uCount - iNum;
|
|
|
|
if (uCount < pDEVBLK->numsense)
|
|
*pMore = 1;
|
|
|
|
// Copy device sense bytes to channel I/O buffer
|
|
memcpy( pIOBuf, pDEVBLK->sense, iNum );
|
|
|
|
// Clear the device sense bytes
|
|
memset( pDEVBLK->sense, 0, sizeof(pDEVBLK->sense) );
|
|
|
|
// Return unit status
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
break;
|
|
|
|
case 0xE4: // 11100100 SENSE ID
|
|
/* ---------------------------------------------------------- */
|
|
/* SENSE ID */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
// Calculate residual byte count
|
|
iNum = ( uCount < pDEVBLK->numdevid ) ? uCount : pDEVBLK->numdevid;
|
|
|
|
*pResidual = uCount - iNum;
|
|
|
|
if (uCount < pDEVBLK->numdevid)
|
|
*pMore = 1;
|
|
|
|
// Copy device identifier bytes to channel I/O buffer
|
|
memcpy( pIOBuf, pDEVBLK->devid, iNum );
|
|
|
|
// Return unit status
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
break;
|
|
|
|
case 0x03: // M0MMM011 NO OPERATION
|
|
case 0xC3: // 11000011 SET EXTENDED MODE
|
|
/* ---------------------------------------------------------- */
|
|
/* NO OPERATON & SET EXTENDED MODE */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
// Return unit status
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
break;
|
|
|
|
default:
|
|
/* ---------------------------------------------------------- */
|
|
/* INVALID OPERATION */
|
|
/* ---------------------------------------------------------- */
|
|
|
|
// Set command reject sense byte, and unit check status
|
|
pDEVBLK->sense[0] = SENSE_CR;
|
|
*pUnitStat = CSW_CE | CSW_DE | CSW_UC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPCCW)
|
|
{
|
|
// HHC03993 "%1d:%04X %s: Status %02X: Residual %08X: More %02X"
|
|
WRMSG(HHC03993, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
*pUnitStat, *pResidual, *pMore );
|
|
}
|
|
|
|
return;
|
|
} /* End function ptp_execute_ccw() */
|
|
|
|
|
|
/* ================================================================== */
|
|
/* ptp_close() */
|
|
/* ================================================================== */
|
|
|
|
int ptp_close( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
|
|
|
|
// Close the device file (if not already closed)
|
|
if (pPTPBLK->fd >= 0)
|
|
{
|
|
// PROGRAMMING NOTE: there's currently no way to interrupt
|
|
// the "ptp_read_thread"s TUNTAP_Read of the adapter. Thus
|
|
// we must simply wait for ptp_read_thread to eventually
|
|
// notice that we're doing a close (via our setting of the
|
|
// fCloseInProgress flag). Its TUNTAP_Read will eventually
|
|
// timeout after a few seconds (currently 5, which is dif-
|
|
// ferent than the PTP_READ_TIMEOUT_SECS timeout value the
|
|
// ptp_read function uses) and will then do the close of
|
|
// the adapter for us (TUNTAP_Close) so we don't have to.
|
|
// All we need to do is ask it to exit (via our setting of
|
|
// the fCloseInProgress flag) and then wait for it to exit
|
|
// (which, as stated, could take up to a max of 5 seconds).
|
|
|
|
// All of this is simply because it's poor form to close a
|
|
// device from one thread while another thread is reading
|
|
// from it. Attempting to do so could trip a race condition
|
|
// wherein the internal i/o buffers used to process the
|
|
// read request could have been freed (by the close call)
|
|
// by the time the read request eventually gets serviced.
|
|
|
|
TID tid = pPTPBLK->tid;
|
|
pPTPBLK->fCloseInProgress = 1; // (ask read thread to exit)
|
|
join_thread( tid, NULL ); // (wait for thread to end)
|
|
#if defined( OPTION_FTHREADS )
|
|
detach_thread( tid ); // (wait for thread to end)
|
|
#endif
|
|
}
|
|
|
|
pDEVBLK->fd = -1; // indicate we're now closed
|
|
|
|
return 0;
|
|
} /* End function ptp_close() */
|
|
|
|
|
|
/* ================================================================== */
|
|
/* ptp_query() */
|
|
/* ================================================================== */
|
|
|
|
// Note: this function is called four times every second!
|
|
|
|
void ptp_query( DEVBLK* pDEVBLK, char** ppszClass,
|
|
int iBufLen, char* pBuffer )
|
|
{
|
|
char filename[ PATH_MAX + 1 ]; /* full path or just name */
|
|
|
|
PTPATH* pPTPATH;
|
|
PTPBLK* pPTPBLK;
|
|
char* pGuestIP4;
|
|
char* pDriveIP4;
|
|
#if defined(ENABLE_IPV6)
|
|
char* pGuestIP6;
|
|
char* pDriveIP6;
|
|
#endif
|
|
|
|
BEGIN_DEVICE_CLASS_QUERY( "CTCA", pDEVBLK, ppszClass, iBufLen, pBuffer );
|
|
|
|
pPTPATH = pDEVBLK->dev_data;
|
|
|
|
if (!pPTPATH)
|
|
{
|
|
strlcpy(pBuffer,"*Uninitialized",iBufLen);
|
|
return;
|
|
}
|
|
|
|
pPTPBLK = pPTPATH->pPTPBLK;
|
|
|
|
if (strlen( pPTPBLK->szGuestIPAddr4 ))
|
|
pGuestIP4 = pPTPBLK->szGuestIPAddr4;
|
|
else
|
|
pGuestIP4 = "-";
|
|
|
|
if (strlen( pPTPBLK->szDriveIPAddr4 ))
|
|
pDriveIP4 = pPTPBLK->szDriveIPAddr4;
|
|
else
|
|
pDriveIP4 = "-";
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
if (strlen( pPTPBLK->szGuestIPAddr6 ))
|
|
pGuestIP6 = pPTPBLK->szGuestIPAddr6;
|
|
else
|
|
pGuestIP6 = "-";
|
|
|
|
if (strlen( pPTPBLK->szDriveIPAddr6 ))
|
|
pDriveIP6 = pPTPBLK->szDriveIPAddr6;
|
|
else
|
|
pDriveIP6 = "-";
|
|
|
|
if (pPTPBLK->fIPv4Spec && pPTPBLK->fIPv6Spec)
|
|
{
|
|
snprintf( pBuffer, iBufLen, "%s %s/%s %s/%s (%s)%s IO[%"PRIu64"]",
|
|
pPTPBLK->pDEVBLKRead->typname,
|
|
pGuestIP4,
|
|
pDriveIP4,
|
|
pGuestIP6,
|
|
pDriveIP6,
|
|
pPTPBLK->szTUNIfName,
|
|
pPTPBLK->uDebugMask ? " -d" : "",
|
|
pDEVBLK->excps );
|
|
}
|
|
else if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
snprintf( pBuffer, iBufLen, "%s %s/%s (%s)%s IO[%"PRIu64"]",
|
|
pPTPBLK->pDEVBLKRead->typname,
|
|
pGuestIP4,
|
|
pDriveIP4,
|
|
pPTPBLK->szTUNIfName,
|
|
pPTPBLK->uDebugMask ? " -d" : "",
|
|
pDEVBLK->excps );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
else
|
|
{
|
|
snprintf( pBuffer, iBufLen, "%s %s/%s (%s)%s IO[%"PRIu64"]",
|
|
pPTPBLK->pDEVBLKRead->typname,
|
|
pGuestIP6,
|
|
pDriveIP6,
|
|
pPTPBLK->szTUNIfName,
|
|
pPTPBLK->uDebugMask ? " -d" : "",
|
|
pDEVBLK->excps );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pBuffer[iBufLen-1] = '\0';
|
|
|
|
return;
|
|
} /* End function ptp_query() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ptp_write() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Input:
|
|
// pDEVBLK A pointer to the CTC adapter device block
|
|
// uCount The I/O buffer length from the read CCW
|
|
// pIOBuf The I/O buffer from the read CCW
|
|
// iCCWSeq The sequence number of the CCW in the chain
|
|
// (0 = first, 1 = second, 2 = third, etc).
|
|
// Output:
|
|
// pMore Set to 1 if packet data exceeds CCW count
|
|
// pUnitStat The CSW status (CE+DE or CE+DE+UC or CE+DE+UC+SM)
|
|
// pResidual The CSW residual byte count
|
|
|
|
void ptp_write( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
MPC_TH* pMPC_TH = (MPC_TH*)pIOBuf;
|
|
PTPHX0* pPTPHX0 = (PTPHX0*)pIOBuf;
|
|
PTPHX2* pPTPHX2 = (PTPHX2*)pIOBuf;
|
|
|
|
int iTraceLen;
|
|
U32 uFirst4;
|
|
|
|
|
|
// Get the first 4-bytes of what was writen by the guest.
|
|
FETCH_FW( uFirst4, pMPC_TH->first4 );
|
|
|
|
// Display up to 256-bytes of data, if debug is active
|
|
if (pPTPBLK->uDebugMask & DBGPTPDATA)
|
|
{
|
|
// HHC00981 "%1d:%04X %s: Accept data of size %d bytes from guest"
|
|
WRMSG(HHC00981, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, (int)uCount );
|
|
iTraceLen = uCount;
|
|
if (iTraceLen > 256)
|
|
{
|
|
iTraceLen = 256;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, (int)(uCount - iTraceLen) );
|
|
}
|
|
net_data_trace( pDEVBLK, pIOBuf, iTraceLen, FROM_GUEST, 'D', "data", 0 );
|
|
}
|
|
|
|
// Process depending on what was writen by the guest.
|
|
if (uCount >= SIZE_TH &&
|
|
uFirst4 == MPC_TH_FIRST4)
|
|
{
|
|
|
|
// Display TH etc. structured, if debug is active
|
|
if (pPTPBLK->uDebugMask & DBGPTPEXPAND)
|
|
{
|
|
// HHC00981 "%1d:%04X %s: Accept data of size %d bytes from guest"
|
|
WRMSG(HHC00981, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,(int)uCount );
|
|
mpc_display_ptp_th_etc( pDEVBLK, pMPC_TH, FROM_GUEST, 64 );
|
|
}
|
|
|
|
// Process the MPC_TH
|
|
write_th( pDEVBLK, uCount, iCCWSeq, pIOBuf, pMore, pUnitStat, pResidual );
|
|
|
|
}
|
|
else if (uCount >= SIZE_HX0 &&
|
|
pPTPHX0->TH_seg == 0x00 &&
|
|
pPTPHX0->TH_ch_flag == TH_CH_0x00)
|
|
{
|
|
|
|
// Process the PTPHX0 type 0x00
|
|
write_hx0_00( pDEVBLK, uCount, iCCWSeq, pIOBuf, pMore, pUnitStat, pResidual );
|
|
|
|
}
|
|
else if (uCount >= SIZE_HX0 &&
|
|
pPTPHX0->TH_seg == 0x00 &&
|
|
pPTPHX0->TH_ch_flag == TH_CH_0x01)
|
|
{
|
|
|
|
// Process the PTPHX0 type 0x01
|
|
write_hx0_01( pDEVBLK, uCount, iCCWSeq, pIOBuf, pMore, pUnitStat, pResidual );
|
|
|
|
}
|
|
else if (uCount >= (SIZE_HX2 + SIZE_HSV) &&
|
|
( pPTPHX2->Ft & XID2_FORMAT_MASK ) == 0x20 &&
|
|
pPTPHX2->NodeID[0] == 0xFF )
|
|
{
|
|
|
|
// Process the PTPHX2
|
|
write_hx2( pDEVBLK, uCount, iCCWSeq, pIOBuf, pMore, pUnitStat, pResidual );
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// HHC03931 "%1d:%04X PTP: Accept data of size %d bytes contains unknown data"
|
|
WRMSG(HHC03931, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, (int)uCount );
|
|
|
|
// Display up to 128-bytes of data, if debug is not active.
|
|
// If debug is active, the data has already been displayed.
|
|
if (!(pPTPBLK->uDebugMask & DBGPTPDATA))
|
|
{
|
|
iTraceLen = uCount;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, (int)(uCount - iTraceLen) );
|
|
}
|
|
net_data_trace( pDEVBLK, pIOBuf, iTraceLen, FROM_GUEST, 'I', "data", 0 );
|
|
}
|
|
|
|
// None of the accepted data was successfully processed, and it will
|
|
// now be dropped as though it never existed. Inform the guest that
|
|
// the data was successfully processed.
|
|
*pMore = 0;
|
|
*pResidual = 0;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
}
|
|
|
|
return;
|
|
} /* End function ptp_write() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_th() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void write_th( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
|
|
// PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
// PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
MPC_TH* pMPC_TH = (MPC_TH*)pIOBuf; // MPC_TH at start of IObuf
|
|
MPC_RRH* pMPC_RRH = NULL; // MPC_RRH
|
|
int iForRRH;
|
|
U32 uOffRRH;
|
|
U16 uNumRRH;
|
|
int rv = 0;
|
|
int iWhat;
|
|
#define UNKNOWN_RRH 0
|
|
#define RRH_8108 1
|
|
#define RRH_C108 2
|
|
#define RRH_417E 3
|
|
#define RRH_C17E 4
|
|
|
|
UNREFERENCED( uCount );
|
|
UNREFERENCED( iCCWSeq );
|
|
|
|
|
|
// Get the number of MPC_RRH and the displacement from the start
|
|
// of the MPC_TH to the first (or only) MPC_RRH.
|
|
FETCH_HW( uNumRRH, pMPC_TH->numrrh );
|
|
FETCH_FW( uOffRRH, pMPC_TH->offrrh );
|
|
|
|
// Process each of the MPC_RRHs.
|
|
for( iForRRH = 1; iForRRH <= uNumRRH; iForRRH++ )
|
|
{
|
|
|
|
// Point to the first or subsequent MPC_RRH.
|
|
pMPC_RRH = (MPC_RRH*)((BYTE*)pMPC_TH + uOffRRH);
|
|
|
|
// Decide what the RRH contains.
|
|
iWhat = UNKNOWN_RRH;
|
|
if (pMPC_RRH->type == RRH_TYPE_CM)
|
|
{
|
|
if (pMPC_RRH->proto == PROTOCOL_LAYER2)
|
|
{
|
|
iWhat = RRH_8108;
|
|
}
|
|
}
|
|
else if (pMPC_RRH->type == RRH_TYPE_ULP)
|
|
{
|
|
if (pMPC_RRH->proto == PROTOCOL_UNKNOWN)
|
|
{
|
|
iWhat = RRH_417E;
|
|
}
|
|
}
|
|
else if (pMPC_RRH->type == RRH_TYPE_IPA)
|
|
{
|
|
if (pMPC_RRH->proto == PROTOCOL_LAYER2)
|
|
{
|
|
iWhat = RRH_C108;
|
|
}
|
|
else if (pMPC_RRH->proto == PROTOCOL_UNKNOWN)
|
|
{
|
|
iWhat = RRH_C17E;
|
|
}
|
|
}
|
|
|
|
// Process what the RRH contains.
|
|
switch( iWhat )
|
|
{
|
|
|
|
// IP packets
|
|
case RRH_8108:
|
|
rv = write_rrh_8108( pDEVBLK, pMPC_TH, pMPC_RRH );
|
|
break;
|
|
|
|
// Exchange IP information
|
|
case RRH_C108:
|
|
rv = write_rrh_C108( pDEVBLK, pMPC_TH, pMPC_RRH );
|
|
break;
|
|
|
|
// Establish connections
|
|
case RRH_417E:
|
|
rv = write_rrh_417E( pDEVBLK, pMPC_TH, pMPC_RRH );
|
|
break;
|
|
|
|
//
|
|
case RRH_C17E:
|
|
rv = write_rrh_C17E( pDEVBLK, pMPC_TH, pMPC_RRH );
|
|
break;
|
|
|
|
// Unknown RRH
|
|
default:
|
|
// HHC03936 "%1d:%04X PTP: Accept data contains unknown %s"
|
|
WRMSG(HHC03936, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "RRH" );
|
|
mpc_display_rrh( pDEVBLK, pMPC_RRH, FROM_GUEST );
|
|
rv = -2;
|
|
break;
|
|
|
|
}
|
|
|
|
// If the MPC_RRH processing was not successful, let's stop.
|
|
if (rv != 0)
|
|
break;
|
|
|
|
// Get the displacement from the start of the MPC_TH to the
|
|
// next MPC_RRH. pMPC_RRH->offrrh will contain zero if this
|
|
// is the last MPC_RRH.
|
|
FETCH_FW( uOffRRH, pMPC_RRH->offrrh );
|
|
|
|
}
|
|
|
|
// Set the residual byte count and unit status depending on
|
|
// whether the MPC_RRHs have been processed successfully or not.
|
|
switch( rv )
|
|
{
|
|
|
|
// 0 Successful
|
|
// All of the accepted data was successfully processed.
|
|
// -1 No storage available
|
|
// -2 Data problem (i.e. incomplete IP packet)
|
|
// None of the accepted data was successfully processed,
|
|
// or some of the accepted data may have been successfully
|
|
// processed. Either way there is some data that was not
|
|
// successfully processed, and it will now be dropped as
|
|
// though it never existed. Inform the guest that the
|
|
// data was successfully processed.
|
|
case 0:
|
|
case -1:
|
|
case -2:
|
|
*pMore = 0;
|
|
*pResidual = 0;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
break;
|
|
|
|
// -3 The TUNTAP_Write failed
|
|
// Hmm...
|
|
case -3:
|
|
pDEVBLK->sense[0] = SENSE_EC;
|
|
*pUnitStat = CSW_CE | CSW_DE | CSW_UC;
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
} /* End function write_th() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_rrh_8108() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note - the Token is xTokenUlpConnection.
|
|
// In all cases that have been seen the MPC_RRH type 0x8108 is followed
|
|
// by one or more MPC_PH, which are followed by data.
|
|
// The data in a PTP message is usually, but need not be, in a single,
|
|
// contiguous lump. The length and displacement to the various pieces
|
|
// of data are described by the MPC_PHs. If there are multiple pieces
|
|
// of data (i.e. there is more than one MPC_PH), this function copies
|
|
// the multiple pieces into a single contiguous lump in a buffer.
|
|
// Return value
|
|
// 0 Successful
|
|
// -1 No storage available for a data buffer
|
|
// -2 Data problem (i.e. incomplete IP packet)
|
|
// -3 The TUNTAP_Write failed
|
|
|
|
int write_rrh_8108( DEVBLK* pDEVBLK, MPC_TH* pMPC_TH, MPC_RRH* pMPC_RRH )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
MPC_PH* pMPC_PH;
|
|
BYTE* pData;
|
|
int iDataLen;
|
|
BYTE* pDataBuf;
|
|
U16 uNumPH;
|
|
U16 uOffPH;
|
|
int iForPH;
|
|
U32 uLenData;
|
|
U32 uOffData;
|
|
BYTE* pData1;
|
|
PIP4FRM pIP4FRM;
|
|
PIP6FRM pIP6FRM;
|
|
U16 uPayLen;
|
|
int iPktLen;
|
|
u_int fWantPkt;
|
|
int iPktVer;
|
|
char cPktVer[8];
|
|
int iTraceLen;
|
|
int rv;
|
|
|
|
|
|
// Get the number of MPC_PHs and point to the first (or only) MPC_PH
|
|
// following the MPC_RRH.
|
|
FETCH_HW( uNumPH, pMPC_RRH->numph );
|
|
FETCH_HW( uOffPH, pMPC_RRH->offph );
|
|
pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + uOffPH);
|
|
|
|
// Get the length of and the pointer to the data referenced by the
|
|
// first (or only) MPC_PH
|
|
FETCH_F3( uLenData, pMPC_PH->lendata );
|
|
FETCH_FW( uOffData, pMPC_PH->offdata );
|
|
pData = (BYTE*)pMPC_TH + uOffData;
|
|
|
|
// Get the total length of the data referenced by all of the MPC_PHs.
|
|
FETCH_F3( iDataLen, pMPC_RRH->lenalda );
|
|
|
|
// Check whether there is more than one MPC_PH.
|
|
if (uNumPH == 1)
|
|
{
|
|
pDataBuf = NULL;
|
|
}
|
|
else
|
|
{
|
|
// More than one MPC_PH. Allocate a buffer in which all of
|
|
// the data referenced by the MPC_PHs will be concatenated.
|
|
pDataBuf = alloc_storage( pDEVBLK, iDataLen ); // Allocate buffer
|
|
if (!pDataBuf) // if the allocate was not successful...
|
|
return -1;
|
|
|
|
// Copy and concatenate the data referenced by the MPC_PHs.
|
|
pData = pDataBuf;
|
|
for( iForPH = 1; iForPH <= uNumPH; iForPH++ )
|
|
{
|
|
FETCH_F3( uLenData, pMPC_PH->lendata );
|
|
FETCH_FW( uOffData, pMPC_PH->offdata );
|
|
pData1 = (BYTE*)pMPC_TH + uOffData;
|
|
|
|
memcpy( pData, pData1, uLenData );
|
|
pData += uLenData;
|
|
|
|
pMPC_PH = (MPC_PH*)((BYTE*)pMPC_PH + SIZE_PH);
|
|
}
|
|
|
|
// Point to the copied and concatenated data.
|
|
pData = pDataBuf;
|
|
}
|
|
|
|
// pData points to and iDataLen contains the length of a contiguous
|
|
// lump of storage that contains the data in the message. The data
|
|
// consists of one or more IP packets.
|
|
while( iDataLen > 0 )
|
|
{
|
|
pIP4FRM = (PIP4FRM)pData;
|
|
pIP6FRM = (PIP6FRM)pData;
|
|
|
|
// Check the IP packet version. The first 4-bits of the first
|
|
// byte of the IP header contains the version number.
|
|
iPktVer = ( ( pData[0] & 0xF0 ) >> 4 );
|
|
if (iPktVer == 4)
|
|
{
|
|
strcpy( cPktVer, " IPv4" );
|
|
}
|
|
else if (iPktVer == 6)
|
|
{
|
|
strcpy( cPktVer, " IPv6" );
|
|
}
|
|
else
|
|
{
|
|
// Err... not IPv4 or IPv6!
|
|
// HHC03933 "%1d:%04X PTP: Accept data for device '%s' contains IP packet with unknown IP version, data dropped"
|
|
WRMSG(HHC03933, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szTUNIfName );
|
|
iTraceLen = iDataLen;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iDataLen - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, pData, iTraceLen, FROM_GUEST, 'I', "data", 0 );
|
|
rv = -2;
|
|
break;
|
|
}
|
|
|
|
// Check that there is a whole IP packet, and that
|
|
// the IP packet is no larger than the TUN interface MTU.
|
|
if (iPktVer == 4)
|
|
{
|
|
if (iDataLen >= (int)sizeof(IP4FRM)) // Size of a minimal IPv4 header
|
|
{
|
|
// Calculate the IPv4 packet length.
|
|
FETCH_HW( uPayLen, pIP4FRM->hwTotalLength );
|
|
iPktLen = uPayLen;
|
|
}
|
|
else
|
|
{
|
|
iPktLen = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (iDataLen >= (int)sizeof(IP6FRM)) // Size of an IPv6 header
|
|
{
|
|
// Calculate the IPv6 packet length.
|
|
FETCH_HW( uPayLen, pIP6FRM->bPayloadLength );
|
|
iPktLen = sizeof(IP6FRM) + uPayLen;
|
|
}
|
|
else
|
|
{
|
|
iPktLen = -1;
|
|
}
|
|
}
|
|
if (iPktLen > iDataLen || iPktLen == -1)
|
|
{
|
|
// HHC03934 "%1d:%04X PTP: Accept data for device '%s' contains incomplete IP packet, data dropped"
|
|
WRMSG(HHC03934, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szTUNIfName );
|
|
iTraceLen = iDataLen;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iDataLen - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, pData, iTraceLen, FROM_GUEST, 'I', "data", 0 );
|
|
rv = -2;
|
|
break;
|
|
}
|
|
if (iPktLen > pPTPBLK->iMTU)
|
|
{
|
|
// HHC03935 "%1d:%04X PTP: Accept data for device '%s' contains IP packet larger than MTU, data dropped"
|
|
WRMSG(HHC03935, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szTUNIfName );
|
|
iTraceLen = iDataLen;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iDataLen - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, pData, iTraceLen, FROM_GUEST, 'I', "data", 0 );
|
|
rv = -2;
|
|
break;
|
|
}
|
|
|
|
// Check whether the TUN interface is ready for the IP packet.
|
|
fWantPkt = TRUE;
|
|
if (iPktVer == 4)
|
|
{
|
|
if (!pPTPBLK->fActive4)
|
|
{
|
|
fWantPkt = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!pPTPBLK->fActive6)
|
|
{
|
|
fWantPkt = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (fWantPkt)
|
|
{
|
|
// Trace the IP packet before sending to TUN interface
|
|
if (pPTPBLK->uDebugMask & DBGPTPPACKET)
|
|
{
|
|
// HHC00910 "%1d:%04X %s: Send%s packet of size %d bytes to device %s"
|
|
WRMSG(HHC00910, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
cPktVer, iPktLen, pPTPBLK->szTUNIfName );
|
|
net_data_trace( pDEVBLK, pData, iPktLen, FROM_GUEST, 'D', "packet", 0 );
|
|
}
|
|
|
|
// Write the IP packet to the TUN interface
|
|
rv = TUNTAP_Write( pPTPBLK->fd, pData, iPktLen );
|
|
if (rv < 0)
|
|
{
|
|
// HHC00911 "%1d:%04X %s: error writing to device %s: %d %s"
|
|
WRMSG(HHC00911, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName, errno, strerror( errno ) );
|
|
rv = -3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
rv = 0;
|
|
|
|
// Point to the next IP packet, if there is one.
|
|
pData += iPktLen;
|
|
iDataLen -= iPktLen;
|
|
|
|
} /* while( iDataLen > 0 ) */
|
|
|
|
// Free the data buffer, if one was used.
|
|
if (pDataBuf)
|
|
free( pDataBuf );
|
|
|
|
return rv;
|
|
} /* End function write_rrh_8108() */
|
|
|
|
// -------------------------------------------------------------------
|
|
// ptp_halt_or_clear
|
|
// -------------------------------------------------------------------
|
|
// The channel is processing a Halt Subchannel or Clear Subchannel
|
|
// instruction and is notifying us of that fact so we can stop our
|
|
// ptp_read CCW processing loop.
|
|
|
|
static void ptp_halt_or_clear( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
const char* hoc;
|
|
const char* type;
|
|
char text[256];
|
|
|
|
if (pPTPBLK->uDebugMask & DBGPTPCCW)
|
|
{
|
|
hoc = str_HOC( pDEVBLK->hoc );
|
|
if (pPTPATH->bDLCtype == DLCTYPE_READ) // For the y-side's Read path?
|
|
type = "read";
|
|
else
|
|
type = "write";
|
|
snprintf( text, sizeof(text), "%s for %s device", hoc, type );
|
|
WRMSG( HHC03991, "D", SSID_TO_LCSS( pDEVBLK->ssid ), pDEVBLK->devnum, pDEVBLK->typname, text );
|
|
}
|
|
|
|
if (pPTPATH->bDLCtype == DLCTYPE_READ) // For the y-side's Read path?
|
|
{
|
|
obtain_lock( &pPTPBLK->ReadEventLock );
|
|
{
|
|
if (pPTPBLK->fReadWaiting)
|
|
{
|
|
pPTPBLK->fHaltOrClear = 1;
|
|
signal_condition( &pPTPBLK->ReadEvent );
|
|
}
|
|
}
|
|
release_lock( &pPTPBLK->ReadEventLock );
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ptp_read() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Input:
|
|
// pDEVBLK A pointer to the CTC adapter device block
|
|
// uCount The I/O buffer length from the read CCW
|
|
// pIOBuf The I/O buffer from the read CCW
|
|
// iCCWSeq The sequence number of the CCW in the chain
|
|
// (0 = first, 1 = second, 2 = third, etc).
|
|
// Output:
|
|
// pMore Set to 1 if packet data exceeds CCW count
|
|
// pUnitStat The CSW status (CE+DE or CE+DE+UC or CE+DE+UC+SM)
|
|
// pResidual The CSW residual byte count
|
|
|
|
void ptp_read( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
PTPHDR* pPTPHDR = NULL;
|
|
int rc = 0;
|
|
struct timespec waittime;
|
|
struct timeval now;
|
|
BYTE haltorclear = FALSE;
|
|
BYTE closeinprogress = FALSE;
|
|
|
|
if (pPTPATH->bDLCtype == DLCTYPE_READ) // Read from the y-side's Read path?
|
|
{
|
|
// The read is from the y-side's Read path.
|
|
for (;;)
|
|
{
|
|
// Return the data from a chain buffer to the guest OS.
|
|
// There will be chain buffers on the Read path during
|
|
// handshaking, and just after the IPv6 connection has
|
|
// become active.
|
|
|
|
// Remove first buffer from chain.
|
|
pPTPHDR = remove_buffer_from_chain( pPTPATH );
|
|
if (pPTPHDR)
|
|
{
|
|
// Return the data to the guest OS.
|
|
read_chain_buffer( pDEVBLK, uCount, iCCWSeq, pIOBuf,
|
|
pMore, pUnitStat, pResidual, pPTPHDR );
|
|
|
|
// Free the buffer.
|
|
free( pPTPHDR );
|
|
break;
|
|
}
|
|
|
|
// Return the data from the read buffer to the guest OS.
|
|
// There is a read buffer on the Read path, and the buffer
|
|
// will contain data after the IPv4 and/or IPv6 connection
|
|
// has become active.
|
|
|
|
// Obtain the read buffer lock.
|
|
obtain_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
pPTPHDR = pPTPBLK->pReadBuffer;
|
|
if (pPTPHDR && pPTPHDR->iDataLen > LEN_OF_PAGE_ONE)
|
|
{
|
|
// Return the data to the guest OS.
|
|
read_read_buffer( pDEVBLK, uCount, iCCWSeq, pIOBuf,
|
|
pMore, pUnitStat, pResidual, pPTPHDR );
|
|
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
break;
|
|
}
|
|
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
// There is no data waiting to be read.
|
|
// Calculate when to end the wait.
|
|
gettimeofday( &now, NULL );
|
|
|
|
waittime.tv_sec = now.tv_sec + PTP_READ_TIMEOUT_SECS;
|
|
waittime.tv_nsec = now.tv_usec * 1000;
|
|
|
|
// Obtain the event lock
|
|
obtain_lock( &pPTPBLK->ReadEventLock );
|
|
|
|
// Use a calculated wait
|
|
pPTPBLK->fReadWaiting = 1;
|
|
rc = timed_wait_condition( &pPTPBLK->ReadEvent,
|
|
&pPTPBLK->ReadEventLock,
|
|
&waittime );
|
|
pPTPBLK->fReadWaiting = 0;
|
|
|
|
// check for halt condition
|
|
if (pPTPBLK->fHaltOrClear)
|
|
{
|
|
haltorclear = TRUE;
|
|
pPTPBLK->fHaltOrClear = 0;
|
|
}
|
|
|
|
// check for shutting down condition
|
|
if (pPTPBLK->fCloseInProgress)
|
|
{
|
|
closeinprogress = TRUE;
|
|
}
|
|
|
|
// Release the event lock
|
|
release_lock( &pPTPBLK->ReadEventLock );
|
|
|
|
// check for halt or shutting down condition
|
|
if (haltorclear || closeinprogress)
|
|
{
|
|
if (pDEVBLK->ccwtrace || pPTPBLK->uDebugMask & DBGPTPCCW)
|
|
{
|
|
// HHC00904 "%1d:%04X %s: halt or clear recognized"
|
|
WRMSG(HHC00904, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname );
|
|
}
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
*pResidual = uCount;
|
|
break;
|
|
}
|
|
} /* for (;;) */
|
|
}
|
|
else
|
|
{
|
|
// The read is from the y-side's Write path. There should only
|
|
// ever be reads from the y-side's Write path while the XID2
|
|
// exchange is in progress during handshaking.
|
|
|
|
// Remove first buffer from chain.
|
|
pPTPHDR = remove_buffer_from_chain( pPTPATH );
|
|
if (pPTPHDR)
|
|
{
|
|
// There is a buffer on the chain waiting to be read.
|
|
read_chain_buffer( pDEVBLK, uCount, iCCWSeq, pIOBuf,
|
|
pMore, pUnitStat, pResidual, pPTPHDR );
|
|
|
|
// Free the buffer.
|
|
free( pPTPHDR );
|
|
}
|
|
else
|
|
{
|
|
// There is no buffer on the chain waiting to be read. This
|
|
// should not happen! Read a load of nulls.
|
|
memset( pIOBuf, 0, (int)uCount );
|
|
*pMore = 0;
|
|
*pResidual = 0;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
}
|
|
} /* if (pPTPATH->bDLCtype == DLCTYPE_READ ) */
|
|
|
|
return;
|
|
} /* End function ptp_read() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* read_read_buffer() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note: The caller must hold the PTPBLK->ReadBufferLock.
|
|
|
|
ENABLE_VS_BUG_ID_363375_BYPASS
|
|
|
|
void read_read_buffer( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual, PTPHDR* pPTPHDR )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data; // PTPATH
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK; // PTPBLK
|
|
MPC_TH* pMPC_TH; // MPC_TH follows the PTPHDR
|
|
MPC_RRH* pMPC_RRH; // MPC_RRH follows the MPC_TH
|
|
MPC_PH* pMPC_PH; // MPC_PH follows the MPC_RRH
|
|
int iDataLen;
|
|
int iIOLen;
|
|
int iLength1;
|
|
int iLength2;
|
|
U32 uTotalLen;
|
|
int iTraceLen;
|
|
|
|
UNREFERENCED( iCCWSeq );
|
|
|
|
|
|
// Point to the data and get its length.
|
|
pMPC_TH = (MPC_TH*)((BYTE*)pPTPHDR + SIZE_HDR);
|
|
pMPC_RRH = (MPC_RRH*)((BYTE*)pMPC_TH + SIZE_TH);
|
|
pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + SIZE_RRH);
|
|
iDataLen = pPTPHDR->iDataLen - LEN_OF_PAGE_ONE;
|
|
|
|
// Set the transmission header sequence number.
|
|
STORE_FW( pMPC_TH->seqnum, ++pPTPATH->uSeqNum );
|
|
|
|
// Set the destination Token.
|
|
pMPC_RRH->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRH->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Check whether all of the data that is currently in page two and
|
|
// onwards will fit into page one.
|
|
if (iDataLen <= (LEN_OF_PAGE_ONE - (int)(SIZE_TH + SIZE_RRH + SIZE_PH)))
|
|
{
|
|
|
|
// All of the data that is currently in page two and onwards
|
|
// will fit into page one. Copy the headers and the data so
|
|
// that the headers and the data are contiguous in the guests
|
|
// read buffer, i.e. the layout is different to that set-up by
|
|
// ptp_read_thread().
|
|
|
|
// Set the residual length and unit status.
|
|
if (uCount >= (U32)(SIZE_TH + SIZE_RRH + SIZE_PH + iDataLen))
|
|
{
|
|
iLength1 = (int)(SIZE_TH + SIZE_RRH + SIZE_PH);
|
|
iLength2 = iDataLen;
|
|
*pMore = 0;
|
|
*pResidual = uCount - (U32)(iLength1 + iLength2);
|
|
}
|
|
else
|
|
{
|
|
if (uCount >= (U32)(SIZE_TH + SIZE_RRH + SIZE_PH))
|
|
{
|
|
iLength1 = (int)(SIZE_TH + SIZE_RRH + SIZE_PH);
|
|
iLength2 = (int)uCount - iLength1;
|
|
}
|
|
else
|
|
{
|
|
iLength1 = (int)uCount;
|
|
iLength2 = 0;
|
|
}
|
|
*pMore = 1;
|
|
*pResidual = 0;
|
|
}
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
// Set length field in MPC_TH
|
|
STORE_FW( pMPC_TH->length, (U32)(iLength1 + iLength2) );
|
|
|
|
// Set length fields in MPC_RRH
|
|
STORE_HW( pMPC_RRH->lenfida, (U16)iLength2 );
|
|
STORE_F3( pMPC_RRH->lenalda, (U32)iLength2 );
|
|
|
|
// Prepare MPC_PH
|
|
pMPC_PH->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PH->lendata, (U32)iLength2 );
|
|
STORE_FW( pMPC_PH->offdata, (U32)(SIZE_TH + SIZE_RRH + SIZE_PH) );
|
|
|
|
// Copy the data to be read to the IO buffer.
|
|
memcpy( pIOBuf, pMPC_TH, iLength1 );
|
|
memcpy( pIOBuf + iLength1, (BYTE*)pMPC_TH + LEN_OF_PAGE_ONE, iLength2 );
|
|
|
|
// Set the length of the data copied to the IO buffer.
|
|
iIOLen = iLength1 + iLength2;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// All of the data that is currently in page two and onwards
|
|
// will not fit into page one. Copy the headers and the data
|
|
// so that the headers and the data are not contiguous in the
|
|
// guests read buffer, i.e. the layout is the same as that
|
|
// set-up by ptp_read_thread().
|
|
|
|
// Set the residual length and unit status.
|
|
if (uCount >= (U32)(LEN_OF_PAGE_ONE + iDataLen))
|
|
{
|
|
iLength1 = LEN_OF_PAGE_ONE;
|
|
iLength2 = iDataLen;
|
|
*pMore = 0;
|
|
*pResidual = uCount - (U32)(iLength1 + iLength2);
|
|
}
|
|
else
|
|
{
|
|
if (uCount >= (U32)LEN_OF_PAGE_ONE)
|
|
{
|
|
iLength1 = LEN_OF_PAGE_ONE;
|
|
iLength2 = (int)uCount - iLength1;
|
|
}
|
|
else
|
|
{
|
|
iLength1 = (int)uCount;
|
|
iLength2 = 0;
|
|
}
|
|
*pMore = 1;
|
|
*pResidual = 0;
|
|
}
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
// Set length field in MPC_TH
|
|
STORE_FW( pMPC_TH->length, (U32)(SIZE_TH + SIZE_RRH + SIZE_PH) );
|
|
|
|
// Set length fields in MPC_RRH
|
|
STORE_HW( pMPC_RRH->lenfida, 0 );
|
|
STORE_F3( pMPC_RRH->lenalda, (U32)iLength2 );
|
|
|
|
// Prepare MPC_PH
|
|
pMPC_PH->locdata = PH_LOC_2;
|
|
STORE_F3( pMPC_PH->lendata, (U32)iLength2 );
|
|
STORE_FW( pMPC_PH->offdata, (U32)(LEN_OF_PAGE_ONE) );
|
|
|
|
// Copy the data to be read to the IO buffer.
|
|
memcpy( pIOBuf, pMPC_TH, iLength1 + iLength2 );
|
|
|
|
// Set the length of the data copied to the IO buffer.
|
|
iIOLen = iLength1 + iLength2;
|
|
|
|
}
|
|
|
|
// Display TH etc. structured, if debug is active
|
|
if (pPTPBLK->uDebugMask & DBGPTPEXPAND)
|
|
{
|
|
// HHC00982 "%1d:%04X %s: Present data of size %d bytes to guest"
|
|
WRMSG(HHC00982, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, iIOLen );
|
|
mpc_display_ptp_th_etc( pDEVBLK, (MPC_TH*)pIOBuf, TO_GUEST, 64 );
|
|
}
|
|
|
|
// Display up to 256-bytes of the read data, if debug is active.
|
|
if (pPTPBLK->uDebugMask & DBGPTPDATA)
|
|
{
|
|
// HHC00982 "%1d:%04X %s: Present data of size %d bytes to guest"
|
|
WRMSG(HHC00982, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, iIOLen );
|
|
FETCH_FW( uTotalLen, pMPC_TH->length );
|
|
iTraceLen = uTotalLen;
|
|
if (iTraceLen > 256)
|
|
{
|
|
iTraceLen = 256;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, (int)(uTotalLen - iTraceLen) );
|
|
}
|
|
net_data_trace( pDEVBLK, pIOBuf, iTraceLen, TO_GUEST, 'D', "data", 0 );
|
|
}
|
|
|
|
// Reset length field in PTPHDR
|
|
pPTPHDR->iDataLen = LEN_OF_PAGE_ONE;
|
|
|
|
// Clear length field in MPC_TH
|
|
STORE_FW( pMPC_TH->length, 0 );
|
|
|
|
// Clear length fields in MPC_RRH
|
|
STORE_HW( pMPC_RRH->lenfida, 0 );
|
|
STORE_F3( pMPC_RRH->lenalda, 0 );
|
|
|
|
// Clear location, length and displacement fields in MPC_PH
|
|
pMPC_PH->locdata = 0;
|
|
STORE_F3( pMPC_PH->lendata, 0 );
|
|
STORE_FW( pMPC_PH->offdata, 0 );
|
|
|
|
return;
|
|
} /* End function read_read_buffer() */
|
|
|
|
DISABLE_VS_BUG_ID_363375_BYPASS
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* read_chain_buffer() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void read_chain_buffer( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual, PTPHDR* pPTPHDR )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data; // PTPATH
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK; // PTPBLK
|
|
MPC_TH* pMPC_TH; // MPC_TH follows the PTPHDR
|
|
int iDataLen;
|
|
int iTraceLen;
|
|
int rc;
|
|
U32 uFirst4;
|
|
|
|
|
|
// Point to the data and get its length.
|
|
pMPC_TH = (MPC_TH*)((BYTE*)pPTPHDR + SIZE_HDR);
|
|
iDataLen = pPTPHDR->iDataLen;
|
|
|
|
// Get the first 4-bytes of the data.
|
|
FETCH_FW( uFirst4, pMPC_TH->first4 );
|
|
|
|
// Set the residual length and unit status.
|
|
if (uCount >= (U32)iDataLen)
|
|
{
|
|
*pMore = 0;
|
|
*pResidual = uCount - (U32)iDataLen;
|
|
}
|
|
else
|
|
{
|
|
iDataLen = uCount;
|
|
*pMore = 1;
|
|
*pResidual = 0;
|
|
}
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
// Set the transmission header sequence number, if necessary.
|
|
if (uFirst4 == MPC_TH_FIRST4)
|
|
{
|
|
STORE_FW( pMPC_TH->seqnum, ++pPTPATH->uSeqNum );
|
|
}
|
|
|
|
// Copy the data to be read.
|
|
memcpy( pIOBuf, pMPC_TH, iDataLen );
|
|
|
|
// Display TH etc. structured, if debug is active
|
|
if (uFirst4 == MPC_TH_FIRST4 && (pPTPBLK->uDebugMask & DBGPTPEXPAND))
|
|
{
|
|
// HHC00982 "%1d:%04X %s: Present data of size %d bytes to guest"
|
|
WRMSG(HHC00982, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, iDataLen );
|
|
mpc_display_ptp_th_etc( pDEVBLK, pMPC_TH, TO_GUEST, 64 );
|
|
}
|
|
|
|
// Display up to 256-bytes of the read data, if debug is active.
|
|
if (pPTPBLK->uDebugMask & DBGPTPDATA)
|
|
{
|
|
// HHC00982 "%1d:%04X %s: Present data of size %d bytes to guest"
|
|
WRMSG(HHC00982, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, iDataLen );
|
|
iTraceLen = iDataLen;
|
|
if (iTraceLen > 256)
|
|
{
|
|
iTraceLen = 256;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iDataLen - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, pIOBuf, iTraceLen, TO_GUEST, 'D', "data", 0 );
|
|
}
|
|
|
|
// When we are handshaking the sixth CCW in the chain marks the
|
|
// end of an exchange.
|
|
if (pPTPATH->fHandshaking && iCCWSeq == 5)
|
|
{
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_ONE) // Handshake one in progress?
|
|
{
|
|
// The end of the first exchange. The y-side VTAM will
|
|
// now wait (for up to 90 seconds) for an Attention
|
|
// interrupt, which indicates to the y-side that the
|
|
// x-side has initiated the second exchange.
|
|
// Raise an attention interrupt in one second.
|
|
pPTPATH->bAttnCode = 0x17;
|
|
rc = raise_unsol_int( pDEVBLK, CSW_ATTN, 1000 );
|
|
if (rc)
|
|
{
|
|
// Any bad news has already been reported.
|
|
// Hmm... the Attention interrupt to the y-side will not be
|
|
// raised. The y-side's VTAM will timeout in 90 seconds.
|
|
}
|
|
pPTPATH->fHandshakeFin |= HANDSHAKE_ONE; // Handshake one finished
|
|
}
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_TWO) // Handshake two in progress?
|
|
{
|
|
pPTPATH->fHandshakeFin |= HANDSHAKE_TWO; // Handshake two finished
|
|
}
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_THREE) // Handshake three in progress?
|
|
{
|
|
pPTPATH->fHandshakeFin |= HANDSHAKE_THREE; // Handshake three finished
|
|
}
|
|
// If all three exchanges have finished, handshaking is complete.
|
|
if (pPTPATH->fHandshakeFin == HANDSHAKE_ALL) // All handshakes finished?
|
|
{
|
|
pPTPATH->fHandshaking = FALSE;
|
|
pPTPATH->fHandshakeCur = 0;
|
|
pPTPATH->fHandshakeSta = 0;
|
|
pPTPATH->fHandshakeFin = 0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
} /* End function read_chain_buffer() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ptp_read_thread() */
|
|
/* ------------------------------------------------------------------ */
|
|
// The ptp_read_thread() reads data from the TUN interface, stores
|
|
// the data in the path read buffer, from where the data is read by
|
|
// the read path of the MPCPTP/MPCPTP6 connection.
|
|
//
|
|
// The size of the read buffer is determined by the maximum read
|
|
// length reported by the y-side during handshaking. The y-side
|
|
// calculates its maximum read length from the MAXBFRU value
|
|
// specified in the TRLE definition. A MAXBFRU value from 1 to 16 can
|
|
// be specified. If MAXBFRU is not specified, a default value of 5 is
|
|
// used. The MAXBFRU value specifies the number of 4K buffer pages
|
|
// used to receive data. The resulting buffer size (and maximum read
|
|
// length) is number_of_pages multiplied by 4096, minus 4 (the
|
|
// 4-bytes are used for an eye-catcher of 'WrHP' at the start of the
|
|
// first page), i.e. (MAXBFRU*4096)-4 .
|
|
//
|
|
// Note: VTAM automatically substitutes a value of 16 for any coded
|
|
// MAXBFRU value higher than 16 without issuing a warning message.
|
|
// Empirical evidence also suggests that VTAM substitutes a value of
|
|
// 5 (the default value) for any coded MAXBFRU value lower than 5
|
|
// without issuing a warning message. I don't think this is a bug, I
|
|
// think it is a feature. MPCPTP/MPCPTP6 connections are claimed to
|
|
// be high-performance connections, so perhaps it was decided that
|
|
// choking the connection with a small buffer size was a daft idea.
|
|
//
|
|
// The MAXBFRU value also determines the maximum MTU that will be
|
|
// used on the MPCPTP/MPCPTP6 connection. The resulting maximum MTU
|
|
// is number_of_pages minus 1, multiplied by 4096, minus 2048.
|
|
// i.e. ((MAXBFRU-1)*4096)-2048
|
|
// Alternatively, starting with the maximum read length, the
|
|
// resulting maximum MTU is maximum_read_length minus 4092, minus
|
|
// 2048.
|
|
// i.e. (Maximum_read_length-4092)-2048
|
|
// The maximum read length and maximum MTU (in bytes) for various
|
|
// MAXBFRU values are shown below.
|
|
//
|
|
// MAXBFRU value Maximum read length Maximum MTU
|
|
// 5 20476 (0x4FFC) 14336 (0x3800)
|
|
// 8 32764 (0x7FFC) 26624 (0x6800)
|
|
// 12 49148 (0xBFFC) 43008 (0xA800)
|
|
// 16 65532 (0xFFFC) 59392 (0xE800)
|
|
//
|
|
// Suppose the x-side reports to the y-side that the x-side's maximum
|
|
// read length is 20476 (0x4FFC) bytes, the y-side will calculate
|
|
// that the actual MTU is 14336 (0x3800) bytes. If the y-side has a
|
|
// route statement that specifies an MTU of, for example, 24576
|
|
// (0x6000) bytes, the MTU specified on the route statement is
|
|
// ignored and the calculated actual MTU is used.
|
|
// Depending on the values specified for MAXBFRU and for routes, the
|
|
// MTU in use from the x-side to the y-side could be different to the
|
|
// MTU in use from the y-side to the x-side. For a real MPCPTP/
|
|
// MPCPTP6 connection this is probably a good thing, the maximum
|
|
// capacity in each direction is automatically used, and the system
|
|
// administrator at one end of the connection does not need to know
|
|
// the values in use at the other end of the connection. However, for
|
|
// this emulated MPCPTP/MPCPTP6 connection this could be a very bad
|
|
// thing. Because we are not processing the packets, we are simply
|
|
// forwarding them, we may be forwarding them from something using a
|
|
// larger MTU to something using a smaller MTU.
|
|
|
|
void* ptp_read_thread( void* arg )
|
|
{
|
|
PTPBLK* pPTPBLK = (PTPBLK*) arg;
|
|
PTPATH* pPTPATH = pPTPBLK->pPTPATHRead; // PTPATH Read
|
|
DEVBLK* pDEVBLK = pPTPATH->pDEVBLK; // DEVBLK
|
|
BYTE* pTunBuf; // TUN read buffer address
|
|
PIP4FRM pIP4FRM; // IPv4 packet in TUN read buffer
|
|
PIP6FRM pIP6FRM; // IPv6 packet in TUN read buffer
|
|
int iTunLen; // TUN read length
|
|
int iLength; // Length of data in TUN read buffer
|
|
PTPHDR* pPTPHDR; // PTPHDR of the path read buffer
|
|
MPC_TH* pMPC_TH; // MPC_TH follows the PTPHDR
|
|
// MPC_RRH* pMPC_RRH; // MPC_RRH follows the MPC_TH
|
|
// MPC_PH* pMPC_PH; // MPC_PH follows the MPC_RRH
|
|
BYTE* pData; //
|
|
U16 uPayLen;
|
|
int iPktVer;
|
|
char cPktVer[8];
|
|
int iPktLen;
|
|
int iTraceLen;
|
|
|
|
|
|
// Allocate the TUN read buffer.
|
|
iTunLen = pPTPBLK->iMTU; // Read length and buffer size
|
|
pTunBuf = alloc_storage( pDEVBLK, iTunLen ); // equal to the MTU size
|
|
if (!pTunBuf) // if the allocate failed...
|
|
{
|
|
// Close the TUN interface.
|
|
VERIFY( pPTPBLK->fd == -1 || TUNTAP_Close( pPTPBLK->fd, pPTPBLK->internal ) == 0 );
|
|
pPTPBLK->fd = -1;
|
|
// Nothing else to be done.
|
|
return NULL;
|
|
}
|
|
pIP6FRM = (PIP6FRM)pTunBuf;
|
|
pIP4FRM = (PIP4FRM)pTunBuf;
|
|
|
|
// ZZ FIXME: Try to avoid race condition at startup with hercifc
|
|
SLEEP(10);
|
|
|
|
pPTPBLK->pid = getpid();
|
|
|
|
// Keep going until we have to stop.
|
|
while( pPTPBLK->fd != -1 && !pPTPBLK->fCloseInProgress )
|
|
{
|
|
// Read an IP packet from the TUN interface.
|
|
iLength = read_tuntap( pPTPBLK->fd, pTunBuf, iTunLen, DEF_NET_READ_TIMEOUT_SECS );
|
|
|
|
// Check for error conditions...
|
|
if (iLength < 0)
|
|
{
|
|
if (!pPTPBLK->fCloseInProgress)
|
|
{
|
|
// HHC00912 "%1d:%04X %s: error reading from device %s: %d %s"
|
|
WRMSG(HHC00912, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName, errno, strerror( errno ) );
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (iLength == 0) // (probably EINTR; ignore)
|
|
continue;
|
|
|
|
// Check the IP packet version. The first 4-bits of the first
|
|
// byte of the IP header contains the version number.
|
|
iPktVer = ( ( pTunBuf[0] & 0xF0 ) >> 4 );
|
|
if (iPktVer == 4)
|
|
{
|
|
strcpy( cPktVer, " IPv4" );
|
|
}
|
|
else if (iPktVer == 6)
|
|
{
|
|
strcpy( cPktVer, " IPv6" );
|
|
}
|
|
else
|
|
{
|
|
// Err... not IPv4 or IPv6!
|
|
// HHC03921 "%1d:%04X PTP: Packet of size %d bytes from device '%s' has an unknown IP version, packet dropped"
|
|
WRMSG(HHC03921, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
iLength, pPTPBLK->szTUNIfName );
|
|
iTraceLen = iLength;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iLength - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, (BYTE*)pTunBuf, iTraceLen, TO_GUEST, 'I', "data", 0 );
|
|
continue;
|
|
}
|
|
|
|
// Check that a whole IP packet has been read. If an incomplete
|
|
// packet has been read it is dropped.
|
|
if (iPktVer == 4)
|
|
{
|
|
if (iLength >= (int)sizeof(IP4FRM)) // Size of a minimal IPv4 header
|
|
{
|
|
// Calculate the IPv4 packet length.
|
|
FETCH_HW( uPayLen, pIP4FRM->hwTotalLength );
|
|
iPktLen = uPayLen;
|
|
}
|
|
else
|
|
{
|
|
iPktLen = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (iLength >= (int)sizeof(IP6FRM)) // Size of an IPv6 header
|
|
{
|
|
// Calculate the IPv6 packet length.
|
|
FETCH_HW( uPayLen, pIP6FRM->bPayloadLength );
|
|
iPktLen = sizeof(IP6FRM) + uPayLen;
|
|
}
|
|
else
|
|
{
|
|
iPktLen = -1;
|
|
}
|
|
}
|
|
if (iPktLen > iLength)
|
|
{
|
|
// HHC03922 "%1d:%04X PTP: Packet of size %d bytes from device '%s' is not equal to the packet length of %d bytes, packet dropped"
|
|
WRMSG(HHC03922, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
iLength, pPTPBLK->szTUNIfName,
|
|
iPktLen );
|
|
iTraceLen = iLength;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iLength - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, (BYTE*)pTunBuf, iTraceLen, TO_GUEST, 'I', "data", 0 );
|
|
continue;
|
|
}
|
|
if (iPktLen < iLength)
|
|
{
|
|
iLength = iPktLen; // Silently truncate to the length of the packet
|
|
}
|
|
|
|
// Enqueue IP packet.
|
|
while( pPTPBLK->fd != -1 && !pPTPBLK->fCloseInProgress )
|
|
{
|
|
|
|
// Obtain the read buffer lock.
|
|
obtain_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
// Check whether the interface is ready for data from the TUN interface.
|
|
if (iPktVer == 4)
|
|
{
|
|
if (!pPTPBLK->fActive4)
|
|
{
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!pPTPBLK->fActive6)
|
|
{
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check that there is a read buffer.
|
|
pPTPHDR = pPTPBLK->pReadBuffer;
|
|
if (!pPTPHDR)
|
|
{
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
break;
|
|
}
|
|
|
|
// Check whether the IP packet is larger than y-side's actual MTU.
|
|
// If it is then it is dropped.
|
|
if (iLength > pPTPBLK->yActMTU)
|
|
{
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
// HHC03923 "%1d:%04X PTP: Packet of size %d bytes from device '%s' is larger than the guests actual MTU of %d bytes, packet dropped"
|
|
WRMSG(HHC03923, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
iLength, pPTPBLK->szTUNIfName,
|
|
(int)pPTPBLK->yActMTU );
|
|
iTraceLen = iLength;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iLength - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, (BYTE*)pTunBuf, iTraceLen, TO_GUEST, 'I', "data", 0 );
|
|
break;
|
|
}
|
|
|
|
// Check whether the IP packet will ever fit into the read buffer.
|
|
// If it will not then it is dropped.
|
|
if (iLength > (pPTPHDR->iAreaLen - LEN_OF_PAGE_ONE))
|
|
{
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
// HHC03924 "%1d:%04X PTP: Packet of size %d bytes from device '%s' is too large for read buffer area of %d bytes, packet dropped"
|
|
WRMSG(HHC03924, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
iLength, pPTPBLK->szTUNIfName,
|
|
pPTPHDR->iAreaLen - LEN_OF_PAGE_ONE );
|
|
iTraceLen = iLength;
|
|
if (iTraceLen > 128)
|
|
{
|
|
iTraceLen = 128;
|
|
// HHC00980 "%1d:%04X PTP: Data of size %d bytes displayed, data of size %d bytes not displayed"
|
|
WRMSG(HHC00980, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
iTraceLen, iLength - iTraceLen );
|
|
}
|
|
net_data_trace( pDEVBLK, (BYTE*)pTunBuf, iTraceLen, TO_GUEST, 'I', "data", 0 );
|
|
break;
|
|
}
|
|
|
|
// Check whether the IP packet will fit into the read buffer.
|
|
if (iLength > (pPTPHDR->iAreaLen - pPTPHDR->iDataLen))
|
|
{
|
|
// The IP packet will not fit into the read buffer at the
|
|
// moment, presumably there are IP packets waiting to be read.
|
|
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
// Don't use schedyield() here; use an actual non-dispatchable
|
|
// delay instead so as to allow another [possibly lower priority]
|
|
// thread to 'read' (remove) the packet(s) from the read buffer.
|
|
USLEEP( PTP_DELAY_USECS ); // (wait a bit before retrying...)
|
|
|
|
continue;
|
|
|
|
}
|
|
else
|
|
{
|
|
// The IP packet will fit into the read buffer.
|
|
|
|
// Display the IP packet just read, if the device group is being debugged.
|
|
if (pPTPBLK->uDebugMask & DBGPTPPACKET)
|
|
{
|
|
// HHC00913 "%1d:%04X %s: Receive%s packet of size %d bytes from device %s"
|
|
WRMSG(HHC00913, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
cPktVer, iLength, pPTPBLK->szTUNIfName );
|
|
net_data_trace( pDEVBLK, (BYTE*)pTunBuf, iLength, TO_GUEST, 'D', "packet", 0 );
|
|
}
|
|
|
|
// Fix-up various pointers
|
|
pMPC_TH = (MPC_TH*)((BYTE*)pPTPHDR + SIZE_HDR);
|
|
pData = (BYTE*)pMPC_TH + pPTPHDR->iDataLen;
|
|
|
|
// Copy the IP packet from the TUN/TAP read buffer
|
|
memcpy( pData, pTunBuf, iLength );
|
|
|
|
// Increment length field in PTPHDR
|
|
pPTPHDR->iDataLen += iLength;
|
|
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
//
|
|
obtain_lock( &pPTPBLK->ReadEventLock );
|
|
signal_condition( &pPTPBLK->ReadEvent );
|
|
release_lock( &pPTPBLK->ReadEventLock );
|
|
|
|
break;
|
|
|
|
} /* if (iLength > (pPTPHDR->iAreaLen - pPTPHDR->iDataLen)) */
|
|
|
|
} /* while( pPTPBLK->fd != -1 && !pPTPBLK->fCloseInProgress ) */
|
|
|
|
} /* while( pPTPBLK->fd != -1 && !pPTPBLK->fCloseInProgress ) */
|
|
|
|
// We must do the close since we were the one doing the i/o...
|
|
VERIFY( pPTPBLK->fd == -1 || TUNTAP_Close( pPTPBLK->fd, pPTPBLK->internal ) == 0 );
|
|
pPTPBLK->fd = -1;
|
|
|
|
// Release the TUN read buffer.
|
|
free( pTunBuf );
|
|
pTunBuf = NULL;
|
|
iTunLen = 0;
|
|
|
|
return NULL;
|
|
} /* End function ptp_read_thread() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* add_buffer_to_chain_and_signal_event(): Add PTPHDR to end of chn. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void* add_buffer_to_chain_and_signal_event( PTPATH* pPTPATH, PTPHDR* pPTPHDR )
|
|
{
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK; // PTPBLK
|
|
|
|
// Prepare PTPHDR for adding to chain.
|
|
if (!pPTPHDR) // Any PTPHDR been passed?
|
|
return NULL;
|
|
pPTPHDR->pNextPTPHDR = NULL; // Clear the pointer to next PTPHDR
|
|
|
|
// Obtain the path chain lock.
|
|
obtain_lock( &pPTPATH->ChainLock );
|
|
|
|
// Add PTPHDR to end of chain.
|
|
if (pPTPATH->pFirstPTPHDR) // if there are already PTPHDRs
|
|
{
|
|
pPTPATH->pLastPTPHDR->pNextPTPHDR = pPTPHDR; // Add the PTPHDR to
|
|
pPTPATH->pLastPTPHDR = pPTPHDR; // the end of the chain
|
|
pPTPATH->iNumPTPHDR++; // Increment number of PTPHDRs
|
|
}
|
|
else
|
|
{
|
|
pPTPATH->pFirstPTPHDR = pPTPHDR; // Make the PTPHDR
|
|
pPTPATH->pLastPTPHDR = pPTPHDR; // the only PTPHDR
|
|
pPTPATH->iNumPTPHDR = 1; // on the chain
|
|
}
|
|
|
|
// Release the path chain lock.
|
|
release_lock( &pPTPATH->ChainLock );
|
|
|
|
//
|
|
obtain_lock( &pPTPBLK->ReadEventLock );
|
|
signal_condition( &pPTPBLK->ReadEvent );
|
|
release_lock( &pPTPBLK->ReadEventLock );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* add_buffer_to_chain(): Add PTPHDR to end of chain. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void* add_buffer_to_chain( PTPATH* pPTPATH, PTPHDR* pPTPHDR )
|
|
{
|
|
|
|
// Prepare PTPHDR for adding to chain.
|
|
if (!pPTPHDR) // Any PTPHDR been passed?
|
|
return NULL;
|
|
pPTPHDR->pNextPTPHDR = NULL; // Clear the pointer to next PTPHDR
|
|
|
|
// Obtain the path chain lock.
|
|
obtain_lock( &pPTPATH->ChainLock );
|
|
|
|
// Add PTPHDR to end of chain.
|
|
if (pPTPATH->pFirstPTPHDR) // if there are already PTPHDRs
|
|
{
|
|
pPTPATH->pLastPTPHDR->pNextPTPHDR = pPTPHDR; // Add the PTPHDR to
|
|
pPTPATH->pLastPTPHDR = pPTPHDR; // the end of the chain
|
|
pPTPATH->iNumPTPHDR++; // Increment number of PTPHDRs
|
|
}
|
|
else
|
|
{
|
|
pPTPATH->pFirstPTPHDR = pPTPHDR; // Make the PTPHDR
|
|
pPTPATH->pLastPTPHDR = pPTPHDR; // the only PTPHDR
|
|
pPTPATH->iNumPTPHDR = 1; // on the chain
|
|
}
|
|
|
|
// Release the path chain lock.
|
|
release_lock( &pPTPATH->ChainLock );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* remove_buffer_from_chain(): Remove PTPHDR from start of chain. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
PTPHDR* remove_buffer_from_chain( PTPATH* pPTPATH )
|
|
{
|
|
|
|
PTPHDR* pPTPHDR; // PTPHDR
|
|
|
|
// Obtain the path chain lock.
|
|
obtain_lock( &pPTPATH->ChainLock );
|
|
|
|
// Point to first PTPHDR on the chain.
|
|
pPTPHDR = pPTPATH->pFirstPTPHDR; // Pointer to first PTPHDR
|
|
|
|
// Remove the first PTPHDR from the chain, if there is one...
|
|
if (pPTPHDR) // If there is a PTPHDR
|
|
{
|
|
pPTPATH->pFirstPTPHDR = pPTPHDR->pNextPTPHDR; // Make the next the first PTPHDR
|
|
pPTPATH->iNumPTPHDR--; // Decrement number of PTPHDRs
|
|
pPTPHDR->pNextPTPHDR = NULL; // Clear the pointer to next PTPHDR
|
|
if (!pPTPATH->pFirstPTPHDR) // if there are no more PTPHDRs
|
|
{
|
|
// pPTPATH->pFirstPTPHDR = NULL; // Clear
|
|
pPTPATH->pLastPTPHDR = NULL; // the chain
|
|
pPTPATH->iNumPTPHDR = 0; // pointers and count
|
|
}
|
|
}
|
|
|
|
// Release the path chain lock.
|
|
release_lock( &pPTPATH->ChainLock );
|
|
|
|
return pPTPHDR;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* remove_and_free_any_buffers_on_chain(): Remove and free PTPHDRs. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void* remove_and_free_any_buffers_on_chain( PTPATH* pPTPATH )
|
|
{
|
|
|
|
PTPHDR* pPTPHDR; // PTPHDR
|
|
|
|
// Obtain the path chain lock.
|
|
obtain_lock( &pPTPATH->ChainLock );
|
|
|
|
// Remove and free the first PTPHDR on the chain, if there is one...
|
|
while( pPTPATH->pFirstPTPHDR != NULL )
|
|
{
|
|
pPTPHDR = pPTPATH->pFirstPTPHDR; // Pointer to first PTPHDR
|
|
pPTPATH->pFirstPTPHDR = pPTPHDR->pNextPTPHDR; // Make the next the first PTPHDR
|
|
free( pPTPHDR ); // Free the message buffer
|
|
}
|
|
|
|
// Reset the chain pointers.
|
|
pPTPATH->pFirstPTPHDR = NULL; // Clear
|
|
pPTPATH->pLastPTPHDR = NULL; // the chain
|
|
pPTPATH->iNumPTPHDR = 0; // pointers and count
|
|
|
|
// Release the path chain lock.
|
|
release_lock( &pPTPATH->ChainLock );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* alloc_ptp_buffer(): Allocate storage for a PTPHDR and data */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
PTPHDR* alloc_ptp_buffer( DEVBLK* pDEVBLK, int iSize )
|
|
{
|
|
|
|
PTPHDR* pPTPHDR; // PTPHDR
|
|
int iBufLen; // Buffer length
|
|
char etext[40]; // malloc error text
|
|
|
|
|
|
// Allocate the buffer.
|
|
iBufLen = SIZE_HDR + iSize;
|
|
pPTPHDR = malloc( iBufLen ); // Allocate the buffer
|
|
if (!pPTPHDR) // if the allocate was not successful...
|
|
{
|
|
// Report the bad news.
|
|
MSGBUF( etext, "malloc(%d)", iBufLen );
|
|
// HHC00900 "%1d:%04X %s: error in function %s: %s"
|
|
WRMSG(HHC00900, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
etext, strerror(errno) );
|
|
return NULL;
|
|
}
|
|
|
|
// Clear the buffer.
|
|
memset( pPTPHDR, 0, iBufLen );
|
|
pPTPHDR->iAreaLen = iSize;
|
|
|
|
return pPTPHDR;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* alloc_storage(): Allocate storage */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void* alloc_storage( DEVBLK* pDEVBLK, int iSize )
|
|
{
|
|
|
|
void* pStorPtr; // Storage pointer
|
|
int iStorLen; // Storage length
|
|
char etext[40]; // malloc error text
|
|
|
|
|
|
// Allocate the storage.
|
|
iStorLen = iSize;
|
|
pStorPtr = malloc( iStorLen ); // Allocate the storage
|
|
if (!pStorPtr) // if the allocate was not successful...
|
|
{
|
|
// Report the bad news.
|
|
MSGBUF( etext, "malloc(%d)", iStorLen );
|
|
// HHC00900 "%1d:%04X %s: error in function %s: %s"
|
|
WRMSG(HHC00900, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
etext, strerror(errno) );
|
|
return NULL;
|
|
}
|
|
|
|
// Clear the storage.
|
|
memset( pStorPtr, 0, iStorLen );
|
|
|
|
return pStorPtr;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* parse_conf_stmt() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
int parse_conf_stmt( DEVBLK* pDEVBLK, PTPBLK* pPTPBLK,
|
|
int argc, char** argx )
|
|
{
|
|
MAC mac; /* Work area for MAC address */
|
|
struct in_addr addr4; /* Work area for IPv4 addresses */
|
|
#if defined(ENABLE_IPV6)
|
|
struct in6_addr addr6; /* Work area for IPv6 addresses */
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
int iPfxSiz; /* Work area for prefix size */
|
|
// int iMaxBfru;
|
|
int iMTU;
|
|
int iDebugMask;
|
|
char *cphost, *cpprfx;
|
|
size_t ilhost, ilprfx;
|
|
uint32_t mask;
|
|
int iWantFamily;
|
|
int iFirstFamily[2];
|
|
int j;
|
|
int rc;
|
|
#if defined(OPTION_W32_CTCI)
|
|
int iKernBuff;
|
|
int iIOBuff;
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
HRB hrb;
|
|
char *argn[MAX_ARGS];
|
|
char **argv = argn;
|
|
#if !defined(OPTION_W32_CTCI)
|
|
int saw_if = 0; /* -x (or --if) specified */
|
|
#endif
|
|
int saw_conf = 0; /* Other configuration flags present */
|
|
|
|
|
|
// Build a copy of the argv list.
|
|
// getopt() and getopt_long() expect argv[0] to be a program name.
|
|
// We need to shift the arguments and insert a dummy argv[0].
|
|
if (argc > (MAX_ARGS-1))
|
|
argc = (MAX_ARGS-1);
|
|
for( j = 0; j < argc; j++ )
|
|
argn[j+1] = argx[j];
|
|
argc++;
|
|
argn[0] = pDEVBLK->typname;
|
|
|
|
// // Display the copied argv.
|
|
// {
|
|
// char tmp[256];
|
|
// int i;
|
|
// snprintf( (char*)tmp, 256, "Number of arguments: %d", argc );
|
|
// WRMSG(HHC03991, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, tmp );
|
|
// for( i = 0; i < argc; i++ )
|
|
// {
|
|
// snprintf( (char*)tmp, 256, "argv[%d]: %s", i, argv[i] );
|
|
// WRMSG(HHC03991, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, tmp );
|
|
// }
|
|
// }
|
|
|
|
// Housekeeping
|
|
memset( &addr4, 0, sizeof( struct in_addr ));
|
|
memset( &mac, 0, sizeof( MAC ));
|
|
#if defined( ENABLE_IPV6 )
|
|
memset( &addr6, 0, sizeof( struct in6_addr ));
|
|
#endif
|
|
|
|
// Set some initial defaults
|
|
STRLCPY( pPTPBLK->szTUNCharDevName, DEF_NETDEV );
|
|
#if defined( OPTION_W32_CTCI )
|
|
pPTPBLK->iKernBuff = DEF_CAPTURE_BUFFSIZE;
|
|
pPTPBLK->iIOBuff = DEF_PACKET_BUFFSIZE;
|
|
#endif
|
|
#if defined( ENABLE_IPV6 )
|
|
pPTPBLK->iAFamily = AF_UNSPEC;
|
|
#else
|
|
pPTPBLK->iAFamily = AF_INET;
|
|
#endif
|
|
STRLCPY( pPTPBLK->szMaxBfru, "5" );
|
|
pPTPBLK->iMaxBfru = 5;
|
|
STRLCPY( pPTPBLK->szMTU, "1500" );
|
|
pPTPBLK->iMTU = 1500;
|
|
STRLCPY( pPTPBLK->szDrivePfxSiz4, "32" );
|
|
STRLCPY( pPTPBLK->szNetMask, "255.255.255.255" );
|
|
#if defined( ENABLE_IPV6 )
|
|
STRLCPY( pPTPBLK->szDrivePfxSiz6, "128" );
|
|
STRLCPY( pPTPBLK->szDriveLLxSiz6, "64" );
|
|
#endif
|
|
|
|
// Initialize getopt's counter. This is necessary in the case
|
|
// that getopt was used previously for another device.
|
|
OPTRESET();
|
|
optind = 0;
|
|
|
|
// Parse any optional arguments
|
|
while( 1 )
|
|
{
|
|
int c;
|
|
|
|
#if defined(OPTION_W32_CTCI)
|
|
#define PTP_OPTSTRING "n:t:d::46m:k:i:"
|
|
#else /* defined(OPTION_W32_CTCI) */
|
|
#define PTP_OPTSTRING "n:x:t:d::46"
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
|
|
#if defined(HAVE_GETOPT_LONG)
|
|
int iOpt;
|
|
|
|
static struct option options[] =
|
|
{
|
|
{ "dev", required_argument, NULL, 'n' },
|
|
#if !defined(OPTION_W32_CTCI)
|
|
{ "if", required_argument, NULL, 'x' },
|
|
#endif /* !defined(OPTION_W32_CTCI) */
|
|
{ "mtu", required_argument, NULL, 't' },
|
|
{ "debug", optional_argument, NULL, 'd' },
|
|
{ "inet", no_argument, NULL, '4' },
|
|
{ "inet6", no_argument, NULL, '6' },
|
|
#if defined(OPTION_W32_CTCI)
|
|
{ "mac", required_argument, NULL, 'm' },
|
|
{ "kbuff", required_argument, NULL, 'k' },
|
|
{ "ibuff", required_argument, NULL, 'i' },
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
{ NULL, 0, NULL, 0 }
|
|
};
|
|
|
|
c = getopt_long( argc, argv, PTP_OPTSTRING, options, &iOpt );
|
|
#else /* defined(HAVE_GETOPT_LONG) */
|
|
c = getopt( argc, argv, PTP_OPTSTRING );
|
|
#endif /* defined(HAVE_GETOPT_LONG) */
|
|
|
|
if (c == -1 ) // No more options found
|
|
break;
|
|
|
|
switch( c )
|
|
{
|
|
|
|
case 'n': // Network Device
|
|
|
|
#if defined( OPTION_W32_CTCI )
|
|
|
|
// This could be the IP or MAC address of the
|
|
// host ethernet adapter.
|
|
if (inet_aton( optarg, &addr4 ) == 0)
|
|
{
|
|
// Not an IP address, check for valid MAC
|
|
if (ParseMAC( optarg, mac ) != 0)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"adapter address", optarg );
|
|
return -1;
|
|
}
|
|
}
|
|
#endif
|
|
// This is the file name of the special TUN/TAP character device
|
|
if (strlen( optarg ) > sizeof( pPTPBLK->szTUNCharDevName )-1)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG( HHC00916, "E", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, "device name", optarg );
|
|
return -1;
|
|
}
|
|
|
|
STRLCPY( pPTPBLK->szTUNCharDevName, optarg );
|
|
break;
|
|
|
|
#if !defined( OPTION_W32_CTCI )
|
|
|
|
case 'x': // TUN network interface name
|
|
|
|
if (strlen( optarg ) > sizeof( pPTPBLK->szTUNIfName )-1)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG( HHC00916, "E", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, "TUN device name", optarg );
|
|
return -1;
|
|
}
|
|
|
|
STRLCPY( pPTPBLK->szTUNIfName, optarg );
|
|
saw_if = 1;
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 't': // MTU of link (ignored if Windows) (default 1500).
|
|
|
|
// Note: The largest MTU supported by MPCPTP or MPCPTP6
|
|
// devices is 59392, based on the MAXBFRU specified in the
|
|
// TRLE definition. The smallest MTU supported is equal to
|
|
// DEFAULTSIZE, which is 576 for IPv4 and 1280 for IPv6. See
|
|
// the manual 'z/OS Communication Server: IP Configuration
|
|
// Reference'.
|
|
// MAXBFRU value Actual MTU value
|
|
// ------------- ----------------------------------
|
|
// 5 14336 ( ( 4 * 4096 ) - 2048 )
|
|
// 16 59392 ( ( 15 * 4096 ) - 2048 )
|
|
// This side will report a MAXBFRU value of 5 to the y-side,
|
|
// from which the y-side will calculate an actual MTU value
|
|
// of 14336. The MTU value that will be used for packets
|
|
// sent from the y-side to this side will depend on the MTU
|
|
// value specified on the y-side's route statement(s). If the
|
|
// y-side's route statement(s) specify an MTU value greater
|
|
// than the actual MTU value the route statement value is
|
|
// ignored and the actual MTU value is used. If the y-side's
|
|
// route statement(s) specify an MTU value less than or equal
|
|
// to the actual MTU value the route statement MTU value is
|
|
// used. Hopefully the y-side's route statement(s) will match
|
|
// the MTU value specified here!
|
|
|
|
iMTU = atoi( optarg );
|
|
if (iMTU < 576 || iMTU > 14336 ||
|
|
strlen(optarg) > sizeof(pPTPBLK->szMTU)-1)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"MTU size", optarg );
|
|
return -1;
|
|
}
|
|
STRLCPY( pPTPBLK->szMTU, optarg );
|
|
pPTPBLK->iMTU = iMTU;
|
|
saw_conf = 1;
|
|
break;
|
|
|
|
// case ' ': // Maximum buffers to use (default 5).
|
|
//
|
|
// // The number of 4K pages used by VTAM to receive data. The
|
|
// // resulting buffer size is number_of_pages multiplied by
|
|
// // 4096, minus 4 bytes for an eye-catcher of 'WrHP'. VTAM
|
|
// // automatically substitutes a value of 16 for any coded
|
|
// // value higher than 16 without issuing a warning message.
|
|
// // Note: Empirical evidence suggests that VTAM ignores any
|
|
// // coded value lower than 5 and substitutes a value of 5
|
|
// // (the default value) without issuing a warning message. Is
|
|
// // this a bug, or a feature?
|
|
//
|
|
// iMaxBfru = atoi( optarg );
|
|
//
|
|
// if ( strlen(optarg) > sizeof(pPTPBLK->szMaxBfru)-1 )
|
|
// {
|
|
// // HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
// WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
// "MaxBfru number", optarg );
|
|
// return -1;
|
|
// }
|
|
//
|
|
// if (iMaxBfru < 5)
|
|
// {
|
|
// STRLCPY( pPTPBLK->szMaxBfru, "5" );
|
|
// pPTPBLK->iMaxBfru = 5;
|
|
// }
|
|
// else if (iMaxBfru > 16)
|
|
// {
|
|
// STRLCPY( pPTPBLK->szMaxBfru, "16" );
|
|
// pPTPBLK->iMaxBfru = 16;
|
|
// }
|
|
// else
|
|
// {
|
|
// STRLCPY( pPTPBLK->szMaxBfru, optarg );
|
|
// pPTPBLK->iMaxBfru = iMaxBfru;
|
|
// }
|
|
//
|
|
// break;
|
|
|
|
case 'd': // Diagnostics
|
|
|
|
if (optarg)
|
|
{
|
|
iDebugMask = atoi( optarg );
|
|
if (iDebugMask < 1 || iDebugMask > 255)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG( HHC00916, "W", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, "debug mask", optarg );
|
|
iDebugMask = DBGPTPPACKET;
|
|
}
|
|
pPTPBLK->uDebugMask = iDebugMask;
|
|
}
|
|
else
|
|
{
|
|
pPTPBLK->uDebugMask = DBGPTPPACKET;
|
|
}
|
|
break;
|
|
|
|
case '4': // Address family.
|
|
|
|
#if defined( ENABLE_IPV6 )
|
|
pPTPBLK->iAFamily = AF_INET;
|
|
#endif
|
|
break;
|
|
|
|
case '6': // Address family.
|
|
|
|
#if defined( ENABLE_IPV6 )
|
|
pPTPBLK->iAFamily = AF_INET6;
|
|
#endif
|
|
break;
|
|
|
|
#if defined( OPTION_W32_CTCI )
|
|
|
|
case 'm':
|
|
|
|
if (0
|
|
|| strlen(optarg) > sizeof(pPTPBLK->szMACAddress)-1
|
|
|| ParseMAC( optarg, mac ) != 0 // (invalid format)
|
|
|| !(mac[0] & 0x02) // (locally assigned MAC bit not ON)
|
|
|| (mac[0] & 0x01) // (broadcast bit is ON)
|
|
)
|
|
{
|
|
// "%1d:%04X %s: Option %s value %s invalid"
|
|
WRMSG( HHC00916, "E", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, "MAC address", optarg );
|
|
return -1;
|
|
}
|
|
|
|
STRLCPY( pPTPBLK->szMACAddress, optarg );
|
|
break;
|
|
|
|
case 'k': // Kernel Buffer Size (Windows only)
|
|
|
|
iKernBuff = atoi( optarg );
|
|
|
|
if (iKernBuff * 1024 < MIN_CAPTURE_BUFFSIZE ||
|
|
iKernBuff * 1024 > MAX_CAPTURE_BUFFSIZE)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG( HHC00916, "E", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, "kernel buffer size", optarg );
|
|
return -1;
|
|
}
|
|
|
|
pPTPBLK->iKernBuff = iKernBuff * 1024;
|
|
break;
|
|
|
|
case 'i': // I/O Buffer Size (Windows only)
|
|
|
|
iIOBuff = atoi( optarg );
|
|
|
|
if (iIOBuff * 1024 < MIN_PACKET_BUFFSIZE ||
|
|
iIOBuff * 1024 > MAX_PACKET_BUFFSIZE)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG( HHC00916, "E", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, "dll i/o buffer size", optarg );
|
|
return -1;
|
|
}
|
|
|
|
pPTPBLK->iIOBuff = iIOBuff * 1024;
|
|
break;
|
|
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
|
|
default: /* Note: the variable c has a value that
|
|
makes default: equivalent to case '?': */
|
|
|
|
// HHC00918 "%1d:%04X %s: option %s unknown or specified incorrectly"
|
|
WRMSG( HHC00918, "E", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
pDEVBLK->devnum, pDEVBLK->typname, argv[optind-1]);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Shift past any options
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
// Check for correct number of arguments.
|
|
// For *nix, there can be either:-
|
|
// a) Two parameters (a pair of IPv4 or IPv6 addresses), or four
|
|
// parameters (a pair of IPv4 addresses and a pair of IPv6
|
|
// addresses). If the -x option has not been specified, PTP
|
|
// will use a TUN interface whose name is allocated by the
|
|
// kernel (e.g. tun0), that is configured by PTP. If the -x
|
|
// option has been specified, PTP will use a pre-named TUN
|
|
// interface. The TUN interface may have been created before
|
|
// PTP was started, or it may be created by PTP, but in either
|
|
// case the TUN interface is configured by PTP.
|
|
// b) One parameter when the -x option has not been specified.
|
|
// The single parameter specifies the name of a pre-configured
|
|
// TUN interface that PTP will use.
|
|
// c) Zero parameters when the -x option has been specified. The
|
|
// The -x option specified the name of a pre-configured TUN
|
|
// interface that PTP will use..
|
|
// For Windows there can be:-
|
|
// a) Two parameters (a pair of IPv4 or IPv6 addresses), or four
|
|
// parameters (a pair of IPv4 addresses and a pair of IPv6
|
|
// addresses).
|
|
// {
|
|
// char tmp[256];
|
|
// snprintf( (char*)tmp, 256, "argc %d saw_if %d saw_conf %d", argc, saw_if, saw_conf );
|
|
// WRMSG( HHC03991, "I", SSID_TO_LCSS( pDEVBLK->ssid ),
|
|
// pDEVBLK->devnum, pDEVBLK->typname, tmp );
|
|
// }
|
|
if (argc == 2
|
|
#if defined( ENABLE_IPV6 )
|
|
|| argc == 4
|
|
#endif
|
|
) /* Not pre-configured, but possibly pre-named */
|
|
{
|
|
pPTPBLK->fPreconfigured = FALSE;
|
|
}
|
|
|
|
#if !defined( OPTION_W32_CTCI )
|
|
|
|
else if (argc == 1 && !saw_if && !saw_conf) /* Pre-configured using name */
|
|
{
|
|
if (strlen( argv[0] ) > sizeof(pPTPBLK->szTUNIfName)-1)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"TUN device name", argv[0] );
|
|
return -1;
|
|
}
|
|
STRLCPY( pPTPBLK->szTUNIfName, argv[0] );
|
|
argc--; argv++;
|
|
pPTPBLK->fPreconfigured = TRUE;
|
|
}
|
|
else if (argc == 0 && saw_if && !saw_conf) /* Pre-configured using -x option */
|
|
{
|
|
pPTPBLK->fPreconfigured = TRUE;
|
|
}
|
|
|
|
#endif /* !defined(OPTION_W32_CTCI) */
|
|
|
|
else
|
|
{
|
|
// HHC00915 "%1d:%04X %s: incorrect number of parameters"
|
|
WRMSG(HHC00915, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname );
|
|
return -1;
|
|
}
|
|
|
|
#if defined( __APPLE__ ) || defined( FREEBSD_OR_NETBSD )
|
|
|
|
if (pPTPBLK->fPreconfigured == TRUE)
|
|
{
|
|
/* Need to append the interface number to the
|
|
* character device name to open the requested interface.
|
|
*/
|
|
char* s = pPTPBLK->szTUNIfName + strlen( pPTPBLK->szTUNIfName );
|
|
|
|
while (isdigit( (unsigned char)s[-1] ))
|
|
s--;
|
|
|
|
STRLCAT( pPTPBLK->szTUNCharDevName, s );
|
|
}
|
|
#endif // defined( __APPLE__ ) || defined( FREEBSD_OR_NETBSD )
|
|
|
|
//
|
|
iWantFamily = pPTPBLK->iAFamily;
|
|
iFirstFamily[0] = AF_UNSPEC;
|
|
iFirstFamily[1] = AF_UNSPEC;
|
|
j = 0;
|
|
|
|
// Process the remaining parameters.
|
|
while (argc > 0)
|
|
{
|
|
// Guest IPv4 address.
|
|
// e.g. 192.168.1.1
|
|
|
|
// Guest IPv6 address.
|
|
// e.g. 2001:db8:3003:1::543:210f
|
|
|
|
cphost = *argv; // point to host name/IP address
|
|
ilhost = strlen( *argv ); // calculate size of name/address (assume no prefix size)
|
|
cpprfx = strchr( *argv, '/' ); // Point to slash character
|
|
ilprfx = 0; // no prefix size
|
|
if (cpprfx) // If there is a slash
|
|
{
|
|
ilhost = cpprfx - cphost; // calculate length of name/address
|
|
cpprfx++; // point to prefix size
|
|
ilprfx = strlen( cpprfx ); // calculate length of prefix size
|
|
}
|
|
if (ilhost > (size_t)(sizeof(hrb.host)-1))
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"IP address", *argv );
|
|
return -1;
|
|
}
|
|
|
|
// Check whether a numeric IPv4 address has been specified.
|
|
memset( &hrb, 0, sizeof(hrb) );
|
|
hrb.wantafam = AF_INET;
|
|
hrb.numeric = TRUE;
|
|
memcpy( hrb.host, cphost, ilhost );
|
|
rc = resolve_host( &hrb);
|
|
if (rc == 0)
|
|
{
|
|
// OK, a numeric IPv4 address has been specified.
|
|
iFirstFamily[j] = AF_INET;
|
|
STRLCPY( pPTPBLK->szGuestIPAddr4, hrb.ipaddr );
|
|
memcpy( &pPTPBLK->iaGuestIPAddr4, &hrb.sa.in.sin_addr, sizeof(pPTPBLK->iaGuestIPAddr4) );
|
|
}
|
|
else
|
|
{
|
|
// A numeric IPv4 address has not been specified.
|
|
#if defined(ENABLE_IPV6)
|
|
// Check whether a numeric IPv6 address has been specified.
|
|
memset( &hrb, 0, sizeof(hrb) );
|
|
hrb.wantafam = AF_INET6;
|
|
hrb.numeric = TRUE;
|
|
if (cphost[0] == '[' && cphost[ilhost-1] == ']')
|
|
{
|
|
memcpy( hrb.host, cphost+1, ilhost-2 );
|
|
}
|
|
else
|
|
{
|
|
memcpy( hrb.host, cphost, ilhost );
|
|
}
|
|
rc = resolve_host( &hrb);
|
|
if (rc == 0)
|
|
{
|
|
// OK, a numeric IPv6 address has been specified.
|
|
iFirstFamily[j] = AF_INET6;
|
|
STRLCPY( pPTPBLK->szGuestIPAddr6, hrb.ipaddr );
|
|
memcpy( &pPTPBLK->iaGuestIPAddr6, &hrb.sa.in6.sin6_addr, sizeof(pPTPBLK->iaGuestIPAddr6) );
|
|
}
|
|
else
|
|
{
|
|
// A numeric IPv6 address has not been specified.
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
// Check whether a host name that resolves to the required
|
|
// address family has been specified.
|
|
memset( &hrb, 0, sizeof(hrb) );
|
|
hrb.wantafam = iWantFamily;
|
|
memcpy( hrb.host, cphost, ilhost );
|
|
rc = resolve_host( &hrb);
|
|
if (rc == 0)
|
|
{
|
|
// OK, a host name that resolves to the required address
|
|
// family has been specified. If no family was specified
|
|
// (the -4/-6 options) whichever family was first in the
|
|
// resolve result is being used.
|
|
iFirstFamily[j] = hrb.afam;
|
|
if (iFirstFamily[j] == AF_INET)
|
|
{
|
|
STRLCPY( pPTPBLK->szGuestIPAddr4, hrb.ipaddr );
|
|
memcpy( &pPTPBLK->iaGuestIPAddr4, &hrb.sa.in.sin_addr, sizeof(pPTPBLK->iaGuestIPAddr4) );
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
else
|
|
{
|
|
STRLCPY( pPTPBLK->szGuestIPAddr6, hrb.ipaddr );
|
|
memcpy( &pPTPBLK->iaGuestIPAddr6, &hrb.sa.in6.sin6_addr, sizeof(pPTPBLK->iaGuestIPAddr6) );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
else
|
|
{
|
|
// Something that isn't very useful has been specified..
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"IP address", *argv );
|
|
return -1;
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
|
|
if (cpprfx)
|
|
{
|
|
if (iFirstFamily[j] == AF_INET)
|
|
{
|
|
// Hmm... the Guest IPv4 address was specified with a prefix size.
|
|
{
|
|
char tmp[256];
|
|
MSGBUF( tmp, "Prefix size specification moved from guest to drive" );
|
|
WRMSG(HHC03991, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, tmp );
|
|
}
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"IP address", *argv );
|
|
return -1;
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
else
|
|
{
|
|
// Hmm... the Guest IPv6 address was specified with a prefix size.
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"IP address", *argv );
|
|
return -1;
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
|
|
argc--; argv++;
|
|
|
|
// Driver IPv4 address and prefix size in CIDR notation.
|
|
// e.g. 192.168.1.1/24
|
|
// If the prefix size is not specified a value of 32 is assumed,
|
|
// which is equivalent to a netmask of 255.255.255.255. If the
|
|
// prefix size is specified it can have a value from 0 to 32.
|
|
// The value is used to produce the equivalent netmask. For example,
|
|
// a value of 0 will produce a netmask of 0.0.0.0, while a value of
|
|
// 26 will produce a netmask of 255.255.255.192.
|
|
|
|
// Driver IPv6 address and prefix size in CIDR notation.
|
|
// e.g. 2001:db8:3003:1::543:210f/48
|
|
// If the prefix size is not specified a value of 128 is
|
|
// assumed. If the prefix size is specified it can have a
|
|
// value from 0 to 128.
|
|
|
|
cphost = *argv; // point to host name/IP address
|
|
ilhost = strlen( *argv ); // calculate size of name/address (assume no prefix)
|
|
cpprfx = strchr( *argv, '/' ); // Point to slash character
|
|
ilprfx = 0; // no prefix size
|
|
if (cpprfx) // If there is a slash
|
|
{
|
|
ilhost = cpprfx - cphost; // calculate length of name/address
|
|
cpprfx++; // point to prefix size
|
|
ilprfx = strlen( cpprfx ); // calculate length of prefix size
|
|
}
|
|
if (ilhost > (size_t)(sizeof(hrb.host)-1))
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"IP address", *argv );
|
|
return -1;
|
|
}
|
|
|
|
memset( &hrb, 0, sizeof(hrb) );
|
|
hrb.wantafam = iFirstFamily[j];
|
|
#if defined(ENABLE_IPV6)
|
|
if (iFirstFamily[j] == AF_INET6 &&
|
|
cphost[0] == '[' && cphost[ilhost-1] == ']')
|
|
{
|
|
hrb.numeric = TRUE;
|
|
memcpy( hrb.host, cphost+1, ilhost-2 );
|
|
}
|
|
else
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
memcpy( hrb.host, cphost, ilhost );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
rc = resolve_host( &hrb);
|
|
if (rc != 0)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"IP address", *argv );
|
|
return -1;
|
|
}
|
|
|
|
if (iFirstFamily[j] == AF_INET)
|
|
{
|
|
STRLCPY( pPTPBLK->szDriveIPAddr4, hrb.ipaddr );
|
|
memcpy( &pPTPBLK->iaDriveIPAddr4, &hrb.sa.in.sin_addr, sizeof(pPTPBLK->iaDriveIPAddr4) );
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
else
|
|
{
|
|
STRLCPY( pPTPBLK->szDriveIPAddr6, hrb.ipaddr );
|
|
memcpy( &pPTPBLK->iaDriveIPAddr6, &hrb.sa.in6.sin6_addr, sizeof(pPTPBLK->iaDriveIPAddr6) );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
if (cpprfx)
|
|
{
|
|
if (iFirstFamily[j] == AF_INET)
|
|
{
|
|
if (ilprfx > (size_t)sizeof(pPTPBLK->szDrivePfxSiz4)-1)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"prefix size", *argv );
|
|
return -1;
|
|
}
|
|
iPfxSiz = atoi( cpprfx );
|
|
if (( iPfxSiz < 0 ) || ( iPfxSiz > 32 ))
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"prefix size", *argv );
|
|
return -1;
|
|
}
|
|
|
|
STRLCPY( pPTPBLK->szDrivePfxSiz4, cpprfx );
|
|
|
|
switch( iPfxSiz )
|
|
{
|
|
case 0:
|
|
mask = 0x00000000;
|
|
break;
|
|
case 32:
|
|
mask = 0xFFFFFFFF;
|
|
break;
|
|
default:
|
|
mask = 0xFFFFFFFF ^ ( 0xFFFFFFFF >> iPfxSiz );
|
|
break;
|
|
}
|
|
addr4.s_addr = htonl(mask);
|
|
|
|
hinet_ntop( AF_INET, &addr4, pPTPBLK->szNetMask,
|
|
sizeof(pPTPBLK->szNetMask) );
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
else
|
|
{
|
|
if (ilprfx > (size_t)sizeof(pPTPBLK->szDrivePfxSiz6)-1)
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"prefix size", *argv );
|
|
return -1;
|
|
}
|
|
iPfxSiz = atoi( cpprfx );
|
|
if (( iPfxSiz < 0 ) || ( iPfxSiz > 128 ))
|
|
{
|
|
// HHC00916 "%1d:%04X %s: option %s value %s invalid"
|
|
WRMSG(HHC00916, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"prefix size", *argv );
|
|
return -1;
|
|
}
|
|
STRLCPY( pPTPBLK->szDrivePfxSiz6, cpprfx );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
|
|
argc--; argv++;
|
|
|
|
// Remember whether IPv4 or IPv6 addresses were specified.
|
|
if (iFirstFamily[j] == AF_INET)
|
|
pPTPBLK->fIPv4Spec = TRUE;
|
|
#if defined(ENABLE_IPV6)
|
|
else
|
|
pPTPBLK->fIPv6Spec = TRUE;
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
// Decide what address family the next pair of IP addresses should be.
|
|
#if defined(ENABLE_IPV6)
|
|
if (iWantFamily == AF_INET)
|
|
iWantFamily = AF_INET6;
|
|
else if (iWantFamily == AF_INET6)
|
|
iWantFamily = AF_INET;
|
|
else
|
|
{
|
|
if (iFirstFamily[j] == AF_INET)
|
|
iWantFamily = AF_INET6;
|
|
else
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
iWantFamily = AF_INET;
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
j++;
|
|
} /* while( argc > 0 ) */
|
|
|
|
// Good, the configuration statement had no obvious errors.
|
|
if (pPTPBLK->fPreconfigured)
|
|
rc = get_preconfigured_value(pDEVBLK, pPTPBLK);
|
|
else
|
|
rc = check_specified_value(pDEVBLK, pPTPBLK);
|
|
if (rc != 0)
|
|
return -1;
|
|
|
|
#if defined(OPTION_W32_CTCI)
|
|
// If the MAC address was not specified in the configuration
|
|
// statement, create a MAC address using pseudo-random numbers.
|
|
if (!pPTPBLK->szMACAddress[0])
|
|
{
|
|
for( j = 0; j < 6; j++ )
|
|
mac[j] = (int)((rand()/(RAND_MAX+1.0))*256);
|
|
mac[0] &= 0xFE; /* Clear multicast bit. */
|
|
mac[0] |= 0x02; /* Set local assignment bit. */
|
|
|
|
MSGBUF
|
|
(
|
|
pPTPBLK->szMACAddress,
|
|
"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
|
|
);
|
|
}
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
|
|
// That's all folks.
|
|
return 0;
|
|
} /* End function parse_conf_stmt() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* get_preconfigured_value() */
|
|
/* ------------------------------------------------------------------ */
|
|
int get_preconfigured_value( DEVBLK* pDEVBLK, PTPBLK* pPTPBLK )
|
|
{
|
|
|
|
#if defined(OPTION_W32_CTCI)
|
|
// HHC03965 "%id:%04X %s; Preconfigured interface %s does not exist or is not accessible by Hercules"
|
|
WRMSG(HHC03965, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName);
|
|
return -1;
|
|
#else /* defined(OPTION_W32_CTCI) */
|
|
/* Extract from Linux getifaddrs/freeifaddrs man page */
|
|
//
|
|
// struct ifaddrs {
|
|
// struct ifaddrs *ifa_next; /* Next item in list */
|
|
// char *ifa_name; /* Name of interface */
|
|
// unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
|
|
// struct sockaddr *ifa_addr; /* Address of interface */
|
|
// struct sockaddr *ifa_netmask; /* Netmask of interface */
|
|
// union {
|
|
// struct sockaddr *ifu_broadaddr;
|
|
// /* Broadcast address of interface */
|
|
// struct sockaddr *ifu_dstaddr;
|
|
// /* Point-to-point destination address */
|
|
// } ifa_ifu;
|
|
// #define ifa_broadaddr ifa_ifu.ifu_broadaddr
|
|
// #define ifa_dstaddr ifa_ifu.ifu_dstaddr
|
|
// void *ifa_data; /* Address-specific data */
|
|
// };
|
|
//
|
|
// The ifa_next field contains a pointer to the next structure on the list, or
|
|
// NULL if this is the last item of the list.
|
|
//
|
|
// The ifa_name points to the null-terminated interface name.
|
|
//
|
|
// The ifa_flags field contains the interface flags, as returned by the
|
|
// SIOCGIFFLAGS ioctl(2) operation (see netdevice(7) for a list of these flags).
|
|
//
|
|
// The ifa_addr field points to a structure containing the interface address.
|
|
// (The sa_family subfield should be consulted to determine the format of the
|
|
// address structure.)
|
|
//
|
|
// The ifa_netmask field points to a structure containing the netmask associated
|
|
// with ifa_addr, if applicable for the address family.
|
|
//
|
|
// Depending on whether the bit IFF_BROADCAST or IFF_POINTOPOINT is set in
|
|
// ifa_flags (only one can be set at a time), either ifa_broadaddr will contain
|
|
// the broadcast address associated with ifa_addr (if applicable for the address
|
|
// family) or ifa_dstaddr will contain the destination address of the point-to-
|
|
// point interface.
|
|
//
|
|
// The ifa_data field points to a buffer containing address-family-specific data;
|
|
// this field may be NULL if there is no such data for this interface.
|
|
//
|
|
// The data returned by getifaddrs() is dynamically allocated and should be freed
|
|
// using freeifaddrs() when no longer needed.
|
|
//
|
|
//
|
|
// On success, getifaddrs() returns zero; on error, -1 is returned, and errno is
|
|
// set appropriately.
|
|
//
|
|
// The addresses returned on Linux will usually be the IPv4 and IPv6 addresses
|
|
// assigned to the interface, but also one AF_PACKET address per interface
|
|
// containing lower-level details about the interface and its physical layer. In
|
|
// this case, the ifa_data field may contain a pointer to a struct
|
|
// net_device_stats, defined in <linux/netdevice.h>, which contains various
|
|
// interface attributes and statistics.
|
|
//
|
|
struct ifaddrs *ifaddr;
|
|
struct ifaddrs *ifacur;
|
|
int family;
|
|
u_int have_name = FALSE;
|
|
struct sockaddr_in *sin;
|
|
struct in_addr drive4;
|
|
struct in_addr guest4;
|
|
struct in_addr mask4;
|
|
u_int have_drive4 = FALSE;
|
|
u_int have_guest4 = FALSE;
|
|
u_int have_mask4 = FALSE;
|
|
#if defined(ENABLE_IPV6)
|
|
struct sockaddr_in6 *sin6;
|
|
struct in6_addr addr6;
|
|
struct in6_addr mask6;
|
|
struct in6_addr adll6;
|
|
struct in6_addr mall6;
|
|
u_int have_addr6 = FALSE;
|
|
u_int have_mask6 = FALSE;
|
|
u_int have_adll6 = FALSE;
|
|
u_int have_mall6 = FALSE;
|
|
struct in6_addr work6;
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
struct {
|
|
union {
|
|
struct in_addr ip4;
|
|
#if defined(ENABLE_IPV6)
|
|
struct in6_addr ip6;
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
unsigned int uint[4];
|
|
} mask;
|
|
unsigned int bit;
|
|
int size;
|
|
} pfx;
|
|
int fd, rc, j;
|
|
struct hifr hifr;
|
|
|
|
|
|
/* */
|
|
memset( &drive4, 0, sizeof(drive4) );
|
|
memset( &guest4, 0, sizeof(guest4) );
|
|
memset( &mask4, 0, sizeof(mask4) );
|
|
#if defined(ENABLE_IPV6)
|
|
memset( &addr6, 0, sizeof(addr6) );
|
|
memset( &mask6, 0, sizeof(mask6) );
|
|
memset( &adll6, 0, sizeof(adll6) );
|
|
memset( &mall6, 0, sizeof(mall6) );
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
/* Get the address information for all of the interfaces */
|
|
if (getifaddrs(&ifaddr) == -1) {
|
|
// HHC00900 "%1d:%04X %s: error in function %s: %s"
|
|
WRMSG(HHC00900, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"getifaddrs", strerror(errno) );
|
|
return -1;
|
|
}
|
|
|
|
/* Process the ifaddr structure(s) for the tun */
|
|
/* interface in the chain of ifaddr structures */
|
|
for (ifacur = ifaddr; ifacur != NULL; ifacur = ifacur->ifa_next) {
|
|
if (strcmp(ifacur->ifa_name, pPTPBLK->szTUNIfName) == 0) {
|
|
have_name = TRUE;
|
|
|
|
/* Extract info from the ifaddr structure for the tun interface */
|
|
if (ifacur->ifa_addr != NULL) {
|
|
family = ifacur->ifa_addr->sa_family;
|
|
if (family == AF_INET) {
|
|
/* If the tun device was configured with an IP command with the */
|
|
/* form:- */
|
|
/* ip -f inet addr add dev tun99 192.168.1.1 */
|
|
/* the device address and the peer (destination) address will */
|
|
/* be the identical. */
|
|
/* If the tun device was configured with an IP command with the */
|
|
/* form:- */
|
|
/* ip -f inet addr add dev tun99 192.168.1.1 peer 192.168.1.2 */
|
|
/* the device address and the peer (destination) address will */
|
|
/* be different (obviously!). */
|
|
if (!have_drive4) {
|
|
sin = (struct sockaddr_in*)ifacur->ifa_addr;
|
|
memcpy( &drive4, &sin->sin_addr, sizeof(drive4) );
|
|
have_drive4 = TRUE;
|
|
sin = (struct sockaddr_in*)ifacur->ifa_netmask;
|
|
memcpy( &mask4, &sin->sin_addr, sizeof(mask4) );
|
|
have_mask4 = TRUE;
|
|
if ((ifacur->ifa_flags & IFF_POINTOPOINT) && ifacur->ifa_dstaddr) {
|
|
sin = (struct sockaddr_in*)ifacur->ifa_dstaddr;
|
|
memset( &guest4, 0, sizeof(guest4) );
|
|
if ( (memcmp(&drive4, &sin->sin_addr, sizeof(drive4)) != 0) &&
|
|
(memcmp(&guest4, &sin->sin_addr, sizeof(guest4)) != 0) ) {
|
|
memcpy( &guest4, &sin->sin_addr, sizeof(guest4) );
|
|
have_guest4 = TRUE;
|
|
}
|
|
}
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
} else if (family == AF_INET6) {
|
|
sin6 = (struct sockaddr_in6*)ifacur->ifa_addr;
|
|
memset( work6.s6_addr, 0, 16 );
|
|
work6.s6_addr[0] = 0xFE;
|
|
work6.s6_addr[1] = 0x80;
|
|
if (memcmp( &sin6->sin6_addr, &work6, 8 ) != 0) {
|
|
if (!have_addr6) {
|
|
sin6 = (struct sockaddr_in6*)ifacur->ifa_addr;
|
|
memcpy( &addr6, &sin6->sin6_addr, sizeof(addr6) );
|
|
have_addr6 = TRUE;
|
|
sin6 = (struct sockaddr_in6*)ifacur->ifa_netmask;
|
|
memcpy( &mask6, &sin6->sin6_addr, sizeof(mask6) );
|
|
have_mask6 = TRUE;
|
|
}
|
|
} else {
|
|
if (!have_adll6) {
|
|
sin6 = (struct sockaddr_in6*)ifacur->ifa_addr;
|
|
memcpy( &adll6, &sin6->sin6_addr, sizeof(adll6) );
|
|
have_adll6 = TRUE;
|
|
sin6 = (struct sockaddr_in6*)ifacur->ifa_netmask;
|
|
memcpy( &mall6, &sin6->sin6_addr, sizeof(mall6) );
|
|
have_mall6 = TRUE;
|
|
}
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
} /* End of if (ifacur->ifa_addr != NULL) */
|
|
|
|
} /* End of if (strcmp(ifa_name, pPTPBLK->szTUNIfName) == 0) */
|
|
} /* End of for (ifacur = ifaddr; ifacur != NULL; ifacur = ifacur->ifa_next) */
|
|
|
|
/* Dispose of all of the returned ifaddrs structures */
|
|
freeifaddrs(ifaddr);
|
|
|
|
/* Check whether the interface exists */
|
|
if (!have_name) {
|
|
// HHC03965 "%id:%04X %s; Preconfigured interface %s does not exist or is not accessible by Hercules"
|
|
WRMSG(HHC03965, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName);
|
|
return -1;
|
|
}
|
|
|
|
/* Process the extracted IPv4 addresses and netmask */
|
|
if (have_drive4 && have_mask4) {
|
|
hinet_ntop( AF_INET, &drive4, pPTPBLK->szDriveIPAddr4, sizeof(pPTPBLK->szDriveIPAddr4) );
|
|
memcpy( &pPTPBLK->iaDriveIPAddr4, &drive4, sizeof(pPTPBLK->iaDriveIPAddr4) );
|
|
memcpy( &pfx.mask.ip4, &mask4, sizeof(mask4) );
|
|
pfx.mask.uint[0] = ntohl(pfx.mask.uint[0]);
|
|
pfx.size = 0;
|
|
pfx.bit = 0x80000000;
|
|
while (pfx.bit) {
|
|
if (pfx.mask.uint[0] & pfx.bit) {
|
|
pfx.size++;
|
|
}
|
|
pfx.bit >>= 1;
|
|
}
|
|
snprintf( pPTPBLK->szDrivePfxSiz4, sizeof(pPTPBLK->szDrivePfxSiz4), "%d", pfx.size );
|
|
hinet_ntop( AF_INET, &mask4, pPTPBLK->szNetMask, sizeof(pPTPBLK->szNetMask) );
|
|
if (have_guest4) {
|
|
hinet_ntop( AF_INET, &guest4, pPTPBLK->szGuestIPAddr4, sizeof(pPTPBLK->szGuestIPAddr4) );
|
|
memcpy( &pPTPBLK->iaGuestIPAddr4, &guest4, sizeof(pPTPBLK->iaGuestIPAddr4) );
|
|
pPTPBLK->fPreGuestIPAddr4 = TRUE;
|
|
}
|
|
pPTPBLK->fIPv4Spec = TRUE;
|
|
}
|
|
else if (!have_drive4 && !have_mask4) {
|
|
pPTPBLK->fIPv4Spec = FALSE;
|
|
}
|
|
else {
|
|
// HHC03965 "%id:%04X %s; Preconfigured interface %s does not exist or is not accessible by Hercules"
|
|
WRMSG(HHC03965, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName);
|
|
return -1;
|
|
}
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
/* Process the extracted IPv6 addresses and masks */
|
|
if (have_addr6 && have_mask6) {
|
|
/* Setup drive IPv6 addresses */
|
|
hinet_ntop( AF_INET6, &addr6, pPTPBLK->szDriveIPAddr6, sizeof(pPTPBLK->szDriveIPAddr6) );
|
|
memcpy( &pPTPBLK->iaDriveIPAddr6, &addr6, sizeof(pPTPBLK->iaDriveIPAddr6) );
|
|
/* Setup drive IPv6 prefix length */
|
|
memcpy( &pfx.mask.ip6, &mask6, sizeof(mask6) );
|
|
pfx.mask.uint[0] = ntohl(pfx.mask.uint[0]);
|
|
pfx.mask.uint[1] = ntohl(pfx.mask.uint[1]);
|
|
pfx.mask.uint[2] = ntohl(pfx.mask.uint[2]);
|
|
pfx.mask.uint[3] = ntohl(pfx.mask.uint[3]);
|
|
pfx.size = 0;
|
|
for (j = 0; j <= 3; j++) {
|
|
if (pfx.mask.uint[j] == 0x00000000)
|
|
break;
|
|
if (pfx.mask.uint[j] == 0xFFFFFFFF) {
|
|
pfx.size += 32;
|
|
} else {
|
|
pfx.bit = 0x80000000;
|
|
while (pfx.bit) {
|
|
if (pfx.mask.uint[j] & pfx.bit) {
|
|
pfx.size++;
|
|
}
|
|
pfx.bit >>= 1;
|
|
}
|
|
}
|
|
}
|
|
snprintf( pPTPBLK->szDrivePfxSiz6, sizeof(pPTPBLK->szDrivePfxSiz6), "%d", pfx.size );
|
|
if (have_adll6 && have_mall6) {
|
|
/* Setup drive IPv6 link local address */
|
|
hinet_ntop( AF_INET6, &adll6, pPTPBLK->szDriveLLAddr6, sizeof(pPTPBLK->szDriveLLAddr6) );
|
|
memcpy( &pPTPBLK->iaDriveLLAddr6, &adll6, sizeof(pPTPBLK->iaDriveLLAddr6) );
|
|
/* Setup drive IPv6 link local prefix length */
|
|
memcpy( &pfx.mask.ip6, &mall6, sizeof(mall6) );
|
|
pfx.mask.uint[0] = ntohl(pfx.mask.uint[0]);
|
|
pfx.mask.uint[1] = ntohl(pfx.mask.uint[1]);
|
|
pfx.mask.uint[2] = ntohl(pfx.mask.uint[2]);
|
|
pfx.mask.uint[3] = ntohl(pfx.mask.uint[3]);
|
|
pfx.size = 0;
|
|
for (j = 0; j <= 3; j++) {
|
|
if (pfx.mask.uint[j] == 0x00000000)
|
|
break;
|
|
if (pfx.mask.uint[j] == 0xFFFFFFFF) {
|
|
pfx.size += 32;
|
|
} else {
|
|
pfx.bit = 0x80000000;
|
|
while (pfx.bit) {
|
|
if (pfx.mask.uint[j] & pfx.bit) {
|
|
pfx.size++;
|
|
}
|
|
pfx.bit >>= 1;
|
|
}
|
|
}
|
|
}
|
|
snprintf( pPTPBLK->szDriveLLxSiz6, sizeof(pPTPBLK->szDriveLLxSiz6), "%d", pfx.size );
|
|
} else {
|
|
// Create a Driver Link Local address using pseudo-random numbers.
|
|
addr6.s6_addr[0] = 0xFE;
|
|
addr6.s6_addr[1] = 0x80;
|
|
memset( &addr6.s6_addr[2], 0, 6 );
|
|
for( j = 8; j < 16; j++ )
|
|
addr6.s6_addr[j] = (int)((rand()/(RAND_MAX+1.0))*256);
|
|
hinet_ntop( AF_INET6, &addr6, pPTPBLK->szDriveLLAddr6, sizeof(pPTPBLK->szDriveLLAddr6) );
|
|
memcpy( &pPTPBLK->iaDriveLLAddr6, &addr6, sizeof(pPTPBLK->iaDriveLLAddr6) );
|
|
}
|
|
pPTPBLK->fIPv6Spec = TRUE;
|
|
}
|
|
else if (!have_addr6 && !have_mask6 && !have_adll6 && !have_mall6) {
|
|
pPTPBLK->fIPv6Spec = FALSE;
|
|
}
|
|
else {
|
|
// HHC03965 "%id:%04X %s; Preconfigured interface %s does not exist or is not accessible by Hercules"
|
|
WRMSG(HHC03965, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName);
|
|
return -1;
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
/* Check that either IPv4 or IPv6 addresses were extracted */
|
|
if (!pPTPBLK->fIPv4Spec
|
|
#if defined(ENABLE_IPV6)
|
|
&& !pPTPBLK->fIPv6Spec
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
)
|
|
{
|
|
// HHC03965 "%id:%04X %s; Preconfigured interface %s does not exist or is not accessible by Hercules"
|
|
WRMSG(HHC03965, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPBLK->szTUNIfName);
|
|
return -1;
|
|
}
|
|
|
|
/* Obtain the MTU value */
|
|
memset( &hifr, 0, sizeof(struct hifr) );
|
|
strncpy( hifr.hifr_name, pPTPBLK->szTUNIfName, sizeof(hifr.hifr_name)-1 );
|
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
rc = TUNTAP_IOCtl( fd, SIOCGIFMTU, (char*)&hifr );
|
|
close(fd);
|
|
|
|
if (rc < 0) {
|
|
// HHC00902 "%1d:%04X %s: ioctl '%s' failed for device '%s': '%s'"
|
|
WRMSG(HHC00902, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
"SIOCGIFMTU", pPTPBLK->szTUNIfName, strerror(errno) );
|
|
return -1;
|
|
}
|
|
|
|
pPTPBLK->iMTU = hifr.hifr_mtu;
|
|
snprintf( pPTPBLK->szMTU, sizeof(pPTPBLK->szMTU), "%d", hifr.hifr_mtu );
|
|
|
|
// // HHC03953 "%1d:%04X PTP: IPv4: Drive %s/%s (%s): Guest %s"
|
|
// WRMSG(HHC03953, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
// pPTPBLK->szDriveIPAddr4,
|
|
// pPTPBLK->szDrivePfxSiz4,
|
|
// pPTPBLK->szNetMask,
|
|
// pPTPBLK->szGuestIPAddr4 );
|
|
// // HHC03954 "%1d:%04X PTP: IPv6: Drive %s/%s %s/%s: Guest %s"
|
|
// WRMSG(HHC03954, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
// pPTPBLK->szDriveLLAddr6,
|
|
// pPTPBLK->szDriveLLxSiz6,
|
|
// pPTPBLK->szDriveIPAddr6,
|
|
// pPTPBLK->szDrivePfxSiz6,
|
|
// pPTPBLK->szGuestIPAddr6 );
|
|
|
|
// mpc_display_stuff( pDEVBLK, "sockaddr_in6", (BYTE*)sin6, sizeof(struct sockaddr_in6), ' ' );
|
|
// mpc_display_stuff( pDEVBLK, "work6", (BYTE*)&work6, sizeof(struct in6_addr), ' ' );
|
|
// mpc_display_stuff( pDEVBLK, "sin6_addr", (BYTE*)&sin6->sin6_addr, sizeof(addr6), ' ' );
|
|
|
|
/* That's all folks. */
|
|
return 0;
|
|
#endif /* defined(OPTION_W32_CTCI) */
|
|
} /* End function get_preconfigured_value() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* check_specified_value() */
|
|
/* ------------------------------------------------------------------ */
|
|
int check_specified_value( DEVBLK* pDEVBLK, PTPBLK* pPTPBLK )
|
|
{
|
|
#if defined(ENABLE_IPV6)
|
|
struct in6_addr addr6; /* Work area for IPv6 addresses */
|
|
int fd;
|
|
int j;
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
|
|
// If IPv4 addresses were specified check that the same IPv4 address
|
|
// has not been specified for the guest and driver.
|
|
if (pPTPBLK->fIPv4Spec &&
|
|
memcmp( &pPTPBLK->iaGuestIPAddr4, &pPTPBLK->iaDriveIPAddr4, 4 ) == 0)
|
|
{
|
|
// HHC03901 "%1d:%04X PTP: Guest and driver IP addresses are the same"
|
|
WRMSG(HHC03901, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum );
|
|
return -1;
|
|
}
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
// If IPv6 addresses were specified check that the same IPv6 address
|
|
// has not been specified for the guest and driver.
|
|
if (pPTPBLK->fIPv6Spec &&
|
|
memcmp( &pPTPBLK->iaGuestIPAddr6, &pPTPBLK->iaDriveIPAddr6, 16 ) == 0)
|
|
{
|
|
// HHC03901 "%1d:%04X PTP: Guest and driver IP addresses are the same"
|
|
WRMSG(HHC03901, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum );
|
|
return -1;
|
|
}
|
|
|
|
// If IPv6 addresses were specified check that IPv6 is supported on
|
|
// this machine.
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
fd = socket( AF_INET6, SOCK_DGRAM, 0 );
|
|
if (fd < 0)
|
|
{
|
|
// HHC03902 "%1d:%04X PTP: Inet6 not supported"
|
|
WRMSG(HHC03902, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum );
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
close( fd );
|
|
}
|
|
}
|
|
|
|
// If IPv6 addresses were specified check that the MTU size is at
|
|
// least the minimum size for an IPv6 link.
|
|
if (pPTPBLK->fIPv6Spec &&
|
|
pPTPBLK->iMTU < 1280)
|
|
{
|
|
// HHC03918 "%1d:%04X PTP: MTU changed from size %d bytes to size %d bytes"
|
|
WRMSG(HHC03918, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pPTPBLK->iMTU, 1280 );
|
|
STRLCPY( pPTPBLK->szMTU, "1280" );
|
|
pPTPBLK->iMTU = 1280;
|
|
}
|
|
|
|
// If IPv6 addresses were specified create a Driver Link Local IPv6
|
|
// address using pseudo-random numbers.
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
addr6.s6_addr[0] = 0xFE;
|
|
addr6.s6_addr[1] = 0x80;
|
|
memset( &addr6.s6_addr[2], 0, 6 );
|
|
for( j = 8; j < 16; j++ )
|
|
addr6.s6_addr[j] = (int)((rand()/(RAND_MAX+1.0))*256);
|
|
|
|
hinet_ntop( AF_INET6, &addr6, pPTPBLK->szDriveLLAddr6, sizeof(pPTPBLK->szDriveLLAddr6) );
|
|
memcpy( &pPTPBLK->iaDriveLLAddr6, &addr6, sizeof(pPTPBLK->iaDriveLLAddr6) );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
// That's all folks.
|
|
return 0;
|
|
} /* End function check_specified_value() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* raise_unsol_int() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Return value
|
|
// 0 Successful
|
|
// -1 No storage available for a PTPINT
|
|
// -2 The create_thread for the ptp_unsol_int_thread failed
|
|
|
|
int raise_unsol_int( DEVBLK* pDEVBLK, BYTE bStatus, int iDelay )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data; // PTPATH
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK; // PTPBLK
|
|
PTPINT* pPTPINT; // PTPINT
|
|
TID tid; // ptp_unsol_int_thread thread ID
|
|
char thread_name[32]; // ptp_unsol_int_thread
|
|
int rc; // Return code
|
|
|
|
|
|
// Obtain the unsolicited interrupt list lock.
|
|
obtain_lock( &pPTPBLK->UnsolListLock );
|
|
|
|
// Obtain a PTPINT from the LIFO linked list.
|
|
pPTPINT = pPTPBLK->pFirstPTPINT; // Pointer to first PTPINT
|
|
if (pPTPINT) // If there is a PTPINT
|
|
{
|
|
pPTPBLK->pFirstPTPINT = pPTPINT->pNextPTPINT; // Make the next the first PTPINT
|
|
pPTPINT->pNextPTPINT = NULL; // Clear the pointer to next PTPINT
|
|
}
|
|
|
|
// Release the unsolicited interrupt list lock.
|
|
release_lock( &pPTPBLK->UnsolListLock );
|
|
|
|
// If we did not obtain a PTPINT from the LIFO linked list
|
|
// then allocate storage for a PTPINT.
|
|
if (!pPTPINT) // If there isn't a PTPINT
|
|
{
|
|
pPTPINT = alloc_storage( pDEVBLK, (int)sizeof(PTPINT) );
|
|
if (!pPTPINT) // If there is no storage
|
|
{
|
|
// Report the bad news.
|
|
// HHC00102 "Error in function create_thread(): %s"
|
|
WRMSG(HHC00102, "E", "No storage available!");
|
|
// Hmm... the interrupt to the y-side will not be raised.
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Initialize the PTPINT.
|
|
pPTPINT->pDEVBLK = pDEVBLK;
|
|
pPTPINT->bStatus = bStatus;
|
|
pPTPINT->iDelay = iDelay;
|
|
|
|
// Create the unsolicited interrupt thread.
|
|
MSGBUF( thread_name, "%s %4.4X UnsolIntThread",
|
|
pPTPBLK->pDEVBLKRead->typname,
|
|
pPTPBLK->pDEVBLKRead->devnum);
|
|
rc = create_thread( &tid, JOINABLE, ptp_unsol_int_thread, pPTPINT, thread_name );
|
|
if (rc)
|
|
{
|
|
// Report the bad news.
|
|
// HHC00102 "Error in function create_thread(): %s"
|
|
WRMSG(HHC00102, "E", strerror(rc));
|
|
// Hmm... the interrupt to the y-side will not be raised.
|
|
return -2;
|
|
}
|
|
|
|
// Good, the thread is active.
|
|
return 0;
|
|
} /* End function raise_unsol_int() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ptp_unsol_int_thread() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void* ptp_unsol_int_thread( void* arg )
|
|
{
|
|
PTPINT* pPTPINT = (PTPINT*) arg;
|
|
DEVBLK* pDEVBLK = pPTPINT->pDEVBLK; // DEVBLK
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data; // PTPATH
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK; // PTPBLK
|
|
int rc;
|
|
int i;
|
|
int delay_q;
|
|
int delay_r;
|
|
struct timespec waittime;
|
|
struct timeval now;
|
|
|
|
|
|
// Check whether the requestor wants a delay before the interrupt
|
|
// is raised.
|
|
if (pPTPINT->iDelay != 0)
|
|
{
|
|
// Wait for the number of milliseconds specified by the requestor.
|
|
// Calculate when to end the wait.
|
|
delay_q = pPTPINT->iDelay / 1000;
|
|
delay_r = pPTPINT->iDelay % 1000;
|
|
|
|
gettimeofday( &now, NULL );
|
|
|
|
waittime.tv_sec = now.tv_sec + delay_q;
|
|
waittime.tv_nsec = (now.tv_usec + (delay_r * 1000)) * 1000;
|
|
if (waittime.tv_nsec >= 1000000000)
|
|
{
|
|
waittime.tv_sec++;
|
|
waittime.tv_nsec -= 1000000000;
|
|
}
|
|
|
|
// Obtain the path unsolicited interrupt event lock
|
|
obtain_lock( &pPTPATH->UnsolEventLock );
|
|
|
|
// Use a calculated wait
|
|
rc = timed_wait_condition( &pPTPATH->UnsolEvent,
|
|
&pPTPATH->UnsolEventLock,
|
|
&waittime );
|
|
|
|
// Release the path unsolicited interrupt event lock
|
|
release_lock( &pPTPATH->UnsolEventLock );
|
|
}
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPCCW)
|
|
{
|
|
// HHC03994 "%1d:%04X %s: Status %02X"
|
|
WRMSG(HHC03994, "D", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname,
|
|
pPTPINT->bStatus );
|
|
}
|
|
|
|
// Raise an interrupt.
|
|
// device_attention() (in channel.c) raises an unsolicited interrupt
|
|
// for the specified device. Return value is 0 if successful, 1 if
|
|
// the device is busy or pending, or 3 if subchannel is not valid
|
|
// or not enabled.
|
|
// If the device is busy or pending, wait for 100 milliseconds and
|
|
// attempt to raise the interrupt again. Retry up to nine times,
|
|
// i.e. attempt to raise the interrupt up to a total of ten times.
|
|
rc = device_attention( pDEVBLK, pPTPINT->bStatus );
|
|
if (rc == 1)
|
|
{
|
|
for( i = 0; i <= 8; i++ )
|
|
{
|
|
// Wait for 100 milliseconds
|
|
// Calculate when to end the wait.
|
|
gettimeofday( &now, NULL );
|
|
|
|
waittime.tv_sec = now.tv_sec;
|
|
waittime.tv_nsec = (now.tv_usec + (100 * 1000)) * 1000;
|
|
if (waittime.tv_nsec >= 1000000000)
|
|
{
|
|
waittime.tv_sec++;
|
|
waittime.tv_nsec -= 1000000000;
|
|
}
|
|
|
|
// Obtain the path unsolicited interrupt event lock
|
|
obtain_lock( &pPTPATH->UnsolEventLock );
|
|
|
|
// Use a calculated wait
|
|
rc = timed_wait_condition( &pPTPATH->UnsolEvent,
|
|
&pPTPATH->UnsolEventLock,
|
|
&waittime );
|
|
|
|
// Release the path unsolicited interrupt event lock
|
|
release_lock( &pPTPATH->UnsolEventLock );
|
|
|
|
// Attempt to raise the interrupt again.
|
|
rc = device_attention( pDEVBLK, pPTPINT->bStatus );
|
|
if (rc != 1)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Obtain the unsolicited interrupt list lock.
|
|
obtain_lock( &pPTPBLK->UnsolListLock );
|
|
|
|
// Return the PTPINT to the LIFO linked list.
|
|
pPTPINT->pNextPTPINT = pPTPBLK->pFirstPTPINT;
|
|
pPTPBLK->pFirstPTPINT = pPTPINT;
|
|
|
|
// Release the unsolicited interrupt list lock.
|
|
release_lock( &pPTPBLK->UnsolListLock );
|
|
|
|
// That's all; the interrupt has been raised, or maybe not...
|
|
return NULL;
|
|
} /* End function ptp_unsol_int_thread() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* ptp_get_tod_clock() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note: the returned TodClock (8-bytes) is in network byte order.
|
|
|
|
void ptp_get_tod_clock( BYTE* TodClock )
|
|
{
|
|
REGS *regs;
|
|
ETOD ETOD;
|
|
TOD tod;
|
|
|
|
obtain_lock( &sysblk.cpulock[ sysblk.pcpu ]);
|
|
{
|
|
regs = sysblk.regs[ sysblk.pcpu ];
|
|
etod_clock( regs, &ETOD, ETOD_standard );
|
|
tod = ETOD2TOD( ETOD );
|
|
}
|
|
release_lock( &sysblk.cpulock[ sysblk.pcpu ]);
|
|
|
|
STORE_DW( TodClock, tod );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* get_subarea_address() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note: the returned SAaddress (4-bytes) is in network byte order.
|
|
// VTAM creates a 4-byte subarea address from a combination of the
|
|
// output of a STIDP instruction and the output of a STCK
|
|
// instruction. The first 2-bytes of the subarea address come from
|
|
// bits 28 to 43 of the output of the STIDP instruction, which is the
|
|
// last 4-bits of the 'CPU Identification Number' and the first
|
|
// 12-bits of the 'Machine-Type Number'. The last 2-bytes of the
|
|
// subarea address come from bits 31 to 46 of the output of the STCK
|
|
// instruction.
|
|
|
|
void get_subarea_address( BYTE* SAaddress )
|
|
{
|
|
REGS *regs;
|
|
ETOD ETOD;
|
|
TOD tod;
|
|
U64 dreg; /* Double word workarea */
|
|
U16 hreg; /* Half word workarea */
|
|
|
|
|
|
obtain_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
regs = sysblk.regs[sysblk.pcpu];
|
|
etod_clock(regs, &ETOD, ETOD_standard);
|
|
tod = ETOD2TOD(ETOD);
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
dreg = sysblk.cpuid;
|
|
|
|
hreg = ( ( dreg >> 20 ) & 0x000000000000FFFFULL );
|
|
STORE_HW( SAaddress+0, hreg );
|
|
hreg = ( ( tod >> 17 ) & 0x000000000000FFFFULL );
|
|
STORE_HW( SAaddress+2, hreg );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_hx0_01() */
|
|
/* ------------------------------------------------------------------ */
|
|
// When we are handshaking the second CCW in the chain is the guest
|
|
// OS on the y-side writing an PTPHX0 type 0x00 or 0x01.
|
|
|
|
void write_hx0_01( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
// PTPHX0* pPTPHX0 = (PTPHX0*)pIOBuf;
|
|
|
|
UNREFERENCED( uCount );
|
|
UNREFERENCED( iCCWSeq );
|
|
UNREFERENCED( pIOBuf );
|
|
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In HX0" );
|
|
}
|
|
|
|
// PTPHX0 type 0x01's should only be written when handshaking is being
|
|
// initiated or is in progress.
|
|
if (!pPTPATH->fHandshaking)
|
|
{
|
|
// An PTPHX0 type 0x01 is being written by the y-side when handshaking
|
|
// was not in progress on the path; we will assume that the y-side
|
|
// has initiated handshaking and that the PTPHX0 is the start of
|
|
// handshake one.
|
|
pPTPATH->fHandshaking = TRUE; // Handshaking in progress
|
|
pPTPATH->fHandshakeCur = HANDSHAKE_ONE; // Handshake one in progress
|
|
pPTPATH->fHandshakeSta |= HANDSHAKE_ONE; // handshake one started
|
|
|
|
// The guest OS on the y-side has started, or restarted, the
|
|
// device, so reset or update any necessary values in the PTPBLK.
|
|
// Note: this section of code is executed twice, once for the read
|
|
// path and once for the write path, though not necessarily in that
|
|
// order. Whichever path executes the routine first will reset or
|
|
// update the values.
|
|
obtain_lock( &pPTPBLK->UpdateLock );
|
|
if (pPTPBLK->xTokensUpdated == 0) // if not updated
|
|
{
|
|
pPTPBLK->xTokensUpdated = 1; // updated
|
|
|
|
// Reset the active & terminate indicators
|
|
if (pPTPBLK->fActive4)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
}
|
|
pPTPBLK->fActive4 = FALSE;
|
|
pPTPBLK->bActivate4 = 0x00;
|
|
pPTPBLK->bTerminate4 = 0x00;
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fActive6)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pPTPBLK->fActive6 = FALSE;
|
|
pPTPBLK->bActivate6 = 0x00;
|
|
pPTPBLK->bTerminate6 = 0x00;
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fActiveLL6)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestLLAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pPTPBLK->fActiveLL6 = FALSE;
|
|
pPTPBLK->bActivateLL6 = 0x00;
|
|
pPTPBLK->bTerminateLL6 = 0x00;
|
|
|
|
// Obtain the lock for manipulating the tokens
|
|
obtain_lock( &TokenLock );
|
|
|
|
// Set the x-side tokens
|
|
STORE_FW( pPTPBLK->xTokenIssuerRm, uTokenIssuerRm );
|
|
STORE_FW( pPTPBLK->xTokenCmFilter, uTokenCmFilter );
|
|
STORE_FW( pPTPBLK->xTokenCmConnection, uTokenCmConnection );
|
|
STORE_FW( pPTPBLK->xTokenUlpFilter, uTokenUlpFilter );
|
|
STORE_FW( pPTPBLK->xTokenUlpConnection, uTokenUlpConnection );
|
|
|
|
// Increment the tokens
|
|
uTokenIssuerRm += INCREMENT_TOKEN;
|
|
uTokenCmFilter += INCREMENT_TOKEN;
|
|
uTokenCmConnection += INCREMENT_TOKEN;
|
|
uTokenUlpFilter += INCREMENT_TOKEN;
|
|
uTokenUlpConnection += INCREMENT_TOKEN;
|
|
|
|
// Release the lock for manipulating the tokens
|
|
release_lock( &TokenLock );
|
|
|
|
// Clear the y-side tokens
|
|
pPTPBLK->yTokensCopied = 0;
|
|
memset( pPTPBLK->yTokenIssuerRm, 0, MPC_TOKEN_LENGTH );
|
|
memset( pPTPBLK->yTokenCmFilter, 0, MPC_TOKEN_LENGTH );
|
|
memset( pPTPBLK->yTokenCmConnection, 0, MPC_TOKEN_LENGTH );
|
|
memset( pPTPBLK->yTokenUlpFilter, 0, MPC_TOKEN_LENGTH );
|
|
memset( pPTPBLK->yTokenUlpConnection, 0, MPC_TOKEN_LENGTH );
|
|
|
|
// Reset the y-side process sequence numbers
|
|
pPTPBLK->uSeqNumIssuer = 0;
|
|
pPTPBLK->uSeqNumCm = 0;
|
|
|
|
/* Clear the y-side IP address information */
|
|
if (pPTPBLK->fPreconfigured) {
|
|
if (!pPTPBLK->fPreGuestIPAddr4) {
|
|
memset(pPTPBLK->szGuestIPAddr4, 0, sizeof(pPTPBLK->szGuestIPAddr4));
|
|
memset(&pPTPBLK->iaGuestIPAddr4, 0, sizeof(pPTPBLK->iaGuestIPAddr4));
|
|
}
|
|
#if defined(ENABLE_IPV6)
|
|
memset(pPTPBLK->szGuestIPAddr6, 0, sizeof(pPTPBLK->szGuestIPAddr6));
|
|
memset(&pPTPBLK->iaGuestIPAddr6, 0, sizeof(pPTPBLK->iaGuestIPAddr6));
|
|
memset(pPTPBLK->szGuestLLAddr6, 0, sizeof(pPTPBLK->szGuestLLAddr6));
|
|
memset(&pPTPBLK->iaGuestLLAddr6, 0, sizeof(pPTPBLK->iaGuestLLAddr6));
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pPTPBLK->xTokensUpdated = 0; // update next restart
|
|
}
|
|
release_lock( &pPTPBLK->UpdateLock );
|
|
|
|
// The guest OS on the y-side has started, or restarted, the
|
|
// device, so dispose of any data waiting to be read by the y-side.
|
|
// Free any PTPHDR on the chain for the path
|
|
remove_and_free_any_buffers_on_chain( pPTPATH );
|
|
// Reset the message sequence number
|
|
pPTPATH->uSeqNum = 0;
|
|
}
|
|
else
|
|
{
|
|
// An PTPHX0 type 0x01 is being written by the y-side and handshaking
|
|
// is in progress on the path; we will assume that the y-side
|
|
// is continuing handshaking and that the PTPHX0 is the start
|
|
// of handshake three.
|
|
pPTPATH->fHandshakeCur = HANDSHAKE_THREE; // Handshake three in progress
|
|
pPTPATH->fHandshakeSta |= HANDSHAKE_THREE; // handshake three started
|
|
}
|
|
|
|
// Set residual byte count and unit status.
|
|
*pMore = 0;
|
|
*pResidual = 0;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
return;
|
|
} /* End function write_hx0_01() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_hx0_00() */
|
|
/* ------------------------------------------------------------------ */
|
|
// When we are handshaking the second CCW in the chain is the guest
|
|
// OS on the y-side writing an PTPHX0 type 0x00 or 0x01.
|
|
|
|
void write_hx0_00( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
// PTPHX0* pPTPHX0 = (PTPHX0*)pIOBuf;
|
|
|
|
UNREFERENCED( uCount );
|
|
UNREFERENCED( iCCWSeq );
|
|
UNREFERENCED( pIOBuf );
|
|
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In HX0" );
|
|
}
|
|
|
|
// PTPHX0 type 0x00 should only be written when handshaking is in progress.
|
|
if (pPTPATH->fHandshaking)
|
|
{
|
|
// An PTPHX0 type 0x00 is being written by the y-side and handshaking
|
|
// is in progress on the path; we will assume that the y-side
|
|
// is continuing handshaking and that the PTPHX0 is the start
|
|
// of handshake two.
|
|
pPTPATH->fHandshakeCur = HANDSHAKE_TWO; // Handshake two in progress
|
|
pPTPATH->fHandshakeSta |= HANDSHAKE_TWO; // handshake two started
|
|
}
|
|
else
|
|
{
|
|
// An PTPHX0 type 0x00 is being written by the y-side and handshaking
|
|
// is not in progress on the path; we don't understand!
|
|
}
|
|
|
|
// Set residual byte count and unit status.
|
|
*pMore = 0;
|
|
*pResidual = 0;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
return;
|
|
} /* End function write_hx0_00() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_hx2() */
|
|
/* ------------------------------------------------------------------ */
|
|
// When we are handshaking the third CCW in the chain is the guest
|
|
// OS on the y-side writing an XID2. We must create the PTPHX0, XID2
|
|
// and 'VTAM' to be read by the fourth, fifth and sixth CCW's in the
|
|
// chain.
|
|
|
|
void write_hx2( DEVBLK* pDEVBLK, U32 uCount,
|
|
int iCCWSeq, BYTE* pIOBuf,
|
|
BYTE* pMore, BYTE* pUnitStat,
|
|
U32* pResidual )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
PTPHX2* pPTPHX2wr = (PTPHX2*)pIOBuf; // PTPHX2 being written
|
|
PTPHSV* pPTPHSVwr; // PTPHSV being written
|
|
|
|
PTPHDR* pPTPHDRx0 = NULL; // PTPHDR before PTPHX0
|
|
PTPHX0* pPTPHX0re = NULL; // PTPHX0 to be read
|
|
PTPHDR* pPTPHDRx2 = NULL; // PTPHDR before PTPHX2
|
|
PTPHX2* pPTPHX2re = NULL; // PTPHX2 to be read
|
|
PTPHSV* pPTPHSVre = NULL; // PTPHSV to be read
|
|
PTPHDR* pPTPHDRvt = NULL; // PTPHDR before 'VTAM'
|
|
BYTE* pPTPVTMre = NULL; // 'VTAM' to be read
|
|
|
|
U16 uDataLen1; // Data length one
|
|
U16 uMaxReadLen; // Maximum read length
|
|
PTPHDR* pPTPHDR; // PTPHDR
|
|
U32 uNodeID;
|
|
|
|
UNREFERENCED( uCount );
|
|
UNREFERENCED( iCCWSeq );
|
|
UNREFERENCED( pIOBuf );
|
|
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In HX2" );
|
|
}
|
|
|
|
// Point to the CSVcv following the XID2.
|
|
pPTPHSVwr = point_CSVcv( pDEVBLK, pPTPHX2wr );
|
|
|
|
// XID2's should only be written when handshaking is in progress.
|
|
if (pPTPATH->fHandshaking)
|
|
{
|
|
// An XID2 is being written by the y-side and handshaking is
|
|
// in progress on the path; all is well with the world.
|
|
|
|
// Copy the start time and token from the XID2.
|
|
// Note: this section of code is executed twice, once for the read
|
|
// path and once for the write path, though not necessarily in that
|
|
// order. Whichever path executes the routine first will copy the
|
|
// values.
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_ONE)
|
|
{
|
|
|
|
obtain_lock( &pPTPBLK->UpdateLock );
|
|
|
|
if (pPTPHX2wr->DLCtype != pPTPATH->bDLCtype ) // XID2 from expected y-side's path?
|
|
{
|
|
// HHC03917 "%1d:%04X PTP: Guest read and write paths mis-configured"
|
|
WRMSG(HHC03917, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum );
|
|
}
|
|
|
|
if (pPTPBLK->yTokensCopied == 0)
|
|
{
|
|
|
|
pPTPBLK->yTokensCopied = 1;
|
|
memcpy( pPTPBLK->yTokenIssuerRm, pPTPHX2wr->Token, MPC_TOKEN_LENGTH );
|
|
memcpy( pPTPBLK->yStartTime, pPTPHSVwr->SID1, 8 );
|
|
|
|
gen_csv_sid( pPTPBLK->yStartTime, pPTPBLK->xStartTime,
|
|
pPTPBLK->xSecondCsvSID2 );
|
|
|
|
}
|
|
|
|
if (pPTPHX2wr->DLCtype == DLCTYPE_READ) // XID2 from y-side's Read path?
|
|
{
|
|
// Extract the data lengths from the XID2.
|
|
FETCH_HW( uDataLen1, pPTPHX2wr->DataLen1 ); // Get y-side's data length one
|
|
FETCH_HW( uMaxReadLen, pPTPHX2wr->MaxReadLen ); // Get y-side's maximum read length
|
|
|
|
// Obtain the read buffer lock.
|
|
obtain_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
// Point to the read buffer.
|
|
pPTPHDR = pPTPBLK->pReadBuffer;
|
|
pPTPBLK->pReadBuffer = NULL;
|
|
|
|
// Replace the existing read buffer if necessary.
|
|
// (This is the buffer into which we place packets
|
|
// received from the TUN interface, and from which
|
|
// the y-side's read path reads the packets.)
|
|
if (pPTPBLK->yMaxReadLen != uMaxReadLen)
|
|
{
|
|
// Free the existing read buffer, if there is one.
|
|
if (pPTPHDR)
|
|
free( pPTPHDR );
|
|
|
|
// Allocate a new read buffer.
|
|
pPTPHDR = alloc_ptp_buffer( pDEVBLK, (int)uMaxReadLen );
|
|
}
|
|
|
|
// Initialize the existing or new read buffer, if there is one.
|
|
if (pPTPHDR)
|
|
{
|
|
MPC_TH* pMPC_TH; // MPC_TH follows the PTPHDR
|
|
MPC_RRH* pMPC_RRH; // MPC_RRH follows the MPC_TH
|
|
// MPC_PH* pMPC_PH; // MPC_PH follows the MPC_RRH
|
|
|
|
// Fix-up various pointers
|
|
pMPC_TH = (MPC_TH*)((BYTE*)pPTPHDR + SIZE_HDR);
|
|
pMPC_RRH = (MPC_RRH*)((BYTE*)pMPC_TH + SIZE_TH);
|
|
// pMPC_PH = (MPC_PH*)((BYTE*)pMPC_RRH + SIZE_RRH);
|
|
|
|
// Prepare PTPHDR
|
|
pPTPHDR->iDataLen = LEN_OF_PAGE_ONE;
|
|
|
|
// Clear the data area.
|
|
memset( pMPC_TH, 0, (int)uMaxReadLen );
|
|
|
|
// Prepare MPC_TH
|
|
STORE_FW( pMPC_TH->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_TH->offrrh, SIZE_TH );
|
|
STORE_HW( pMPC_TH->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_TH->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRH
|
|
pMPC_RRH->type = RRH_TYPE_CM;
|
|
pMPC_RRH->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRH->numph, 1 );
|
|
STORE_HW( pMPC_RRH->offph, SIZE_RRH );
|
|
|
|
// Prepare MPC_PH
|
|
|
|
// increment the read buffer generation number
|
|
pPTPBLK->iReadBufferGen++;
|
|
}
|
|
|
|
// Set the pointer to the read buffer.
|
|
pPTPBLK->pReadBuffer = pPTPHDR;
|
|
|
|
// Release the read buffer lock.
|
|
release_lock( &pPTPBLK->ReadBufferLock );
|
|
|
|
// Copy the data lengths extracted from the XID2.
|
|
pPTPBLK->yDataLen1 = uDataLen1;
|
|
pPTPBLK->yMaxReadLen = uMaxReadLen;
|
|
pPTPBLK->yActMTU = ( pPTPBLK->yMaxReadLen - pPTPBLK->yDataLen1 ) - 2048;
|
|
|
|
// An MPCPTP/MPCPTP6 connection uses an MTU that is the smaller of
|
|
// a) the MTU specified on a route statement, or b) the MTU calculated
|
|
// from the maximum read length reported by the other side during
|
|
// handshaking. For example, if the x-side's TRLE definition is using
|
|
// the default MAXBFRU value of 5, the maximum read length reported
|
|
// by the x-side to the y-side will be 20476 (0x4FFC) bytes, from
|
|
// which both sides will calculate an MTU of 14336 (0x3800) bytes.
|
|
// If the y-side has a route statement that specifies an MTU of 24576
|
|
// (0x6000) bytes, the specified MTU is ignored and the calculated MTU
|
|
// will be used. Depending on the values specified for MAXBFRU and for
|
|
// route statements, the MTU in use from the x-side to the y-side
|
|
// could be different to the MTU in use from the y-side to the x-side.
|
|
// For a real MPCPTP/MPCPTP6 connection this is probably a good thing,
|
|
// with the maximum capacity in each direction automatically used.
|
|
// However, for this emulated MPCPTP/MPCPTP6 connection this could be
|
|
// a bad thing because we are not processing the packets, we are simply
|
|
// forwarding them, and we may be forwarding them to something that is
|
|
// using a smaller MTU.
|
|
|
|
// HHC03910 "%1d:%04X PTP: Hercules has maximum read length of size %d bytes and actual MTU of size %d bytes"
|
|
WRMSG(HHC03910, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
(int)pPTPBLK->xMaxReadLen, (int)pPTPBLK->xActMTU );
|
|
// HHC03911 "%1d:%04X PTP: Guest has maximum read length of size %d bytes and actual MTU of size %d bytes"
|
|
WRMSG(HHC03911, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
(int)pPTPBLK->yMaxReadLen, (int)pPTPBLK->yActMTU );
|
|
|
|
}
|
|
|
|
release_lock( &pPTPBLK->UpdateLock );
|
|
|
|
}
|
|
|
|
// Allocate a buffer in which the PTPHX0 will be build.
|
|
pPTPHDRx0 = alloc_ptp_buffer( pDEVBLK, SIZE_HX0 );
|
|
if (!pPTPHDRx0)
|
|
return;
|
|
pPTPHX0re = (PTPHX0*)((BYTE*)pPTPHDRx0 + SIZE_HDR);
|
|
|
|
// Allocate a buffer in which the PTPHX2 and PTPHSV will be build.
|
|
pPTPHDRx2 = alloc_ptp_buffer( pDEVBLK, 255 );
|
|
if (!pPTPHDRx2)
|
|
{
|
|
// Free the PTPHDR
|
|
free( pPTPHDRx0 );
|
|
return;
|
|
}
|
|
pPTPHX2re = (PTPHX2*)((BYTE*)pPTPHDRx2 + SIZE_HDR);
|
|
pPTPHSVre = (PTPHSV*)((BYTE*)pPTPHDRx2 + SIZE_HDR + SIZE_HX2);
|
|
|
|
// Allocate a buffer in which the literal 'VTAM' will be build.
|
|
pPTPHDRvt = alloc_ptp_buffer( pDEVBLK, 4 );
|
|
if (!pPTPHDRvt)
|
|
{
|
|
// Free the PTPHDRs
|
|
free( pPTPHDRx2 );
|
|
free( pPTPHDRx0 );
|
|
return;
|
|
}
|
|
pPTPVTMre = (BYTE*)pPTPHDRvt + SIZE_HDR;
|
|
|
|
// Prepare PTPHDRx0 and PTPHX0re
|
|
pPTPHDRx0->iDataLen = SIZE_HX0;
|
|
// PTPHX0
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_ONE ||
|
|
pPTPATH->fHandshakeCur == HANDSHAKE_TWO)
|
|
{
|
|
pPTPHX0re->TH_ch_flag = TH_CH_0x01;
|
|
}
|
|
else
|
|
{
|
|
pPTPHX0re->TH_ch_flag = TH_CH_0x00;
|
|
}
|
|
pPTPHX0re->TH_blk_flag = TH_DATA_IS_XID;
|
|
pPTPHX0re->TH_is_xid = TH_IS_0x01;
|
|
STORE_FW( pPTPHX0re->TH_SeqNum, PTPHX0_SEQNUM ); // !!! //
|
|
|
|
// Prepare PTPHDRx2 PTPHX2re and PTPHSVre
|
|
pPTPHDRx2->iDataLen = 255;
|
|
// XID2
|
|
pPTPHX2re->Ft = 0x20;
|
|
pPTPHX2re->Length = SIZE_HX2 + SIZE_HSV;
|
|
uNodeID = ( sysblk.cpuid >> 36 ) | 0xFFF00000;
|
|
STORE_FW( pPTPHX2re->NodeID, uNodeID );
|
|
pPTPHX2re->LenXcv = SIZE_HX2;
|
|
pPTPHX2re->ULPuse = 0x80;
|
|
memcpy( pPTPHX2re->SAaddress, pPTPBLK->xSAaddress, 4 );
|
|
if (pPTPATH->fHandshakeCur != HANDSHAKE_ONE)
|
|
{
|
|
pPTPHX2re->CLstatus = 0x07;
|
|
}
|
|
if (pPTPATH->bDLCtype == DLCTYPE_WRITE) // Destined for the y-side's Write path?
|
|
{
|
|
pPTPHX2re->DLCtype = DLCTYPE_READ; // This XID2 is from x-side's Read path
|
|
}
|
|
else
|
|
{
|
|
pPTPHX2re->DLCtype = DLCTYPE_WRITE; // This XID2 is from x-side's Write path
|
|
}
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_ONE && // The first exchange of handshaking and
|
|
pPTPATH->bDLCtype == DLCTYPE_WRITE) // destined for the y-side's Write path?
|
|
{
|
|
STORE_HW( pPTPHX2re->DataLen1, pPTPBLK->xDataLen1 );
|
|
STORE_HW( pPTPHX2re->MaxReadLen, pPTPBLK->xMaxReadLen );
|
|
}
|
|
pPTPHX2re->MpcFlag = 0x27;
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_ONE)
|
|
{
|
|
pPTPHX2re->TokenX5 = MPC_TOKEN_X5;
|
|
memcpy( pPTPHX2re->Token, pPTPBLK->xTokenIssuerRm, MPC_TOKEN_LENGTH );
|
|
}
|
|
else
|
|
{
|
|
pPTPHX2re->TokenX5 = MPC_TOKEN_X5;
|
|
memcpy( pPTPHX2re->Token, pPTPBLK->yTokenIssuerRm, MPC_TOKEN_LENGTH );
|
|
}
|
|
// CSVcv
|
|
pPTPHSVre->Length = SIZE_HSV;
|
|
pPTPHSVre->Key = CSV_KEY;
|
|
pPTPHSVre->LenSIDs = sizeof(pPTPHSVre->LenSIDs) +
|
|
sizeof(pPTPHSVre->SID1) + sizeof(pPTPHSVre->SID2);
|
|
memcpy( pPTPHSVre->SID1, &pPTPBLK->xStartTime, 8 ); // x-side's start time
|
|
if (pPTPATH->fHandshakeCur == HANDSHAKE_ONE)
|
|
{
|
|
memcpy( pPTPHSVre->SID2, &pPTPBLK->xFirstCsvSID2, 8 );
|
|
}
|
|
else
|
|
{
|
|
memcpy( pPTPHSVre->SID2, &pPTPBLK->xSecondCsvSID2, 8 );
|
|
}
|
|
|
|
// Prepare PTPHDRvt
|
|
pPTPHDRvt->iDataLen = 4;
|
|
memcpy( pPTPVTMre, &VTAM_ebcdic, 4 ); // 'VTAM' in EBCDIC
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out HX0" );
|
|
mpc_display_description( pDEVBLK, "Out HX2" );
|
|
}
|
|
|
|
// Add PTPHDRs to chain.
|
|
add_buffer_to_chain( pPTPATH, pPTPHDRx0 );
|
|
add_buffer_to_chain( pPTPATH, pPTPHDRx2 );
|
|
add_buffer_to_chain( pPTPATH, pPTPHDRvt );
|
|
|
|
}
|
|
else
|
|
{
|
|
// An XID2 is being written by the y-side but handshaking is
|
|
// not in progress on the path; we don't understand!
|
|
}
|
|
|
|
// Set residual byte count and unit status.
|
|
*pMore = 0;
|
|
*pResidual = 0;
|
|
*pUnitStat = CSW_CE | CSW_DE;
|
|
|
|
return;
|
|
} /* End function write_hx2() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* point_CSVcv() */
|
|
/* ------------------------------------------------------------------ */
|
|
// This function is probably overkill at present while the XID2 is
|
|
// followed immediately by the CSVcv. However, one day, there may be
|
|
// more than one cv...
|
|
|
|
PTPHSV* point_CSVcv( DEVBLK* pDEVBLK, PTPHX2* pPTPHX2 )
|
|
{
|
|
|
|
PTPHSV* pPTPHSV;
|
|
BYTE* pCurCv;
|
|
BYTE* pEndCv;
|
|
|
|
UNREFERENCED( pDEVBLK );
|
|
|
|
|
|
// Point to the first cv, point to the end of the cv's, and
|
|
// work down the cv's until we find the CSVcv.
|
|
pCurCv = (BYTE*)pPTPHX2 + pPTPHX2->LenXcv;
|
|
pEndCv = (BYTE*)pPTPHX2 + pPTPHX2->Length;
|
|
|
|
while( pCurCv < pEndCv )
|
|
{
|
|
pPTPHSV = (PTPHSV*)pCurCv;
|
|
if (pPTPHSV->Key == CSV_KEY)
|
|
break;
|
|
pCurCv += pPTPHSV->Length;
|
|
pPTPHSV = NULL;
|
|
}
|
|
|
|
return pPTPHSV;
|
|
} /* End function point_CSVcv() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_rrh_417E() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note - the Token is xTokenIssuerRm or xTokenCmConnection.
|
|
// In all cases that have been seen the MPC_RRH type 0x417E is
|
|
// followed by a single MPC_PH, which is followed by a single
|
|
// MPC_PUK, which is followed by up to four MPC_PUSs.
|
|
|
|
int write_rrh_417E( DEVBLK* pDEVBLK, MPC_TH* pMPC_THwr, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
PTPATH* pPTPATHre = pPTPBLK->pPTPATHRead;
|
|
PTPATH* pPTPATHwr = pPTPBLK->pPTPATHWrite;
|
|
MPC_PH* pMPC_PHwr; // MPC_PH being written
|
|
MPC_PUK* pMPC_PUKwr; // MPC_PUK being written
|
|
MPC_PUS* pMPC_PUSwr; // MPC_PUSs being written
|
|
U16 uOffPH;
|
|
// U32 uLenData;
|
|
U32 uOffData;
|
|
u_int fxSideWins;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
int iWhat;
|
|
#define UNKNOWN_PUK 0
|
|
#define CM_ENABLE 1
|
|
#define CM_SETUP 2
|
|
#define CM_CONFIRM 3
|
|
#define CM_DISABLE 4
|
|
#define CM_TAKEDOWN 5
|
|
#define ULP_ENABLE 6
|
|
#define ULP_SETUP 7
|
|
#define ULP_CONFIRM 8
|
|
#define ULP_DISABLE 9
|
|
#define ULP_TAKEDOWN 10
|
|
#define DM_ACT 11
|
|
|
|
|
|
// Point to the MPC_PH.
|
|
FETCH_HW( uOffPH, pMPC_RRHwr->offph );
|
|
pMPC_PHwr = (MPC_PH*)((BYTE*)pMPC_RRHwr + uOffPH);
|
|
|
|
// Get the length of and point to the data referenced by the
|
|
// MPC_PH. The data contain a MPC_PUK and one or more MPC_PUSs.
|
|
// FETCH_F3( uLenData, pMPC_PH->lendata );
|
|
FETCH_FW( uOffData, pMPC_PHwr->offdata );
|
|
pMPC_PUKwr = (MPC_PUK*)((BYTE*)pMPC_THwr + uOffData);
|
|
|
|
// Decide what the PUK contains.
|
|
iWhat = UNKNOWN_PUK;
|
|
if (memcmp( pMPC_RRHwr->token, pPTPBLK->xTokenIssuerRm, MPC_TOKEN_LENGTH ) == 0)
|
|
{
|
|
if (pMPC_PUKwr->what == PUK_WHAT_41)
|
|
{
|
|
if (pMPC_PUKwr->type == PUK_TYPE_ENABLE)
|
|
{
|
|
iWhat = CM_ENABLE;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_SETUP)
|
|
{
|
|
iWhat = CM_SETUP;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_CONFIRM)
|
|
{
|
|
iWhat = CM_CONFIRM;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_DISABLE)
|
|
{
|
|
iWhat = CM_DISABLE;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_TAKEDOWN)
|
|
{
|
|
iWhat = CM_TAKEDOWN;
|
|
}
|
|
}
|
|
}
|
|
else if (memcmp( pMPC_RRHwr->token, pPTPBLK->xTokenCmConnection, MPC_TOKEN_LENGTH ) == 0)
|
|
{
|
|
if (pMPC_PUKwr->what == PUK_WHAT_41)
|
|
{
|
|
if (pMPC_PUKwr->type == PUK_TYPE_ENABLE)
|
|
{
|
|
iWhat = ULP_ENABLE;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_SETUP)
|
|
{
|
|
iWhat = ULP_SETUP;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_CONFIRM)
|
|
{
|
|
iWhat = ULP_CONFIRM;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_DISABLE)
|
|
{
|
|
iWhat = ULP_DISABLE;
|
|
}
|
|
else if (pMPC_PUKwr->type == PUK_TYPE_TAKEDOWN)
|
|
{
|
|
iWhat = ULP_TAKEDOWN;
|
|
}
|
|
}
|
|
else if (pMPC_PUKwr->what == PUK_WHAT_43)
|
|
{
|
|
if (pMPC_PUKwr->type == PUK_TYPE_ACTIVE)
|
|
{
|
|
iWhat = DM_ACT;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process the PUK.
|
|
switch( iWhat )
|
|
{
|
|
|
|
// PUK 0x4102 to xTokenIssuerRm
|
|
// The MPC_PUK should be followed by three MPC_PUSs, the first a type
|
|
// 0x0401, the second a type 0x0402, and the third a type 0x040c.
|
|
case CM_ENABLE:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (Issuer) PUK 0x4102 (CM_ENABLE)" );
|
|
}
|
|
|
|
// Find the PUS and copy the yTokenCmFilter.
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_01 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (CM_ENABLE)", "PUS_01" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
memcpy( pPTPBLK->yTokenCmFilter, pMPC_PUSwr->vc.pus_01.token, MPC_TOKEN_LENGTH );
|
|
|
|
// Find the PUS that contains the 'bid' value.
|
|
// Build RRH 0x417E PUK 0x4102 to yTokenIssuerRm
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_02 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (CM_ENABLE)", "PUS_02" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
fxSideWins = FALSE;
|
|
pPTPHDRre = build_417E_cm_enable( pDEVBLK, pMPC_RRHwr, pMPC_PUSwr, &fxSideWins );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
// If this side 'wins' the 'handedness' this side must now send
|
|
// a RRH 0x417E PUK 0x4104 to yTokenIssuerRm on the other side.
|
|
// If the other side 'wins' the 'handedness' this side must now wait
|
|
// to receive a RRH 0x417E PUK 0x4104 to xTokenIssuerRm from the
|
|
// other side.
|
|
if (fxSideWins) // if the x-side wins
|
|
{
|
|
|
|
// Build RRH 0x417E PUK 0x4104 to yTokenIssuerRm
|
|
pPTPHDRre = build_417E_cm_setup( pDEVBLK, pMPC_RRHwr );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
// PUK 0x4104 to xTokenIssuerRm
|
|
// The MPC_PUK should be followed by three MPC_PUSs, the first a type
|
|
// 0x0404, the second a type 0x0405, and the third a type 0x0406.
|
|
case CM_SETUP:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (Issuer) PUK 0x4104 (CM_SETUP)" );
|
|
}
|
|
|
|
// Find the PUS and copy the yTokenCmConnection.
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_04 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (CM_SETUP)", "PUS_04" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
memcpy( pPTPBLK->yTokenCmConnection, pMPC_PUSwr->vc.pus_04.token, MPC_TOKEN_LENGTH );
|
|
|
|
// Build RRH 0x417E PUK 0x4106 to yTokenIssuerRm
|
|
pPTPHDRre = build_417E_cm_confirm( pDEVBLK, pMPC_RRHwr );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
// When the y-side receives the RRH 0x417E PUK 0x4106 the control
|
|
// process between the x-side and the y-side is active. On a connection
|
|
// between two VTAMs, the x-side VTAM sends messages from xTokenCmFilter
|
|
// to yTokenCmConnection, and the y-side VTAM sends messages from yTokenCmFilter
|
|
// to xTokenCmConnection. The x-side (i.e. Hercules) will now wait for the
|
|
// y-side VTAM to send a MSG 0x417E PUK 0x4102 to xTokenCmConnection to
|
|
// begin the setup of the communication process.
|
|
|
|
break;
|
|
|
|
// PUK 0x4106 to xTokenIssuerRm
|
|
// The MPC_PUK should be followed by three MPC_PUSs, the first a type
|
|
// 0x0404, the second a type 0x0408, and the third a type 0x0407.
|
|
case CM_CONFIRM:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (Issuer) PUK 0x4106 (CM_CONFIRM)" );
|
|
}
|
|
|
|
// Find the PUS and copy the yTokenCmConnection.
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_08 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (CM_CONFIRM)", "PUS_08" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
memcpy( pPTPBLK->yTokenCmConnection, pMPC_PUSwr->vc.pus_08.token, MPC_TOKEN_LENGTH );
|
|
|
|
// The control process between the x-side and the y-side is active. On
|
|
// a connection between two VTAMs, the x-side VTAM sends messages from
|
|
// xTokenCmFilter to yTokenCmConnection, and the y-side VTAM sends messages
|
|
// from yTokenCmFilter to xTokenCmConnection. The x-side (i.e. Hercules)
|
|
// will now wait for the y-side VTAM to send a MSG 0x417E PUK 0x4102
|
|
// to xTokenCmConnection to begin the setup of the communication process.
|
|
|
|
break;
|
|
|
|
// PUK 0x4103 to xTokenIssuerRm
|
|
// The MPC_PUK should be followed by a single MPC_PUS, a type 0x0403.
|
|
case CM_DISABLE:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (Issuer) PUK 0x4103 (CM_DISABLE)" );
|
|
}
|
|
|
|
break;
|
|
|
|
// PUK 0x4105 to xTokenIssuerRm
|
|
// The MPC_PUK should be followed by a single MPC_PUS, a type 0x0404.
|
|
case CM_TAKEDOWN:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (Issuer) PUK 0x4105 (CM_TAKEDOWN)" );
|
|
}
|
|
|
|
// The guest OS on the y-side has stopped the device
|
|
|
|
break;
|
|
|
|
// PUK 0x4102 to xTokenCmConnection
|
|
// The MPC_PUK should be followed by two MPC_PUSs, the first a type
|
|
// 0x0401 and the second a type 0x0402.
|
|
case ULP_ENABLE:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (CmComm) PUK 0x4102 (ULP_ENABLE)" );
|
|
}
|
|
|
|
// Find the PUS and copy the yTokenUlpFilter.
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_01 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (ULP_ENABLE)", "PUS_01" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
memcpy( pPTPBLK->yTokenUlpFilter, pMPC_PUSwr->vc.pus_01.token, MPC_TOKEN_LENGTH );
|
|
|
|
// Find the PUS that contains the 'bid' value.
|
|
// Build RRH 0x417E PUK 0x4102 to yTokenCmConnection
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_02 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (ULP_ENABLE)", "PUS_02" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
fxSideWins = FALSE;
|
|
pPTPHDRre = build_417E_ulp_enable( pDEVBLK, pMPC_RRHwr, pMPC_PUSwr, &fxSideWins );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
// If this side 'wins' the 'handedness' this side must now send
|
|
// a RRH 0x417E PUK 0x4104 to yTokenCmConnection on the other side.
|
|
// If the other side 'wins' the 'handedness' this side must now wait
|
|
// to receive a RRH 0x417E PUK 0x4104 to xTokenCmConnection from the
|
|
// other side.
|
|
if (fxSideWins) // if the x-side wins
|
|
{
|
|
|
|
// Build RRH 0x417E PUK 0x4104 to yTokenCmConnection
|
|
pPTPHDRre = build_417E_ulp_setup( pDEVBLK, pMPC_RRHwr );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
// PUK 0x4104 to xTokenCmConnection
|
|
// The MPC_PUK should be followed by four MPC_PUSs, the first a type
|
|
// 0x0404, the second a type 0x0405, the third a type 0x0406, and
|
|
// the fourth a type 0x0402.
|
|
case ULP_SETUP:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (CmComm) PUK 0x4104 (ULP_SETUP)" );
|
|
}
|
|
|
|
// Find the PUS and copy the yTokenUlpConnection.
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_04 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (ULP_SETUP)", "PUS_04" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
memcpy( pPTPBLK->yTokenUlpConnection, pMPC_PUSwr->vc.pus_04.token, MPC_TOKEN_LENGTH );
|
|
|
|
// Build RRH 0x417E PUK 0x4106 to yTokenCmConnection
|
|
pPTPHDRre = build_417E_ulp_confirm( pDEVBLK, pMPC_RRHwr );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
// Build RRH 0x417E PUK 0x4360 to yTokenCmConnection
|
|
pPTPHDRre = build_417E_dm_act( pDEVBLK, pMPC_RRHwr );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
break;
|
|
|
|
// PUK 0x4106 to xTokenCmConnection
|
|
// The MPC_PUK should be followed by four MPC_PUSs, the first a type
|
|
// 0x0404, the second a type 0x0408, the third a type 0x0407, and
|
|
// the fourth a type 0x0402.
|
|
case ULP_CONFIRM:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (CmComm) PUK 0x4106 (ULP_CONFIRM)" );
|
|
}
|
|
|
|
// Find the PUS and copy the yTokenUlpConnection.
|
|
pMPC_PUSwr = mpc_point_pus( pDEVBLK, pMPC_PUKwr, PUS_TYPE_08 );
|
|
if (!pMPC_PUSwr)
|
|
{
|
|
// HHC03937 "%1d:%04X PTP: Accept data contains %s that does not contain expected %s"
|
|
WRMSG(HHC03937, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK (ULP_CONFIRM)", "PUS_08" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
break;
|
|
}
|
|
memcpy( pPTPBLK->yTokenUlpConnection, pMPC_PUSwr->vc.pus_08.token, MPC_TOKEN_LENGTH );
|
|
|
|
// Build RRH 0x417E PUK 0x4360 to yTokenCmConnection
|
|
pPTPHDRre = build_417E_dm_act( pDEVBLK, pMPC_RRHwr );
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
break;
|
|
|
|
// PUK 0x4360 to xTokenCmConnection
|
|
// The MPC_PUK should be followed by a single MPC_PUS, a type 0x0404.
|
|
case DM_ACT:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (CmComm) PUK 0x4360 (DM_ACT)" );
|
|
}
|
|
|
|
break;
|
|
|
|
// PUK 0x4103 to xTokenCmConnection
|
|
// The MPC_PUK should be followed by a single MPC_PUS, a type 0x0403.
|
|
case ULP_DISABLE:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (CmComm) PUK 0x4103 (ULP_DISABLE)" );
|
|
}
|
|
|
|
break;
|
|
|
|
// PUK 0x4105 to xTokenCmConnection
|
|
// The MPC_PUK should be followed by a single MPC_PUS, a type 0x0404.
|
|
case ULP_TAKEDOWN:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0x417E (CmComm) PUK 0x4105 (ULP_TAKEDOWN)" );
|
|
}
|
|
|
|
// The guest OS on the y-side has stopped the device
|
|
if (pPTPBLK->fActive4)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
}
|
|
pPTPBLK->fActive4 = FALSE;
|
|
pPTPBLK->bActivate4 = 0x00;
|
|
pPTPBLK->bTerminate4 = 0x00;
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fActive6)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pPTPBLK->fActive6 = FALSE;
|
|
pPTPBLK->bActivate6 = 0x00;
|
|
pPTPBLK->bTerminate6 = 0x00;
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fActiveLL6)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestLLAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pPTPBLK->fActiveLL6 = FALSE;
|
|
pPTPBLK->bActivateLL6 = 0x00;
|
|
pPTPBLK->bTerminateLL6 = 0x00;
|
|
// Dispose of any data waiting to be read by the y-side.
|
|
// Free any PTPHDR on the chain for the read path
|
|
remove_and_free_any_buffers_on_chain( pPTPATHre );
|
|
// Reset the message sequence number
|
|
pPTPATHre->uSeqNum = 0;
|
|
// Free any PTPHDR on the chain for the write path
|
|
remove_and_free_any_buffers_on_chain( pPTPATHwr );
|
|
// Reset the message sequence number
|
|
pPTPATHwr->uSeqNum = 0;
|
|
|
|
break;
|
|
|
|
// Unknown PUK
|
|
default:
|
|
|
|
// HHC03936 "%1d:%04X PTP: Accept data contains unknown %s"
|
|
WRMSG(HHC03936, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
|
|
break;
|
|
|
|
} /* switch( iWhat ) */
|
|
|
|
|
|
return 0;
|
|
} /* End function write_rrh_417E() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_cm_enable() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4102 to yTokenIssuerRm
|
|
|
|
PTPHDR* build_417E_cm_enable( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr,
|
|
MPC_PUS* pMPC_PUSwr, u_int* fxSideWins )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre[3]; // MPC_PUSs follow MPC_PUK
|
|
U64 uTod;
|
|
int rc;
|
|
|
|
UNREFERENCED( pMPC_RRHwr );
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_01 + // first MPC_PUS (0x0401)
|
|
SIZE_PUS_02_A + // second MPC_PUS (0x0402)
|
|
SIZE_PUS_0C; // third MPC_PUS (0x040c)
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and the MPC_PUSs (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre[0] = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
pMPC_PUSre[1] = (MPC_PUS*)((BYTE*)pMPC_PUSre[0] + SIZE_PUS_01);
|
|
pMPC_PUSre[2] = (MPC_PUS*)((BYTE*)pMPC_PUSre[1] + SIZE_PUS_02_A);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumIssuer );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenIssuerRm, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_41;
|
|
pMPC_PUKre->type = PUK_TYPE_ENABLE;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[0]->length, SIZE_PUS_01 );
|
|
pMPC_PUSre[0]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[0]->type = PUS_TYPE_01;
|
|
pMPC_PUSre[0]->vc.pus_01.proto = PROTOCOL_UNKNOWN;
|
|
pMPC_PUSre[0]->vc.pus_01.unknown05 = 0x01; // !!! //
|
|
pMPC_PUSre[0]->vc.pus_01.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[0]->vc.pus_01.token, pPTPBLK->xTokenCmFilter, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare second MPC_PUSre
|
|
// Note: the 8-byte value placed in the second MPC_PUS is important.
|
|
// Whichever side has the highest value 'wins', and dictates the
|
|
// 'handedness' of the RRH 0x417E exchanges. If this code 'wins'
|
|
// and then acts like a 'loser', confusion reigns, to the extent
|
|
// that VTAM on the y-side will not shutdown because it thinks
|
|
// the link is still active. Presumably we could always return
|
|
// 0xFF's, but hey...
|
|
STORE_HW( pMPC_PUSre[1]->length, SIZE_PUS_02_A );
|
|
pMPC_PUSre[1]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[1]->type = PUS_TYPE_02;
|
|
ptp_get_tod_clock( pMPC_PUSre[1]->vc.pus_02.a.clock ); // x-side's time
|
|
|
|
// Prepare third MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[2]->length, SIZE_PUS_0C );
|
|
pMPC_PUSre[2]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[2]->type = PUS_TYPE_0C;
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[0] = 0x00; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[1] = 0x09; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[2] = 0x00; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[3] = 0x06; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[4] = 0x04; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[5] = 0x01; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[6] = 0x03; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[7] = 0x04; // !!! //
|
|
pMPC_PUSre[2]->vc.pus_0C.unknown04[8] = 0x08; // !!! //
|
|
|
|
// Compare the tod clock value in the MPC_PUSwr with the tod clock
|
|
// value in the second MPC_PUSre to determine which side wins.
|
|
rc = memcmp( pMPC_PUSwr->vc.pus_02.a.clock,
|
|
pMPC_PUSre[1]->vc.pus_02.a.clock,
|
|
sizeof(pMPC_PUSwr->vc.pus_02.a.clock) );
|
|
if (rc < 0)
|
|
// This should be the normal case; the other side must have
|
|
// obtained the tod clock a few moments ago for it to be in the
|
|
// message we recently received.
|
|
*fxSideWins = TRUE; // i.e. the x-side wins
|
|
else if (rc > 0)
|
|
// This shouldn't happen; the tod clock we have just obtained is
|
|
// earlier than the tod clock in the message we recently received.
|
|
// Presumably it wasn't a tod clock, or it was manipulated somehow.
|
|
*fxSideWins = FALSE; // i.e. the y-side wins
|
|
else
|
|
{
|
|
// This shouldn't happen; the tod clock we have just obtained is
|
|
// equal to the tod clock in the message we recently received.
|
|
// Perhaps Hercules hasn't updated the tod clock for ages, though
|
|
// that seems unlikely, so assume it was manipulated somehow.
|
|
FETCH_DW( uTod, pMPC_PUSre[1]->vc.pus_02.a.clock ); // get x-side's time
|
|
uTod += 0x0000000000000001; // Add a tiny amount
|
|
STORE_DW( pMPC_PUSre[1]->vc.pus_02.a.clock, uTod ); // set x-side's time
|
|
*fxSideWins = TRUE; // the x-side wins
|
|
}
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (Issuer) PUK 0x4102 (CM_ENABLE)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_cm_enable() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_cm_setup() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4104 to yTokenIssuerRm
|
|
|
|
PTPHDR* build_417E_cm_setup( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre[3]; // MPC_PUSs follow MPC_PUK
|
|
|
|
|
|
// Allocate a buffer.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_04 + // first MPC_PUS (0x0404)
|
|
SIZE_PUS_05 + // second MPC_PUS (0x0405)
|
|
SIZE_PUS_06; // third MPC_PUS (0x0406)
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and the MPC_PUSs (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre[0] = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
pMPC_PUSre[1] = (MPC_PUS*)((BYTE*)pMPC_PUSre[0] + SIZE_PUS_04);
|
|
pMPC_PUSre[2] = (MPC_PUS*)((BYTE*)pMPC_PUSre[1] + SIZE_PUS_05);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumIssuer );
|
|
memcpy( pMPC_RRHre->ackseq, pMPC_RRHwr->seqnum, 4 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenIssuerRm, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_41;
|
|
pMPC_PUKre->type = PUK_TYPE_SETUP;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[0]->length, SIZE_PUS_04 );
|
|
pMPC_PUSre[0]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[0]->type = PUS_TYPE_04;
|
|
pMPC_PUSre[0]->vc.pus_04.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[0]->vc.pus_04.token, pPTPBLK->xTokenCmConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare second MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[1]->length, SIZE_PUS_05 );
|
|
pMPC_PUSre[1]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[1]->type = PUS_TYPE_05;
|
|
pMPC_PUSre[1]->vc.pus_05.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[1]->vc.pus_05.token, pPTPBLK->yTokenCmFilter, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare third MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[2]->length, SIZE_PUS_06 );
|
|
pMPC_PUSre[2]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[2]->type = PUS_TYPE_06;
|
|
pMPC_PUSre[2]->vc.pus_06.unknown04[0] = 0xC8; // !!! //
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (Issuer) PUK 0x4104 (CM_SETUP)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_cm_setup() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_cm_confirm() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4106 to yTokenIssuerRm
|
|
|
|
PTPHDR* build_417E_cm_confirm( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre[3]; // MPC_PUSs follow MPC_PUK
|
|
|
|
|
|
// Allocate a buffer.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_04 + // first MPC_PUS (0x0404)
|
|
SIZE_PUS_08 + // second MPC_PUS (0x0408)
|
|
SIZE_PUS_07; // third MPC_PUS (0x0407)
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and the MPC_PUSs (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre[0] = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
pMPC_PUSre[1] = (MPC_PUS*)((BYTE*)pMPC_PUSre[0] + SIZE_PUS_04);
|
|
pMPC_PUSre[2] = (MPC_PUS*)((BYTE*)pMPC_PUSre[1] + SIZE_PUS_08);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumIssuer );
|
|
memcpy( pMPC_RRHre->ackseq, pMPC_RRHwr->seqnum, 4 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenIssuerRm, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_41;
|
|
pMPC_PUKre->type = PUK_TYPE_CONFIRM;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[0]->length, SIZE_PUS_04 );
|
|
pMPC_PUSre[0]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[0]->type = PUS_TYPE_04;
|
|
pMPC_PUSre[0]->vc.pus_04.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[0]->vc.pus_04.token, pPTPBLK->yTokenCmConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare second MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[1]->length, SIZE_PUS_08 );
|
|
pMPC_PUSre[1]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[1]->type = PUS_TYPE_08;
|
|
pMPC_PUSre[1]->vc.pus_08.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[1]->vc.pus_08.token, pPTPBLK->xTokenCmFilter, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare third MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[2]->length, SIZE_PUS_07 );
|
|
pMPC_PUSre[2]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[2]->type = PUS_TYPE_07;
|
|
pMPC_PUSre[2]->vc.pus_07.unknown04[0] = 0xC8; // !!! //
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (Issuer) PUK 0x4106 (CM_CONFIRM)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_cm_confirm() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_ulp_enable() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4102 to yTokenCmConnection
|
|
|
|
PTPHDR* build_417E_ulp_enable( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr,
|
|
MPC_PUS* pMPC_PUSwr, u_int* fxSideWins )
|
|
{
|
|
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre[2]; // MPC_PUSs follow MPC_PUK
|
|
int rc;
|
|
|
|
UNREFERENCED( pMPC_RRHwr );
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_01 + // first MPC_PUS (0x0401)
|
|
SIZE_PUS_02_B; // second MPC_PUS (0x0402)
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and the MPC_PUSs (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre[0] = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
pMPC_PUSre[1] = (MPC_PUS*)((BYTE*)pMPC_PUSre[0] + SIZE_PUS_01);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumCm );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenCmConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_41;
|
|
pMPC_PUKre->type = PUK_TYPE_ENABLE;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[0]->length, SIZE_PUS_01 );
|
|
pMPC_PUSre[0]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[0]->type = PUS_TYPE_01;
|
|
pMPC_PUSre[0]->vc.pus_01.proto = PROTOCOL_LAYER2;
|
|
pMPC_PUSre[0]->vc.pus_01.unknown05 = 0x01; // !!! //
|
|
pMPC_PUSre[0]->vc.pus_01.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[0]->vc.pus_01.token, pPTPBLK->xTokenUlpFilter, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare second MPC_PUSre
|
|
// Note: the 40-bytes placed in the second MPC_PUS are important.
|
|
// Whichever side has the lowest value 'wins', and dictates the
|
|
// 'handedness' of the RRH 0x417E exchanges. If this code 'wins'
|
|
// and then acts like a 'loser', confusion reigns.
|
|
STORE_HW( pMPC_PUSre[1]->length, SIZE_PUS_02_B );
|
|
pMPC_PUSre[1]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[1]->type = PUS_TYPE_02;
|
|
pMPC_PUSre[1]->vc.pus_02.b.unknown04 = 0x02; // !!! //
|
|
pMPC_PUSre[1]->vc.pus_02.b.flags = 0x90; // !!! //
|
|
pMPC_PUSre[1]->vc.pus_02.b.unknown0A = 0x40; // !!! //
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
memcpy( pMPC_PUSre[1]->vc.pus_02.b.ipaddr, &pPTPBLK->iaDriveIPAddr4, 4 );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
else
|
|
{
|
|
pMPC_PUSre[1]->vc.pus_02.b.flags |= 0x08;
|
|
memcpy( pMPC_PUSre[1]->vc.pus_02.b.ipaddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
// Compare the IP address in the MPC_PUSwr with the IP address in
|
|
// the second MPC_PUSre to determine which side wins. First, check
|
|
// whether both sides are using the same variety of IP address.
|
|
if (( pMPC_PUSwr->vc.pus_02.b.flags & 0x08 ) == ( pMPC_PUSre[1]->vc.pus_02.b.flags & 0x08 ))
|
|
{
|
|
// Both sides are using the same variety of IP address.
|
|
rc = memcmp( &pMPC_PUSwr->vc.pus_02.b.ipaddr, &pMPC_PUSre[1]->vc.pus_02.b.ipaddr, 16 );
|
|
if (rc < 0)
|
|
// The y-side's IP address is lower than the x-side's.
|
|
*fxSideWins = TRUE; // i.e. the x-side wins
|
|
else if (rc > 0)
|
|
// The y-side's IP address is higher than the x-side's.
|
|
*fxSideWins = FALSE; // i.e. the y-side wins
|
|
else
|
|
// This shouldn't happen; the y-side and the x-side have the
|
|
// same IP address! Empirical evidence suggests that in
|
|
// these circumstances each side believes that it has the
|
|
// lower address. As a result communication between them
|
|
// stalls, with each side waiting for the other side to send
|
|
// the next message. Presumably the VTAM coders didn't think
|
|
// anyone would be daft enough to give both sides the same
|
|
// IP address, or possibly they didn't think of it at all.
|
|
// Until a stop command is issued on the y-side nothing else
|
|
// will happen. However, to prevent that unhappy situation
|
|
// we will deem ourselves the winner.
|
|
*fxSideWins = TRUE; // i.e. the x-side wins
|
|
}
|
|
else
|
|
{
|
|
// One side is using an IPv4 address, the other an IPv6 address.
|
|
// This is normal behaviour when one side is starting both the
|
|
// IPv4 and IPv6 connections, and the other is only starting the
|
|
// IPv6 connection. The side that is using the IPv4 address is
|
|
// the winner. Check the y-side's variety of IP address.
|
|
if (( pMPC_PUSwr->vc.pus_02.b.flags & 0x08 ) == 0x08)
|
|
*fxSideWins = TRUE; // i.e. the x-side wins, it's using IPv4
|
|
else
|
|
*fxSideWins = FALSE; // i.e. the y-side wins, it's using IPv4
|
|
}
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (CmComm) PUK 0x4102 (ULP_ENABLE)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_ulp_enable() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_ulp_setup() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4104 to yTokenCmConnection
|
|
|
|
PTPHDR* build_417E_ulp_setup( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre[4]; // MPC_PUSs follow MPC_PUK
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_04 + // first MPC_PUS (0x0404)
|
|
SIZE_PUS_05 + // second MPC_PUS (0x0405)
|
|
SIZE_PUS_06 + // third MPC_PUS (0x0406)
|
|
SIZE_PUS_02_B; // fourth MPC_PUS (0x0402)
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and the MPC_PUSs (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre[0] = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
pMPC_PUSre[1] = (MPC_PUS*)((BYTE*)pMPC_PUSre[0] + SIZE_PUS_04);
|
|
pMPC_PUSre[2] = (MPC_PUS*)((BYTE*)pMPC_PUSre[1] + SIZE_PUS_05);
|
|
pMPC_PUSre[3] = (MPC_PUS*)((BYTE*)pMPC_PUSre[2] + SIZE_PUS_06);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumCm );
|
|
memcpy( pMPC_RRHre->ackseq, pMPC_RRHwr->seqnum, 4 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenCmConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_41;
|
|
pMPC_PUKre->type = PUK_TYPE_SETUP;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[0]->length, SIZE_PUS_04 );
|
|
pMPC_PUSre[0]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[0]->type = PUS_TYPE_04;
|
|
pMPC_PUSre[0]->vc.pus_04.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[0]->vc.pus_04.token, pPTPBLK->xTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare second MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[1]->length, SIZE_PUS_05 );
|
|
pMPC_PUSre[1]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[1]->type = PUS_TYPE_05;
|
|
pMPC_PUSre[1]->vc.pus_05.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[1]->vc.pus_05.token, pPTPBLK->yTokenUlpFilter, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare third MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[2]->length, SIZE_PUS_06 );
|
|
pMPC_PUSre[2]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[2]->type = PUS_TYPE_06;
|
|
pMPC_PUSre[2]->vc.pus_06.unknown04[0] = 0x40; // !!! //
|
|
|
|
// Prepare fourth MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[3]->length, SIZE_PUS_02_B );
|
|
pMPC_PUSre[3]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[3]->type = PUS_TYPE_02;
|
|
pMPC_PUSre[3]->vc.pus_02.b.unknown04 = 0x02; // !!! //
|
|
pMPC_PUSre[3]->vc.pus_02.b.flags = 0x90; // !!! //
|
|
pMPC_PUSre[3]->vc.pus_02.b.unknown0A = 0x40; // !!! //
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
memcpy( pMPC_PUSre[3]->vc.pus_02.b.ipaddr, &pPTPBLK->iaDriveIPAddr4, 4 );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
else
|
|
{
|
|
pMPC_PUSre[1]->vc.pus_02.b.flags |= 0x08;
|
|
memcpy( pMPC_PUSre[3]->vc.pus_02.b.ipaddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (CmComm) PUK 0x4104 (ULP_SETUP)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_ulp_setup() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_ulp_confirm() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4106 to yTokenCmConnection
|
|
|
|
PTPHDR* build_417E_ulp_confirm( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre[4]; // MPC_PUSs follow MPC_PUK
|
|
|
|
|
|
// Allocate a buffer.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_04 + // first MPC_PUS (0x0404)
|
|
SIZE_PUS_08 + // second MPC_PUS (0x0408)
|
|
SIZE_PUS_07 + // third MPC_PUS (0x0407)
|
|
SIZE_PUS_02_B; // fourth MPC_PUS (0x0402)
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and the MPC_PUSs (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre[0] = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
pMPC_PUSre[1] = (MPC_PUS*)((BYTE*)pMPC_PUSre[0] + SIZE_PUS_04);
|
|
pMPC_PUSre[2] = (MPC_PUS*)((BYTE*)pMPC_PUSre[1] + SIZE_PUS_08);
|
|
pMPC_PUSre[3] = (MPC_PUS*)((BYTE*)pMPC_PUSre[2] + SIZE_PUS_07);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumCm );
|
|
memcpy( pMPC_RRHre->ackseq, pMPC_RRHwr->seqnum, 4 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenCmConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_41;
|
|
pMPC_PUKre->type = PUK_TYPE_CONFIRM;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[0]->length, SIZE_PUS_04 );
|
|
pMPC_PUSre[0]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[0]->type = PUS_TYPE_04;
|
|
pMPC_PUSre[0]->vc.pus_04.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[0]->vc.pus_04.token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare second MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[1]->length, SIZE_PUS_08 );
|
|
pMPC_PUSre[1]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[1]->type = PUS_TYPE_08;
|
|
pMPC_PUSre[1]->vc.pus_08.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre[1]->vc.pus_08.token, pPTPBLK->xTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare third MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[2]->length, SIZE_PUS_07 );
|
|
pMPC_PUSre[2]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[2]->type = PUS_TYPE_07;
|
|
pMPC_PUSre[2]->vc.pus_07.unknown04[0] = 0x40; // !!! //
|
|
|
|
// Prepare fourth MPC_PUSre
|
|
STORE_HW( pMPC_PUSre[3]->length, SIZE_PUS_02_B );
|
|
pMPC_PUSre[3]->what = PUS_WHAT_04;
|
|
pMPC_PUSre[3]->type = PUS_TYPE_02;
|
|
pMPC_PUSre[3]->vc.pus_02.b.unknown04 = 0x02; // !!! //
|
|
pMPC_PUSre[3]->vc.pus_02.b.flags = 0x90; // !!! //
|
|
pMPC_PUSre[3]->vc.pus_02.b.unknown0A = 0x40; // !!! //
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
memcpy( pMPC_PUSre[3]->vc.pus_02.b.ipaddr, &pPTPBLK->iaDriveIPAddr4, 4 );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
else
|
|
{
|
|
pMPC_PUSre[1]->vc.pus_02.b.flags |= 0x08;
|
|
memcpy( pMPC_PUSre[3]->vc.pus_02.b.ipaddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (CmComm) PUK 0x4106 (ULP_CONFIRM)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_ulp_confirm() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_417E_dm_act() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0x417E PUK 0x4360 to yTokenCmConnection
|
|
|
|
PTPHDR* build_417E_dm_act( DEVBLK* pDEVBLK, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PUK* pMPC_PUKre; // MPC_PUK follows MPC_PH
|
|
MPC_PUS* pMPC_PUSre; // MPC_PUS follows MPC_PUK
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength4 = SIZE_PUS_04; // the MPC_PUS
|
|
uLength3 = SIZE_PUK + uLength4; // the MPC_PUK and MPC_PUS (the data)
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PUKre = (MPC_PUK*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pMPC_PUSre = (MPC_PUS*)((BYTE*)pMPC_PUKre + SIZE_PUK);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_ULP;
|
|
pMPC_RRHre->proto = PROTOCOL_UNKNOWN;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_FW( pMPC_RRHre->seqnum, ++pPTPBLK->uSeqNumCm );
|
|
memcpy( pMPC_RRHre->ackseq, pMPC_RRHwr->seqnum, 4 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenCmConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PUKre
|
|
STORE_HW( pMPC_PUKre->length, SIZE_PUK );
|
|
pMPC_PUKre->what = PUK_WHAT_43;
|
|
pMPC_PUKre->type = PUK_TYPE_ACTIVE;
|
|
STORE_HW( pMPC_PUKre->lenpus, uLength4 );
|
|
|
|
// Prepare first MPC_PUSre
|
|
STORE_HW( pMPC_PUSre->length, SIZE_PUS_04 );
|
|
pMPC_PUSre->what = PUS_WHAT_04;
|
|
pMPC_PUSre->type = PUS_TYPE_04;
|
|
pMPC_PUSre->vc.pus_04.tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_PUSre->vc.pus_04.token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x417E (CmComm) PUK 0x4360 (DM_ACT)" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_417E_dm_act() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_rrh_C17E() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note - the Token is xTokenIssuerRm (in all cases that have been seen).
|
|
// In all cases that have been seen the MPC_RRH type 0xC17E is followed
|
|
// by a single MPC_PH, which is followed by a single MPC_PUK, which is
|
|
// followed by two MPC_PUSs.
|
|
|
|
int write_rrh_C17E( DEVBLK* pDEVBLK, MPC_TH* pMPC_THwr, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
MPC_PH* pMPC_PHwr; // MPC_PH being written
|
|
MPC_PUK* pMPC_PUKwr; // MPC_PUK being written
|
|
// MPC_PUS* pMPC_PUSwr; // MPC_PUSs being written
|
|
U16 uOffPH;
|
|
// U32 uLenData;
|
|
U32 uOffData;
|
|
int iWhat;
|
|
#define PUK_4501 1
|
|
|
|
|
|
// Point to the MPC_PH.
|
|
FETCH_HW( uOffPH, pMPC_RRHwr->offph );
|
|
pMPC_PHwr = (MPC_PH*)((BYTE*)pMPC_RRHwr + uOffPH);
|
|
|
|
// Get the length of and point to the data referenced by the
|
|
// MPC_PH. The data contain a MPC_PUK and one or more MPC_PUSs.
|
|
// FETCH_F3( uLenData, pMPC_PH->lendata );
|
|
FETCH_FW( uOffData, pMPC_PHwr->offdata );
|
|
pMPC_PUKwr = (MPC_PUK*)((BYTE*)pMPC_THwr + uOffData);
|
|
|
|
// Decide what the PUK contains.
|
|
iWhat = UNKNOWN_PUK;
|
|
if (memcmp( pMPC_RRHwr->token, pPTPBLK->xTokenIssuerRm, MPC_TOKEN_LENGTH ) == 0)
|
|
{
|
|
if (pMPC_PUKwr->what == PUK_WHAT_45)
|
|
{
|
|
if (pMPC_PUKwr->type == PUK_TYPE_01)
|
|
{
|
|
iWhat = PUK_4501;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process the PUK.
|
|
switch( iWhat )
|
|
{
|
|
|
|
// PUK 0x4501 to xTokenIssuerRm
|
|
// The MPC_PUK should be followed by two MPC_PUSs, the first a type
|
|
// 0x0409 and the second a type 0x0404.
|
|
case PUK_4501:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC17E (Issuer)" );
|
|
}
|
|
|
|
break;
|
|
|
|
// Unknown PUK
|
|
default:
|
|
|
|
// HHC03936 "%1d:%04X PTP: Accept data contains unknown %s"
|
|
WRMSG(HHC03936, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PUK" );
|
|
mpc_display_rrh_and_puk( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
|
|
break;
|
|
|
|
} /* switch( iWhat ) */
|
|
|
|
return 0;
|
|
} /* End function write_rrh_C17E() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* write_rrh_C108() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Note - the Token is xTokenUlpConnection.
|
|
// In all cases that have been seen the MPC_RRH type 0xC108 is followed
|
|
// by a single MPC_PH, which is followed by a single MPC_PIX.
|
|
|
|
int write_rrh_C108( DEVBLK* pDEVBLK, MPC_TH* pMPC_THwr, MPC_RRH* pMPC_RRHwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
PTPATH* pPTPATHre = pPTPBLK->pPTPATHRead;
|
|
MPC_PH* pMPC_PHwr;
|
|
MPC_PIX* pMPC_PIXwr;
|
|
U32 uOffData;
|
|
// U32 uLenData;
|
|
U16 uOffPH;
|
|
#if defined(ENABLE_IPV6)
|
|
u_int fLL;
|
|
struct in6_addr addr6;
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
struct in_addr addr4;
|
|
char cIPaddr[48];
|
|
PTPHDR* pPTPHDRr1;
|
|
PTPHDR* pPTPHDRr2;
|
|
#if defined(ENABLE_IPV6)
|
|
PTPHDR* pPTPHDRr3;
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
int iWhat;
|
|
#define UNKNOWN_PIX 0
|
|
#define WILL_YOU_START_IPV4 1
|
|
#define WILL_YOU_START_IPV6 2
|
|
#define I_WILL_START_IPV4 3
|
|
#define I_WILL_START_IPV6 4
|
|
#define MY_ADDRESS_IPV4 5
|
|
#define MY_ADDRESS_IPV6 6
|
|
#define YOUR_ADDRESS_IPV4 7
|
|
#define YOUR_ADDRESS_IPV6 8
|
|
#define WILL_YOU_STOP_IPV4 9
|
|
#define WILL_YOU_STOP_IPV6 10
|
|
#define I_WILL_STOP_IPV4 11
|
|
#define I_WILL_STOP_IPV6 12
|
|
|
|
|
|
// Point to the MPC_PH.
|
|
FETCH_HW( uOffPH, pMPC_RRHwr->offph );
|
|
pMPC_PHwr = (MPC_PH*)((BYTE*)pMPC_RRHwr + uOffPH);
|
|
|
|
// Get the length of and point to the data referenced by the
|
|
// MPC_PH. The data is a MPC_PIX.
|
|
// FETCH_F3( uLenData, pMPC_PH->lendata );
|
|
FETCH_FW( uOffData, pMPC_PHwr->offdata );
|
|
pMPC_PIXwr = (MPC_PIX*)((BYTE*)pMPC_THwr + uOffData);
|
|
|
|
// Decide what the PIX contains.
|
|
iWhat = UNKNOWN_PIX;
|
|
if (pMPC_PIXwr->action == PIX_START)
|
|
{
|
|
if (pMPC_PIXwr->askans == PIX_ASK)
|
|
{
|
|
if (pMPC_PIXwr->iptype == PIX_IPV4)
|
|
iWhat = WILL_YOU_START_IPV4;
|
|
else if (pMPC_PIXwr->iptype == PIX_IPV6)
|
|
iWhat = WILL_YOU_START_IPV6;
|
|
}
|
|
else if (pMPC_PIXwr->askans == PIX_ANSWER)
|
|
{
|
|
if (pMPC_PIXwr->iptype == PIX_IPV4)
|
|
iWhat = I_WILL_START_IPV4;
|
|
else if (pMPC_PIXwr->iptype == PIX_IPV6)
|
|
iWhat = I_WILL_START_IPV6;
|
|
}
|
|
}
|
|
else if (pMPC_PIXwr->action == PIX_ADDRESS)
|
|
{
|
|
if (pMPC_PIXwr->askans == PIX_ASK)
|
|
{
|
|
if (pMPC_PIXwr->iptype == PIX_IPV4)
|
|
iWhat = MY_ADDRESS_IPV4;
|
|
else if (pMPC_PIXwr->iptype == PIX_IPV6)
|
|
iWhat = MY_ADDRESS_IPV6;
|
|
}
|
|
if (pMPC_PIXwr->askans == PIX_ANSWER)
|
|
{
|
|
if (pMPC_PIXwr->iptype == PIX_IPV4)
|
|
iWhat = YOUR_ADDRESS_IPV4;
|
|
else if (pMPC_PIXwr->iptype == PIX_IPV6)
|
|
iWhat = YOUR_ADDRESS_IPV6;
|
|
}
|
|
}
|
|
else if (pMPC_PIXwr->action == PIX_STOP)
|
|
{
|
|
if (pMPC_PIXwr->askans == PIX_ASK)
|
|
{
|
|
if (pMPC_PIXwr->iptype == PIX_IPV4)
|
|
iWhat = WILL_YOU_STOP_IPV4;
|
|
else if (pMPC_PIXwr->iptype == PIX_IPV6)
|
|
iWhat = WILL_YOU_STOP_IPV6;
|
|
}
|
|
else if (pMPC_PIXwr->askans == PIX_ANSWER)
|
|
{
|
|
if (pMPC_PIXwr->iptype == PIX_IPV4)
|
|
iWhat = I_WILL_STOP_IPV4;
|
|
else if (pMPC_PIXwr->iptype == PIX_IPV6)
|
|
iWhat = I_WILL_STOP_IPV6;
|
|
}
|
|
}
|
|
|
|
// Process what the PIX contains.
|
|
switch( iWhat )
|
|
{
|
|
|
|
case WILL_YOU_START_IPV4:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) Will you start IPv4?" );
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= HEASKEDME_START;
|
|
|
|
// Build RRH 0xC108 PIX 0x0101 to yTokenUlpConnection (I will start IPv4)
|
|
pPTPHDRr1 = build_C108_i_will_start_4( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= IANSWEREDHIM_START;
|
|
|
|
// Add PTPHDRs to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
|
|
// We have said we will start IPv4, but if IPv4 was not specified
|
|
// that's all we will do. The y-side will wait patiently for our
|
|
// will you start IPv4, which will never arrive. He's quite happy,
|
|
// he just assumes the device/link has not been started on this side
|
|
// and might be at sometime in the future.
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
for( ; ; )
|
|
{
|
|
|
|
// Build RRH 0xC108 PIX 0x0180 to yTokenUlpConnection (Will you start IPv4?)
|
|
pPTPHDRr1 = build_C108_will_you_start_4( pDEVBLK );
|
|
if (!pPTPHDRr1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Build RRH 0xC108 PIX 0x1180 to yTokenUlpConnection (My address IPv4)
|
|
pPTPHDRr2 = build_C108_my_address_4( pDEVBLK );
|
|
if (!pPTPHDRr2)
|
|
{
|
|
free( pPTPHDRr1 );
|
|
break;
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= IASKEDHIM_START;
|
|
pPTPBLK->bActivate4 |= ITOLDHIMMY_ADDRESS;
|
|
|
|
// Add PTPHDRs to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr2 );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case WILL_YOU_START_IPV6:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) Will you start IPv6?" );
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= HEASKEDME_START;
|
|
pPTPBLK->bActivateLL6 |= HEASKEDME_START;
|
|
|
|
// Build RRH 0xC108 PIX 0x0101 to yTokenUlpConnection (I will start IPv6)
|
|
pPTPHDRr1 = build_C108_i_will_start_6( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= IANSWEREDHIM_START;
|
|
pPTPBLK->bActivateLL6 |= IANSWEREDHIM_START;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
// We have said we will start IPv6, but if IPv6 was not specified
|
|
// that's all we will do. The y-side will wait patiently for our
|
|
// will you start IPv6, which will never arrive. He's quite happy,
|
|
// he just assumes the interface has not been started on this side
|
|
// and might be at sometime in the future.
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
for( ; ; )
|
|
{
|
|
|
|
// Build RRH 0xC108 PIX 0x0180 to yTokenUlpConnection (Will you start IPv6?)
|
|
pPTPHDRr1 = build_C108_will_you_start_6( pDEVBLK );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Build RRH 0xC108 PIX 0x1180 to yTokenUlpConnection (My address IPv6)
|
|
pPTPHDRr2 = build_C108_my_address_6( pDEVBLK, TRUE ); // Link local
|
|
if (!pPTPHDRr2)
|
|
{
|
|
free( pPTPHDRr1 );
|
|
break;
|
|
}
|
|
|
|
// Build RRH 0xC108 PIX 0x1180 to yTokenUlpConnection (My address IPv6)
|
|
pPTPHDRr3 = build_C108_my_address_6( pDEVBLK, FALSE );
|
|
if (!pPTPHDRr3)
|
|
{
|
|
free( pPTPHDRr2 );
|
|
free( pPTPHDRr1 );
|
|
break;
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= IASKEDHIM_START;
|
|
pPTPBLK->bActivateLL6 |= IASKEDHIM_START;
|
|
pPTPBLK->bActivate6 |= ITOLDHIMMY_ADDRESS;
|
|
pPTPBLK->bActivateLL6 |= ITOLDHIMMY_ADDRESS;
|
|
|
|
// Add PTPHDRs to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr2 );
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr3 );
|
|
|
|
break;
|
|
}
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
break;
|
|
|
|
case I_WILL_START_IPV4:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) I will start IPv4" );
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= HEANSWEREDME_START;
|
|
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivate4 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
pPTPBLK->fActive4 = TRUE;
|
|
pPTPBLK->bActivate4 = 0x00;
|
|
pPTPBLK->bTerminate4 = 0x00;
|
|
}
|
|
|
|
break;
|
|
|
|
case I_WILL_START_IPV6:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) I will start IPv6" );
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= HEANSWEREDME_START;
|
|
pPTPBLK->bActivateLL6 |= HEANSWEREDME_START;
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivateLL6 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestLLAddr6 );
|
|
pPTPBLK->fActiveLL6 = TRUE;
|
|
pPTPBLK->bActivateLL6 = 0x00;
|
|
pPTPBLK->bTerminateLL6 = 0x00;
|
|
if (pPTPBLK->fActive6)
|
|
{
|
|
build_8108_icmpv6_packets( pDEVBLK );
|
|
}
|
|
}
|
|
if (pPTPBLK->bActivate6 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
pPTPBLK->fActive6 = TRUE;
|
|
pPTPBLK->bActivate6 = 0x00;
|
|
pPTPBLK->bTerminate6 = 0x00;
|
|
if (pPTPBLK->fActiveLL6)
|
|
{
|
|
build_8108_icmpv6_packets( pDEVBLK );
|
|
}
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
break;
|
|
|
|
case MY_ADDRESS_IPV4:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) My address IPv4" );
|
|
}
|
|
|
|
// The y-side is telling us about his IPv4 address, which means
|
|
// IPv4 is defined in the guest and that the device/link is started.
|
|
// However, if IPv4 was not specified on the config statement, or
|
|
// the pre-configured TUN interface, we are not interested. We will
|
|
// respond to his message to keep him happy but that is all.
|
|
if (pPTPBLK->fIPv4Spec)
|
|
{
|
|
// Check for the guests IPv4 address.
|
|
if (memcmp( pMPC_PIXwr->ipaddr, &pPTPBLK->iaGuestIPAddr4, 4 ) == 0)
|
|
{
|
|
// The y-side has told us his IPv4 address and it is the
|
|
// guest address specified on the config statement or the
|
|
// pre-configured TUN interface, which is of course good news.
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= HETOLDMEHIS_ADDRESS;
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv4)
|
|
pPTPHDRr1 = build_C108_your_address_4( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= IANSWEREDHIS_ADDRESS;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
else
|
|
{
|
|
// Hmm... the y-side has told us his IPv4 address and it wasn't
|
|
// the guest IPv4 address specified on the config statement
|
|
// or the pre-configured TUN interface. This could happen if
|
|
// if have been told the wrong address on the config statement,
|
|
// or we are using a pre-configured TUN interface that did not
|
|
// specify the guest IPv4 address.
|
|
// Perhaps the guest and driver addresses were transposed.
|
|
if (memcmp( pMPC_PIXwr->ipaddr, &pPTPBLK->iaDriveIPAddr4, 4 ) == 0)
|
|
{
|
|
// Looks like the guest and driver IPv4 addresses were transposed.
|
|
hinet_ntop( AF_INET, &pMPC_PIXwr->ipaddr, cIPaddr, sizeof(cIPaddr) );
|
|
// HHC03912 "%1d:%04X PTP: Guest has the driver IP address '%s'"
|
|
WRMSG(HHC03912, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, cIPaddr );
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv4)
|
|
pPTPHDRr1 = build_C108_your_address_4( pDEVBLK, pMPC_PIXwr, 12 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
else
|
|
{
|
|
// Hmm... the y-side has told us his IPv4 address and it wasn't
|
|
// the guest or driver IPv4 address specified on the config
|
|
// statement or the pre-configured TUN interface.
|
|
// Check whether we are using a pre-configured TUN interface
|
|
// that did not specify the guest IPv4 address, and that we
|
|
// have not already been told an address.
|
|
memset(&addr4, 0, sizeof(addr4));
|
|
if (pPTPBLK->fPreconfigured && !pPTPBLK->fPreGuestIPAddr4 &&
|
|
( memcmp( &addr4, &pPTPBLK->iaGuestIPAddr4, sizeof(addr4) ) == 0 )) {
|
|
|
|
// We are using a pre-configured TUN interface that didn't
|
|
// specify the guest IPv4 address. Hooray, the y-side has
|
|
// told us his IPv4 address, something we didn't know, but
|
|
// need to. Copy the y-side's IPv4 address.
|
|
memcpy( &pPTPBLK->iaGuestIPAddr4, &pMPC_PIXwr->ipaddr,
|
|
sizeof(pPTPBLK->iaGuestIPAddr4) );
|
|
hinet_ntop( AF_INET, &pMPC_PIXwr->ipaddr, pPTPBLK->szGuestIPAddr4,
|
|
sizeof(pPTPBLK->szGuestIPAddr4) );
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= HETOLDMEHIS_ADDRESS;
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv4)
|
|
pPTPHDRr1 = build_C108_your_address_4( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= IANSWEREDHIS_ADDRESS;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
else
|
|
{
|
|
// The guest has an IPv4 address we know nothing about. The guest
|
|
// can only have one IPv4 address associated with a link.
|
|
hinet_ntop( AF_INET, &pMPC_PIXwr->ipaddr, cIPaddr, sizeof(cIPaddr) );
|
|
// HHC03913 "%1d:%04X PTP: Guest has IP address '%s'"
|
|
WRMSG(HHC03913, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
cIPaddr );
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv4)
|
|
pPTPHDRr1 = build_C108_your_address_4( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// IPv4 was not specified on the config statement or the
|
|
// preconfigured TUN interface, but the guest has informed
|
|
// us of his IPv4 address. Reply but otherwise ignore.
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv4)
|
|
pPTPHDRr1 = build_C108_your_address_4( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivate4 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
pPTPBLK->fActive4 = TRUE;
|
|
pPTPBLK->bActivate4 = 0x00;
|
|
pPTPBLK->bTerminate4 = 0x00;
|
|
}
|
|
|
|
break;
|
|
|
|
case MY_ADDRESS_IPV6:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) My address IPv6" );
|
|
}
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
// Check whether the y-side is telling us about a Link Local address.
|
|
fLL = FALSE;
|
|
memset( addr6.s6_addr, 0, 16 );
|
|
addr6.s6_addr[0] = 0xFE;
|
|
addr6.s6_addr[1] = 0x80;
|
|
if (memcmp( pMPC_PIXwr->ipaddr, &addr6, 8 ) == 0)
|
|
fLL = TRUE;
|
|
|
|
// The y-side is telling us about his IPv6 address(es), which means
|
|
// IPv6 is defined in the guest and that the interface is started.
|
|
// However, if IPv6 was not specified on the config statement, or
|
|
// the pre-configured TUN interface, we are not interested. We will
|
|
// respond to his message to keep him happy but that is all.
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
if (!fLL)
|
|
{
|
|
// The y-side has told us about an address that is not his Link
|
|
// Local address. Check whether the guests IPv6 is the address
|
|
// that was specified on the config statement.
|
|
if (memcmp( pMPC_PIXwr->ipaddr, &pPTPBLK->iaGuestIPAddr6, 16 ) == 0)
|
|
{
|
|
// The y-side has told us his IPv6 address and it is the guest
|
|
// address specified on the config statement, which is of course
|
|
// good news. Remember the activation status.
|
|
pPTPBLK->bActivate6 |= HETOLDMEHIS_ADDRESS;
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv6)
|
|
pPTPHDRr1 = build_C108_your_address_6( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= IANSWEREDHIS_ADDRESS;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
else
|
|
{
|
|
// Hmm... the y-side has told us his IPv6 address and it wasn't
|
|
// the guest IPv6 address specified on the config statement. This
|
|
// could happen; the guest can have multiple IPv6 addresses, or
|
|
// we are using a pre-configured TUN interface and we don't know
|
|
// the guest IPv6 address, or we have been told the wrong address.
|
|
// Perhaps the guest and driver IPv6 addresses were transposed on
|
|
// the config statement.
|
|
if (memcmp( pMPC_PIXwr->ipaddr, &pPTPBLK->iaDriveIPAddr6, 16 ) == 0)
|
|
{
|
|
// Looks like the guest and driver IPv6 addresses were transposed.
|
|
hinet_ntop( AF_INET, &pMPC_PIXwr->ipaddr, cIPaddr, sizeof(cIPaddr) );
|
|
// HHC03912 "%1d:%04X PTP: Guest has the driver IP address '%s'"
|
|
WRMSG(HHC03912, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
cIPaddr );
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv6)
|
|
pPTPHDRr1 = build_C108_your_address_6( pDEVBLK, pMPC_PIXwr, 12 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
else
|
|
{
|
|
// Hmm... the y-side has told us an IPv6 address and it wasn't
|
|
// the guest or driver IPv4 address specified on the config
|
|
// statement or the pre-configured TUN interface.
|
|
// Check whether we are using a pre-configured TUN interface,
|
|
// and that we have not already been told an address.
|
|
memset(&addr6, 0, sizeof(addr6));
|
|
if (pPTPBLK->fPreconfigured &&
|
|
( memcmp( &addr6, &pPTPBLK->iaGuestIPAddr6, sizeof(addr6) ) == 0 )) {
|
|
|
|
// We are using a pre-configured TUN interface. Hooray, the
|
|
// y-side has told us his IPv6 address, something we didn't
|
|
// know but need to. Copy the y-side's IPv6 address.
|
|
memcpy( &pPTPBLK->iaGuestIPAddr6, &pMPC_PIXwr->ipaddr,
|
|
sizeof(pPTPBLK->iaGuestIPAddr6) );
|
|
hinet_ntop( AF_INET6, &pMPC_PIXwr->ipaddr, pPTPBLK->szGuestIPAddr6,
|
|
sizeof(pPTPBLK->szGuestIPAddr6) );
|
|
|
|
// The y-side has told us his IPv6 address and it is the guest
|
|
// address specified on the config statement, which is of course
|
|
// good news. Remember the activation status.
|
|
pPTPBLK->bActivate6 |= HETOLDMEHIS_ADDRESS;
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv6)
|
|
pPTPHDRr1 = build_C108_your_address_6( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= IANSWEREDHIS_ADDRESS;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
else
|
|
{
|
|
// The guest has an IPv6 address we know nothing about. The guest
|
|
// can have multiple IPv6 addresses associated with an interface.
|
|
hinet_ntop( AF_INET6, &pMPC_PIXwr->ipaddr, cIPaddr, sizeof(cIPaddr) );
|
|
// HHC03914 "%1d:%04X PTP: Guest has IP address '%s'"
|
|
WRMSG(HHC03914, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
cIPaddr );
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv6)
|
|
pPTPHDRr1 = build_C108_your_address_6( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The y-side has told us about his Link Local address.
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivateLL6 |= HETOLDMEHIS_ADDRESS;
|
|
|
|
// Copy the y-side's Link Local address.
|
|
memcpy( &pPTPBLK->iaGuestLLAddr6, pMPC_PIXwr->ipaddr, 16 );
|
|
hinet_ntop( AF_INET6, &pPTPBLK->iaGuestLLAddr6,
|
|
pPTPBLK->szGuestLLAddr6,
|
|
sizeof(pPTPBLK->szGuestLLAddr6) );
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv6)
|
|
pPTPHDRr1 = build_C108_your_address_6( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivateLL6 |= IANSWEREDHIS_ADDRESS;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
// IPv6 was not specified on the config statement, but the guest
|
|
// has informed us of an IPv6 address. Reply but otherwise ignore.
|
|
|
|
// Build RRH 0xC108 PIX 0x1101 to yTokenUlpConnection (Your address IPv6)
|
|
pPTPHDRr1 = build_C108_your_address_6( pDEVBLK, pMPC_PIXwr, 0 );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
#if defined(ENABLE_IPV6)
|
|
}
|
|
|
|
//
|
|
if (pPTPBLK->fIPv6Spec)
|
|
{
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivateLL6 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestLLAddr6 );
|
|
pPTPBLK->fActiveLL6 = TRUE;
|
|
pPTPBLK->bActivateLL6 = 0x00;
|
|
pPTPBLK->bTerminateLL6 = 0x00;
|
|
if (pPTPBLK->fActive6)
|
|
build_8108_icmpv6_packets( pDEVBLK );
|
|
}
|
|
if (pPTPBLK->bActivate6 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
pPTPBLK->fActive6 = TRUE;
|
|
pPTPBLK->bActivate6 = 0x00;
|
|
pPTPBLK->bTerminate6 = 0x00;
|
|
if (pPTPBLK->fActiveLL6)
|
|
build_8108_icmpv6_packets( pDEVBLK );
|
|
}
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
break;
|
|
|
|
case YOUR_ADDRESS_IPV4:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) Your address IPv4" );
|
|
}
|
|
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate4 |= HEANSWEREDMY_ADDRESS;
|
|
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivate4 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
pPTPBLK->fActive4 = TRUE;
|
|
pPTPBLK->bActivate4 = 0x00;
|
|
pPTPBLK->bTerminate4 = 0x00;
|
|
}
|
|
|
|
break;
|
|
|
|
case YOUR_ADDRESS_IPV6:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) Your address IPv6" );
|
|
}
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
// Check whether the y-side is telling us about a Link Local address.
|
|
fLL = FALSE;
|
|
memset( addr6.s6_addr, 0, 16 );
|
|
addr6.s6_addr[0] = 0xFE;
|
|
addr6.s6_addr[1] = 0x80;
|
|
if (memcmp( pMPC_PIXwr->ipaddr, &addr6, 8 ) == 0)
|
|
fLL = TRUE;
|
|
|
|
//
|
|
if (!fLL)
|
|
{
|
|
// The y-side has told us about our IPv6 address.
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivate6 |= HEANSWEREDMY_ADDRESS;
|
|
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivate6 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
pPTPBLK->fActive6 = TRUE;
|
|
pPTPBLK->bActivate6 = 0x00;
|
|
pPTPBLK->bTerminate6 = 0x00;
|
|
if (pPTPBLK->fActiveLL6)
|
|
build_8108_icmpv6_packets( pDEVBLK );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The y-side has told us about our Link Local address.
|
|
// Remember the activation status.
|
|
pPTPBLK->bActivateLL6 |= HEANSWEREDMY_ADDRESS;
|
|
|
|
// Check whether the connection is active.
|
|
if (pPTPBLK->bActivateLL6 == WEAREACTIVE)
|
|
{
|
|
// HHC03915 "%1d:%04X PTP: Connection active to guest IP address '%s'"
|
|
WRMSG(HHC03915, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestLLAddr6 );
|
|
pPTPBLK->fActiveLL6 = TRUE;
|
|
pPTPBLK->bActivateLL6 = 0x00;
|
|
pPTPBLK->bTerminateLL6 = 0x00;
|
|
if (pPTPBLK->fActive6)
|
|
build_8108_icmpv6_packets( pDEVBLK );
|
|
}
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
break;
|
|
|
|
case WILL_YOU_STOP_IPV4:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) Will you stop IPv4?" );
|
|
}
|
|
|
|
// Remember the termination status.
|
|
pPTPBLK->bTerminate4 |= HEASKEDME_STOP;
|
|
|
|
// Build RRH 0xC108 PIX 0x0180 to yTokenUlpConnection (I will stop IPv4)
|
|
pPTPHDRr1 = build_C108_i_will_stop_4( pDEVBLK, pMPC_PIXwr );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Build RRH 0xC108 PIX 0x0180 to yTokenUlpConnection (Will you stop IPv4)
|
|
pPTPHDRr2 = build_C108_will_you_stop_4( pDEVBLK );
|
|
if (!pPTPHDRr2)
|
|
{
|
|
free( pPTPHDRr1 );
|
|
break;
|
|
}
|
|
|
|
// Remember the termination status.
|
|
pPTPBLK->bTerminate4 |= IANSWEREDHIM_STOP;
|
|
pPTPBLK->bTerminate4 |= IASKEDHIM_STOP;
|
|
|
|
// Add PTPHDRs to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr2 );
|
|
|
|
break;
|
|
|
|
case WILL_YOU_STOP_IPV6:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) Will you stop IPv6?" );
|
|
}
|
|
|
|
// Remember the termination status.
|
|
pPTPBLK->bTerminate6 |= HEASKEDME_STOP;
|
|
pPTPBLK->bTerminateLL6 |= HEASKEDME_STOP;
|
|
|
|
// Build RRH 0xC108 PIX 0x0180 to yTokenUlpConnection (I will stop IPv6)
|
|
pPTPHDRr1 = build_C108_i_will_stop_6( pDEVBLK, pMPC_PIXwr );
|
|
if (!pPTPHDRr1)
|
|
break;
|
|
|
|
// Build RRH 0xC108 PIX 0x0180 to yTokenUlpConnection (Will you stop IPv6)
|
|
pPTPHDRr2 = build_C108_will_you_stop_6( pDEVBLK );
|
|
if (!pPTPHDRr2)
|
|
{
|
|
free( pPTPHDRr1 );
|
|
break;
|
|
}
|
|
|
|
// Remember the termination status.
|
|
pPTPBLK->bTerminate6 |= IANSWEREDHIM_STOP;
|
|
pPTPBLK->bTerminate6 |= IASKEDHIM_STOP;
|
|
pPTPBLK->bTerminateLL6 |= IANSWEREDHIM_STOP;
|
|
pPTPBLK->bTerminateLL6 |= IASKEDHIM_STOP;
|
|
|
|
// Add PTPHDRs to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr1 );
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRr2 );
|
|
|
|
break;
|
|
|
|
case I_WILL_STOP_IPV4:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) I will stop IPv4" );
|
|
}
|
|
|
|
// Remember the termination status.
|
|
pPTPBLK->bTerminate4 |= HEANSWEREDME_STOP;
|
|
|
|
// Check whether the connection is terminated.
|
|
if (pPTPBLK->bTerminate4 == WEARETERMINATED)
|
|
{
|
|
// The guest OS on the y-side has stopped the device.
|
|
if (pPTPBLK->fActive4)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr4 );
|
|
}
|
|
pPTPBLK->fActive4 = FALSE;
|
|
pPTPBLK->bActivate4 = 0x00;
|
|
pPTPBLK->bTerminate4 = 0x00;
|
|
}
|
|
|
|
break;
|
|
|
|
case I_WILL_STOP_IPV6:
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "In RRH 0xC108 (UlpComm) I will stop IPv6" );
|
|
}
|
|
|
|
// Remember the termination status.
|
|
pPTPBLK->bTerminate6 |= HEANSWEREDME_STOP;
|
|
pPTPBLK->bTerminateLL6 |= HEANSWEREDME_STOP;
|
|
|
|
// Check whether the connection is terminated.
|
|
if (pPTPBLK->bTerminate6 == WEARETERMINATED)
|
|
{
|
|
// The guest OS on the y-side has stopped the device.
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fActive6)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestIPAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pPTPBLK->fActive6 = FALSE;
|
|
pPTPBLK->bActivate6 = 0x00;
|
|
pPTPBLK->bTerminate6 = 0x00;
|
|
}
|
|
if (pPTPBLK->bTerminateLL6 == WEARETERMINATED)
|
|
{
|
|
// The guest OS on the y-side has stopped the device.
|
|
#if defined(ENABLE_IPV6)
|
|
if (pPTPBLK->fActiveLL6)
|
|
{
|
|
// HHC03916 "%1d:%04X PTP: Connection cleared to guest IP address '%s'"
|
|
WRMSG(HHC03916, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum,
|
|
pPTPBLK->szGuestLLAddr6 );
|
|
}
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
pPTPBLK->fActiveLL6 = FALSE;
|
|
pPTPBLK->bActivateLL6 = 0x00;
|
|
pPTPBLK->bTerminateLL6 = 0x00;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// HHC03936 "%1d:%04X PTP: Accept data contains unknown %s"
|
|
WRMSG(HHC03936, "W", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, "PIX" );
|
|
mpc_display_rrh_and_pix( pDEVBLK, pMPC_THwr, pMPC_RRHwr, FROM_GUEST );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
} /* End function write_rrh_C108() */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_will_you_start_4() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0180 (Will you start IPv4?)
|
|
|
|
PTPHDR* build_C108_will_you_start_4( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_START;
|
|
pMPC_PIXre->askans = PIX_ASK;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV4;
|
|
STORE_HW( pMPC_PIXre->idnum, ++pPTPBLK->uIdNum );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) Will you start IPv4?" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_will_you_start_4() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_will_you_start_6() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0180 (Will you start IPv6?)
|
|
|
|
PTPHDR* build_C108_will_you_start_6( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_START;
|
|
pMPC_PIXre->askans = PIX_ASK;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV6;
|
|
STORE_HW( pMPC_PIXre->idnum, ++pPTPBLK->uIdNum );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) Will you start IPv6?" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_will_you_start_6() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_i_will_start_4() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0101 (I will start IPv4)
|
|
|
|
PTPHDR* build_C108_i_will_start_4( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIXwr, U16 uRCode )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the message will be build.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_START;
|
|
pMPC_PIXre->askans = PIX_ANSWER;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV4;
|
|
memcpy( pMPC_PIXre->idnum, pMPC_PIXwr->idnum, sizeof(pMPC_PIXre->idnum) );
|
|
STORE_HW( pMPC_PIXre->rcode, uRCode );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) I will start IPv4" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_i_will_start_4() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_i_will_start_6() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0101 (I will start IPv6)
|
|
|
|
PTPHDR* build_C108_i_will_start_6( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIXwr, U16 uRCode )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_START;
|
|
pMPC_PIXre->askans = PIX_ANSWER;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV6;
|
|
memcpy( pMPC_PIXre->idnum, pMPC_PIXwr->idnum, sizeof(pMPC_PIXre->idnum) );
|
|
STORE_HW( pMPC_PIXre->rcode, uRCode );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) I will start IPv6" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_i_will_start_6() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_my_address_4() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x1180 (My address IPv4)
|
|
|
|
PTPHDR* build_C108_my_address_4( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_ADDRESS;
|
|
pMPC_PIXre->askans = PIX_ASK;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV4;
|
|
STORE_HW( pMPC_PIXre->idnum, ++pPTPBLK->uIdNum );
|
|
memcpy( pMPC_PIXre->ipaddr, &pPTPBLK->iaDriveIPAddr4, 4 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) My address IPv4" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_my_address_4() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_my_address_6() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x1180 (My address IPv6)
|
|
|
|
PTPHDR* build_C108_my_address_6( DEVBLK* pDEVBLK, u_int fLL )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_ADDRESS;
|
|
pMPC_PIXre->askans = PIX_ASK;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV6;
|
|
STORE_HW( pMPC_PIXre->idnum, ++pPTPBLK->uIdNum );
|
|
if (fLL)
|
|
{
|
|
#if defined(ENABLE_IPV6)
|
|
memcpy( pMPC_PIXre->ipaddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
}
|
|
else
|
|
{
|
|
memcpy( pMPC_PIXre->ipaddr, &pPTPBLK->iaDriveIPAddr6, 16 );
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
}
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) My address IPv6" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_my_address_6() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_your_address_4() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x1101 (Your address IPv4)
|
|
|
|
PTPHDR* build_C108_your_address_4( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIXwr, U16 uRCode )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_ADDRESS;
|
|
pMPC_PIXre->askans = PIX_ANSWER;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV4;
|
|
memcpy( pMPC_PIXre->idnum, pMPC_PIXwr->idnum, sizeof(pMPC_PIXre->idnum) );
|
|
STORE_HW( pMPC_PIXre->rcode, uRCode );
|
|
memcpy( pMPC_PIXre->ipaddr, pMPC_PIXwr->ipaddr, 4 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) Your address IPv4" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_your_address_4() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_your_address_6() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x1101 (Your address IPv6)
|
|
|
|
PTPHDR* build_C108_your_address_6( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIXwr, U16 uRCode )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the first reply will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_ADDRESS;
|
|
pMPC_PIXre->askans = PIX_ANSWER;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV6;
|
|
memcpy( pMPC_PIXre->idnum, pMPC_PIXwr->idnum, sizeof(pMPC_PIXre->idnum) );
|
|
STORE_HW( pMPC_PIXre->rcode, uRCode );
|
|
memcpy( pMPC_PIXre->ipaddr, pMPC_PIXwr->ipaddr, 16 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) Your address IPv6" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_your_address_6() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_will_you_stop_4() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0280 (Will you stop IPv4?)
|
|
|
|
PTPHDR* build_C108_will_you_stop_4( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_STOP;
|
|
pMPC_PIXre->askans = PIX_ASK;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV4;
|
|
STORE_HW( pMPC_PIXre->idnum, ++pPTPBLK->uIdNum );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) Will you stop IPv4?" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_will_you_stop_4() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_will_you_stop_6() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0280 (Will you stop IPv6?)
|
|
|
|
PTPHDR* build_C108_will_you_stop_6( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_STOP;
|
|
pMPC_PIXre->askans = PIX_ASK;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV6;
|
|
STORE_HW( pMPC_PIXre->idnum, ++pPTPBLK->uIdNum );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) Will you stop IPv6?" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_will_you_stop_6() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_i_will_stop_4() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0201 (I will stop IPv4)
|
|
|
|
PTPHDR* build_C108_i_will_stop_4( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIXwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_STOP;
|
|
pMPC_PIXre->askans = PIX_ANSWER;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV4;
|
|
memcpy( pMPC_PIXre->idnum, pMPC_PIXwr->idnum, sizeof(pMPC_PIXre->idnum) );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) I will stop IPv4" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_i_will_stop_4() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_C108_i_will_stop_6() */
|
|
/* ------------------------------------------------------------------ */
|
|
// Build RRH 0xC108 PIX 0x0201 (I will stop IPv6)
|
|
|
|
PTPHDR* build_C108_i_will_stop_6( DEVBLK* pDEVBLK, MPC_PIX* pMPC_PIXwr )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
MPC_PIX* pMPC_PIXre; // MPC_PIX follows MPC_PH
|
|
|
|
|
|
// Allocate a buffer in which the response will be build.
|
|
// Note: the largest reply will be 88 bytes.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return NULL;
|
|
|
|
// Fix-up various lengths
|
|
uLength3 = SIZE_PIX; // the MPC_PIX
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pMPC_PIXre = (MPC_PIX*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_IPA;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare MPC_PIXre
|
|
pMPC_PIXre->action = PIX_STOP;
|
|
pMPC_PIXre->askans = PIX_ANSWER;
|
|
pMPC_PIXre->numaddr = PIX_ONEADDR;
|
|
pMPC_PIXre->iptype = PIX_IPV6;
|
|
memcpy( pMPC_PIXre->idnum, pMPC_PIXwr->idnum, sizeof(pMPC_PIXre->idnum) );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0xC108 (UlpComm) I will stop IPv6" );
|
|
}
|
|
|
|
return pPTPHDRre;
|
|
} /* End function build_C108_i_will_stop_6() */
|
|
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
/* ------------------------------------------------------------------ */
|
|
/* build_8108_icmpv6_packets() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void build_8108_icmpv6_packets( DEVBLK* pDEVBLK )
|
|
{
|
|
PTPATH* pPTPATH = pDEVBLK->dev_data;
|
|
PTPBLK* pPTPBLK = pPTPATH->pPTPBLK;
|
|
PTPATH* pPTPATHre = pPTPBLK->pPTPATHRead;
|
|
U32 uLength1;
|
|
U32 uLength2;
|
|
U32 uLength3;
|
|
U16 uLength4;
|
|
U16 uLength5;
|
|
U16 uLength6;
|
|
PTPHDR* pPTPHDRre; // PTPHDR to be read
|
|
MPC_TH* pMPC_THre; // MPC_TH follows PTPHDR
|
|
MPC_RRH* pMPC_RRHre; // MPC_RRH follows MPC_TH
|
|
MPC_PH* pMPC_PHre; // MPC_PH follows MPC_RRH
|
|
PIP6FRM pIP6FRMre; // IPv6 header
|
|
BYTE* pHopOpt; // Hop-by-Hop Options follows IPv6 header
|
|
BYTE* pIcmpHdr; // ICMPv6 header follows IPv6 header or Hop-by-Hop
|
|
|
|
|
|
// Allocate a buffer in which the ICMPv6 Neighbor Advertisement message
|
|
// will be built. Note: the message will be 128 bytes.
|
|
// The source address is the drive link local address, the destination
|
|
// address is the Link-Local Scope All Nodes multicast address, i.e.
|
|
// FF02:0:0:0:0:0:0:1.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return;
|
|
|
|
// Fix-up various lengths
|
|
uLength6 = 24; // the ICMPv6 packet
|
|
uLength5 = 0; // no Hop-by-Hop Options
|
|
uLength4 = sizeof(IP6FRM); // the IPv6 header
|
|
uLength3 = uLength4 + uLength6; // the data
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pIP6FRMre = (IP6FRM*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pHopOpt = NULL;
|
|
pIcmpHdr = (BYTE*)pIP6FRMre->bPayload;
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_CM;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare IP6FRMre, i.e. IPv6 header
|
|
pIP6FRMre->bVersTCFlow[0] = 0x60;
|
|
STORE_HW( pIP6FRMre->bPayloadLength, uLength6 );
|
|
pIP6FRMre->bNextHeader = 0x3A;
|
|
pIP6FRMre->bHopLimit = 0xFF;
|
|
memcpy( pIP6FRMre->bSrcAddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
pIP6FRMre->bDstAddr[0] = 0xFF;
|
|
pIP6FRMre->bDstAddr[1] = 0x02;
|
|
pIP6FRMre->bDstAddr[15] = 0x01;
|
|
|
|
// Prepare ICMPv6 packet
|
|
pIcmpHdr[0] = 0x88;
|
|
pIcmpHdr[4] = 0x20;
|
|
memcpy( pIcmpHdr+8, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
|
|
// Calculate and set the ICMPv6 checksum
|
|
calculate_icmpv6_checksum( pIP6FRMre, pIcmpHdr, (int)uLength6 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x8108 (UlpComm) Neighbor advertisement" );
|
|
}
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
|
|
// Allocate a buffer in which the ICMPv6 Router Solicitation message
|
|
// will be built. Note: the message will be 120 bytes.
|
|
// The source address is the drive link local address, the destination
|
|
// address is the Link-Local Scope All Routers multicast address, i.e.
|
|
// FF02:0:0:0:0:0:0:2.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return;
|
|
|
|
// Fix-up various lengths
|
|
uLength6 = 16; // the ICMPv6 packet
|
|
uLength5 = 0; // no Hop-by-Hop Options
|
|
uLength4 = sizeof(IP6FRM); // the IPv6 header
|
|
uLength3 = uLength4 + uLength6; // the data
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pIP6FRMre = (IP6FRM*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pHopOpt = NULL;
|
|
pIcmpHdr = (BYTE*)pIP6FRMre->bPayload;
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_CM;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare IP6FRMre, i.e. IPv6 header
|
|
pIP6FRMre->bVersTCFlow[0] = 0x60;
|
|
STORE_HW( pIP6FRMre->bPayloadLength, uLength6 );
|
|
pIP6FRMre->bNextHeader = 0x3A;
|
|
pIP6FRMre->bHopLimit = 0xFF;
|
|
memcpy( pIP6FRMre->bSrcAddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
pIP6FRMre->bDstAddr[0] = 0xFF;
|
|
pIP6FRMre->bDstAddr[1] = 0x02;
|
|
pIP6FRMre->bDstAddr[15] = 0x02;
|
|
|
|
// Prepare ICMPv6 packet
|
|
pIcmpHdr[0] = 0x85;
|
|
pIcmpHdr[8] = 0x01;
|
|
pIcmpHdr[9] = 0x01;
|
|
|
|
// Calculate and set the ICMPv6 checksum
|
|
calculate_icmpv6_checksum( pIP6FRMre, pIcmpHdr, (int)uLength6 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x8108 (UlpComm) Router solicitation" );
|
|
}
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
|
|
// Allocate a buffer in which the ICMPv6 Neighbor Advertisement message
|
|
// will be built. Note: the message will be 128 bytes.
|
|
// The source address is the drive address, the destination address
|
|
// is the Link-Local Scope All Nodes multicast address, i.e.
|
|
// FF02:0:0:0:0:0:0:1.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return;
|
|
|
|
// Fix-up various lengths
|
|
uLength6 = 24; // the ICMPv6 packet
|
|
uLength5 = 0; // no Hop-by-Hop Options
|
|
uLength4 = sizeof(IP6FRM); // the IPv6 header
|
|
uLength3 = uLength4 + uLength6; // the data
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pIP6FRMre = (IP6FRM*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pHopOpt = NULL;
|
|
pIcmpHdr = (BYTE*)pIP6FRMre->bPayload;
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_CM;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare IP6FRMre, i.e. IPv6 header
|
|
pIP6FRMre->bVersTCFlow[0] = 0x60;
|
|
STORE_HW( pIP6FRMre->bPayloadLength, uLength6 );
|
|
pIP6FRMre->bNextHeader = 0x3A;
|
|
pIP6FRMre->bHopLimit = 0xFF;
|
|
memcpy( pIP6FRMre->bSrcAddr, &pPTPBLK->iaDriveIPAddr6, 16 );
|
|
pIP6FRMre->bDstAddr[0] = 0xFF;
|
|
pIP6FRMre->bDstAddr[1] = 0x02;
|
|
pIP6FRMre->bDstAddr[15] = 0x01;
|
|
|
|
// Prepare ICMPv6 packet
|
|
pIcmpHdr[0] = 0x88;
|
|
pIcmpHdr[4] = 0x20;
|
|
memcpy( pIcmpHdr+8, &pPTPBLK->iaDriveIPAddr6, 16 );
|
|
|
|
// Calculate and set the ICMPv6 checksum
|
|
calculate_icmpv6_checksum( pIP6FRMre, pIcmpHdr, (int)uLength6 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x8108 (UlpComm) Neighbor advertisement" );
|
|
}
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
|
|
// Allocate a buffer in which the ICMPv6 Group Membership Report message
|
|
// will be built. Note: the message will be 136 bytes.
|
|
// The source address is the drive link local address, the destination
|
|
// address is the Link-Local Scope Selected-Node multicast address for
|
|
// the drive link local address, i.e. FF02:0:0:0:0:1:FFxx:xxxx.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return;
|
|
|
|
// Fix-up various lengths
|
|
uLength6 = 24; // the ICMPv6 packet
|
|
uLength5 = 8; // the Hop-by-Hop Options
|
|
uLength4 = sizeof(IP6FRM); // the IPv6 header
|
|
uLength3 = uLength4 + uLength5 + uLength6; // the data
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pIP6FRMre = (IP6FRM*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pHopOpt = (BYTE*)pIP6FRMre->bPayload;
|
|
pIcmpHdr = pHopOpt + uLength5;
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_CM;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare IP6FRMre, i.e. IPv6 header
|
|
pIP6FRMre->bVersTCFlow[0] = 0x60;
|
|
STORE_HW( pIP6FRMre->bPayloadLength, uLength5 + uLength6 );
|
|
pIP6FRMre->bNextHeader = 0x00;
|
|
pIP6FRMre->bHopLimit = 0x01;
|
|
memcpy( pIP6FRMre->bSrcAddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
pIP6FRMre->bDstAddr[0] = 0xFF;
|
|
pIP6FRMre->bDstAddr[1] = 0x02;
|
|
pIP6FRMre->bDstAddr[11] = 0x01;
|
|
pIP6FRMre->bDstAddr[12] = 0xFF;
|
|
memcpy( pIP6FRMre->bDstAddr+13, &pPTPBLK->iaDriveLLAddr6+13, 3 );
|
|
|
|
// Prepare Hop-by-Hop Options
|
|
pHopOpt[0] = 0x3A;
|
|
pHopOpt[2] = 0x05;
|
|
pHopOpt[3] = 0x02;
|
|
|
|
// Prepare ICMPv6 packet
|
|
pIcmpHdr[0] = 0x83;
|
|
pIcmpHdr[8] = 0xFF;
|
|
pIcmpHdr[9] = 0x02;
|
|
pIcmpHdr[19] = 0x01;
|
|
pIcmpHdr[20] = 0xFF;
|
|
memcpy( pIcmpHdr+21, &pPTPBLK->iaDriveLLAddr6+13, 3 );
|
|
|
|
// Calculate and set the ICMPv6 checksum
|
|
calculate_icmpv6_checksum( pIP6FRMre, pIcmpHdr, (int)uLength6 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x8108 (UlpComm) Group membership report" );
|
|
}
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
|
|
// Allocate a buffer in which the ICMPv6 Group Membership Report message
|
|
// will be built. Note: the message will be 136 bytes.
|
|
// The source address is the drive link local address, the destination
|
|
// address is the Link-Local Scope Selected-Node multicast address for
|
|
// the drive address, i.e. FF02:0:0:0:0:1:FFyy:yyyy.
|
|
pPTPHDRre = alloc_ptp_buffer( pDEVBLK, 256 );
|
|
if (!pPTPHDRre)
|
|
return;
|
|
|
|
// Fix-up various lengths
|
|
uLength6 = 24; // the ICMPv6 packet
|
|
uLength5 = 8; // the Hop-by-Hop Options
|
|
uLength4 = sizeof(IP6FRM); // the IPv6 header
|
|
uLength3 = uLength4 + uLength5 + uLength6; // the data
|
|
uLength2 = SIZE_TH + SIZE_RRH + SIZE_PH; // the MPC_TH/MPC_RRH/MPC_PH
|
|
uLength1 = uLength2 + uLength3; // the MPC_TH/MPC_RRH/MPC_PH and data
|
|
|
|
// Fix-up various pointers
|
|
pMPC_THre = (MPC_TH*)((BYTE*)pPTPHDRre + SIZE_HDR);
|
|
pMPC_RRHre = (MPC_RRH*)((BYTE*)pMPC_THre + SIZE_TH);
|
|
pMPC_PHre = (MPC_PH*)((BYTE*)pMPC_RRHre + SIZE_RRH);
|
|
pIP6FRMre = (IP6FRM*)((BYTE*)pMPC_PHre + SIZE_PH);
|
|
pHopOpt = (BYTE*)pIP6FRMre->bPayload;
|
|
pIcmpHdr = pHopOpt + uLength5;
|
|
|
|
// Prepare PTPHDRre
|
|
pPTPHDRre->iDataLen = uLength1;
|
|
|
|
// Prepare MPC_THre
|
|
STORE_FW( pMPC_THre->first4, MPC_TH_FIRST4 );
|
|
STORE_FW( pMPC_THre->offrrh, SIZE_TH );
|
|
STORE_FW( pMPC_THre->length, uLength1 );
|
|
STORE_HW( pMPC_THre->unknown10, MPC_TH_UNKNOWN10 ); // !!! //
|
|
STORE_HW( pMPC_THre->numrrh, 1 );
|
|
|
|
// Prepare MPC_RRHre
|
|
pMPC_RRHre->type = RRH_TYPE_CM;
|
|
pMPC_RRHre->proto = PROTOCOL_LAYER2;
|
|
STORE_HW( pMPC_RRHre->numph, 1 );
|
|
STORE_HW( pMPC_RRHre->offph, SIZE_RRH );
|
|
STORE_HW( pMPC_RRHre->lenfida, (U16)uLength3 );
|
|
STORE_F3( pMPC_RRHre->lenalda, uLength3 );
|
|
pMPC_RRHre->tokenx5 = MPC_TOKEN_X5;
|
|
memcpy( pMPC_RRHre->token, pPTPBLK->yTokenUlpConnection, MPC_TOKEN_LENGTH );
|
|
|
|
// Prepare MPC_PHre
|
|
pMPC_PHre->locdata = PH_LOC_1;
|
|
STORE_F3( pMPC_PHre->lendata, uLength3 );
|
|
STORE_FW( pMPC_PHre->offdata, uLength2 );
|
|
|
|
// Prepare IP6FRMre, i.e. IPv6 header
|
|
pIP6FRMre->bVersTCFlow[0] = 0x60;
|
|
STORE_HW( pIP6FRMre->bPayloadLength, uLength5 + uLength6 );
|
|
pIP6FRMre->bNextHeader = 0x00;
|
|
pIP6FRMre->bHopLimit = 0x01;
|
|
memcpy( pIP6FRMre->bSrcAddr, &pPTPBLK->iaDriveLLAddr6, 16 );
|
|
pIP6FRMre->bDstAddr[0] = 0xFF;
|
|
pIP6FRMre->bDstAddr[1] = 0x02;
|
|
pIP6FRMre->bDstAddr[11] = 0x01;
|
|
pIP6FRMre->bDstAddr[12] = 0xFF;
|
|
memcpy( pIP6FRMre->bDstAddr+13, &pPTPBLK->iaDriveIPAddr6+13, 3 );
|
|
|
|
// Prepare Hop-by-Hop Options
|
|
pHopOpt[0] = 0x3A;
|
|
pHopOpt[2] = 0x05;
|
|
pHopOpt[3] = 0x02;
|
|
|
|
// Prepare ICMPv6 packet
|
|
pIcmpHdr[0] = 0x83;
|
|
pIcmpHdr[8] = 0xFF;
|
|
pIcmpHdr[9] = 0x02;
|
|
pIcmpHdr[19] = 0x01;
|
|
pIcmpHdr[20] = 0xFF;
|
|
memcpy( pIcmpHdr+21, &pPTPBLK->iaDriveIPAddr6+13, 3 );
|
|
|
|
// Calculate and set the ICMPv6 checksum
|
|
calculate_icmpv6_checksum( pIP6FRMre, pIcmpHdr, (int)uLength6 );
|
|
|
|
// Display various information, maybe
|
|
if (pPTPBLK->uDebugMask & DBGPTPUPDOWN)
|
|
{
|
|
mpc_display_description( pDEVBLK, "Out RRH 0x8108 (UlpComm) Group membership report" );
|
|
}
|
|
|
|
// Add PTPHDR to chain.
|
|
add_buffer_to_chain_and_signal_event( pPTPATHre, pPTPHDRre );
|
|
|
|
return;
|
|
} /* End function build_8108_icmpv6_packets() */
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* gen_csv_sid() */
|
|
/* ------------------------------------------------------------------ */
|
|
// If this function is called multiple times with the same input clock
|
|
// values the output token value will always be the same.
|
|
// For example:-
|
|
// if Clock1 is always C5620E1F FC2FA000
|
|
// and Clock2 is always C5620DD2 5E806000
|
|
// the token will always be 76152E37 8A370460
|
|
// but:-
|
|
// if Clock1 is always C5620DD2 5E806000
|
|
// and Clock2 is always C5620E1F FC2FA000
|
|
// the Token will always be 734EE30C 0854474F
|
|
|
|
// Input: pClock1 An 8-byte tod clock value
|
|
// pClock2 An 8-byte tod clock value
|
|
// Output: pToken An 8-byte token
|
|
|
|
void gen_csv_sid( BYTE* pClock1, BYTE* pClock2, BYTE* pToken )
|
|
{
|
|
|
|
static const U32 XorConstant[512] =
|
|
{ 0x00404100, 0x00000000, 0x00004000, 0x00404101,
|
|
0x00404001, 0x00004101, 0x00000001, 0x00004000,
|
|
0x00000100, 0x00404100, 0x00404101, 0x00000100,
|
|
0x00400101, 0x00404001, 0x00400000, 0x00000001,
|
|
0x00000101, 0x00400100, 0x00400100, 0x00004100,
|
|
0x00004100, 0x00404000, 0x00404000, 0x00400101,
|
|
0x00004001, 0x00400001, 0x00400001, 0x00004001,
|
|
0x00000000, 0x00000101, 0x00004101, 0x00400000,
|
|
0x00004000, 0x00404101, 0x00000001, 0x00404000,
|
|
0x00404100, 0x00400000, 0x00400000, 0x00000100,
|
|
0x00404001, 0x00004000, 0x00004100, 0x00400001,
|
|
0x00000100, 0x00000001, 0x00400101, 0x00004101,
|
|
0x00404101, 0x00004001, 0x00404000, 0x00400101,
|
|
0x00400001, 0x00000101, 0x00004101, 0x00404100,
|
|
0x00000101, 0x00400100, 0x00400100, 0x00000000,
|
|
0x00004001, 0x00004100, 0x00000000, 0x00404001,
|
|
0x20042008, 0x20002000, 0x00002000, 0x00042008,
|
|
0x00040000, 0x00000008, 0x20040008, 0x20002008,
|
|
0x20000008, 0x20042008, 0x20042000, 0x20000000,
|
|
0x20002000, 0x00040000, 0x00000008, 0x20040008,
|
|
0x00042000, 0x00040008, 0x20002008, 0x00000000,
|
|
0x20000000, 0x00002000, 0x00042008, 0x20040000,
|
|
0x00040008, 0x20000008, 0x00000000, 0x00042000,
|
|
0x00002008, 0x20042000, 0x20040000, 0x00002008,
|
|
0x00000000, 0x00042008, 0x20040008, 0x00040000,
|
|
0x20002008, 0x20040000, 0x20042000, 0x00002000,
|
|
0x20040000, 0x20002000, 0x00000008, 0x20042008,
|
|
0x00042008, 0x00000008, 0x00002000, 0x20000000,
|
|
0x00002008, 0x20042000, 0x00040000, 0x20000008,
|
|
0x00040008, 0x20002008, 0x20000008, 0x00040008,
|
|
0x00042000, 0x00000000, 0x20002000, 0x00002008,
|
|
0x20000000, 0x20040008, 0x20042008, 0x00042000,
|
|
0x00000082, 0x02008080, 0x00000000, 0x02008002,
|
|
0x02000080, 0x00000000, 0x00008082, 0x02000080,
|
|
0x00008002, 0x02000002, 0x02000002, 0x00008000,
|
|
0x02008082, 0x00008002, 0x02008000, 0x00000082,
|
|
0x02000000, 0x00000002, 0x02008080, 0x00000080,
|
|
0x00008080, 0x02008000, 0x02008002, 0x00008082,
|
|
0x02000082, 0x00008080, 0x00008000, 0x02000082,
|
|
0x00000002, 0x02008082, 0x00000080, 0x02000000,
|
|
0x02008080, 0x02000000, 0x00008002, 0x00000082,
|
|
0x00008000, 0x02008080, 0x02000080, 0x00000000,
|
|
0x00000080, 0x00008002, 0x02008082, 0x02000080,
|
|
0x02000002, 0x00000080, 0x00000000, 0x02008002,
|
|
0x02000082, 0x00008000, 0x02000000, 0x02008082,
|
|
0x00000002, 0x00008082, 0x00008080, 0x02000002,
|
|
0x02008000, 0x02000082, 0x00000082, 0x02008000,
|
|
0x00008082, 0x00000002, 0x02008002, 0x00008080,
|
|
0x40200800, 0x40000820, 0x40000820, 0x00000020,
|
|
0x00200820, 0x40200020, 0x40200000, 0x40000800,
|
|
0x00000000, 0x00200800, 0x00200800, 0x40200820,
|
|
0x40000020, 0x00000000, 0x00200020, 0x40200000,
|
|
0x40000000, 0x00000800, 0x00200000, 0x40200800,
|
|
0x00000020, 0x00200000, 0x40000800, 0x00000820,
|
|
0x40200020, 0x40000000, 0x00000820, 0x00200020,
|
|
0x00000800, 0x00200820, 0x40200820, 0x40000020,
|
|
0x00200020, 0x40200000, 0x00200800, 0x40200820,
|
|
0x40000020, 0x00000000, 0x00000000, 0x00200800,
|
|
0x00000820, 0x00200020, 0x40200020, 0x40000000,
|
|
0x40200800, 0x40000820, 0x40000820, 0x00000020,
|
|
0x40200820, 0x40000020, 0x40000000, 0x00000800,
|
|
0x40200000, 0x40000800, 0x00200820, 0x40200020,
|
|
0x40000800, 0x00000820, 0x00200000, 0x40200800,
|
|
0x00000020, 0x00200000, 0x00000800, 0x00200820,
|
|
0x00000040, 0x00820040, 0x00820000, 0x10800040,
|
|
0x00020000, 0x00000040, 0x10000000, 0x00820000,
|
|
0x10020040, 0x00020000, 0x00800040, 0x10020040,
|
|
0x10800040, 0x10820000, 0x00020040, 0x10000000,
|
|
0x00800000, 0x10020000, 0x10020000, 0x00000000,
|
|
0x10000040, 0x10820040, 0x10820040, 0x00800040,
|
|
0x10820000, 0x10000040, 0x00000000, 0x10800000,
|
|
0x00820040, 0x00800000, 0x10800000, 0x00020040,
|
|
0x00020000, 0x10800040, 0x00000040, 0x00800000,
|
|
0x10000000, 0x00820000, 0x10800040, 0x10020040,
|
|
0x00800040, 0x10000000, 0x10820000, 0x00820040,
|
|
0x10020040, 0x00000040, 0x00800000, 0x10820000,
|
|
0x10820040, 0x00020040, 0x10800000, 0x10820040,
|
|
0x00820000, 0x00000000, 0x10020000, 0x10800000,
|
|
0x00020040, 0x00800040, 0x10000040, 0x00020000,
|
|
0x00000000, 0x10020000, 0x00820040, 0x10000040,
|
|
0x08000004, 0x08100000, 0x00001000, 0x08101004,
|
|
0x08100000, 0x00000004, 0x08101004, 0x00100000,
|
|
0x08001000, 0x00101004, 0x00100000, 0x08000004,
|
|
0x00100004, 0x08001000, 0x08000000, 0x00001004,
|
|
0x00000000, 0x00100004, 0x08001004, 0x00001000,
|
|
0x00101000, 0x08001004, 0x00000004, 0x08100004,
|
|
0x08100004, 0x00000000, 0x00101004, 0x08101000,
|
|
0x00001004, 0x00101000, 0x08101000, 0x08000000,
|
|
0x08001000, 0x00000004, 0x08100004, 0x00101000,
|
|
0x08101004, 0x00100000, 0x00001004, 0x08000004,
|
|
0x00100000, 0x08001000, 0x08000000, 0x00001004,
|
|
0x08000004, 0x08101004, 0x00101000, 0x08100000,
|
|
0x00101004, 0x08101000, 0x00000000, 0x08100004,
|
|
0x00000004, 0x00001000, 0x08100000, 0x00101004,
|
|
0x00001000, 0x00100004, 0x08001004, 0x00000000,
|
|
0x08101000, 0x08000000, 0x00100004, 0x08001004,
|
|
0x00080000, 0x81080000, 0x81000200, 0x00000000,
|
|
0x00000200, 0x81000200, 0x80080200, 0x01080200,
|
|
0x81080200, 0x00080000, 0x00000000, 0x81000000,
|
|
0x80000000, 0x01000000, 0x81080000, 0x80000200,
|
|
0x01000200, 0x80080200, 0x80080000, 0x01000200,
|
|
0x81000000, 0x01080000, 0x01080200, 0x80080000,
|
|
0x01080000, 0x00000200, 0x80000200, 0x81080200,
|
|
0x00080200, 0x80000000, 0x01000000, 0x00080200,
|
|
0x01000000, 0x00080200, 0x00080000, 0x81000200,
|
|
0x81000200, 0x81080000, 0x81080000, 0x80000000,
|
|
0x80080000, 0x01000000, 0x01000200, 0x00080000,
|
|
0x01080200, 0x80000200, 0x80080200, 0x01080200,
|
|
0x80000200, 0x81000000, 0x81080200, 0x01080000,
|
|
0x00080200, 0x00000000, 0x80000000, 0x81080200,
|
|
0x00000000, 0x80080200, 0x01080000, 0x00000200,
|
|
0x81000000, 0x01000200, 0x00000200, 0x80080000,
|
|
0x04000410, 0x00000400, 0x00010000, 0x04010410,
|
|
0x04000000, 0x04000410, 0x00000010, 0x04000000,
|
|
0x00010010, 0x04010000, 0x04010410, 0x00010400,
|
|
0x04010400, 0x00010410, 0x00000400, 0x00000010,
|
|
0x04010000, 0x04000010, 0x04000400, 0x00000410,
|
|
0x00010400, 0x00010010, 0x04010010, 0x04010400,
|
|
0x00000410, 0x00000000, 0x00000000, 0x04010010,
|
|
0x04000010, 0x04000400, 0x00010410, 0x00010000,
|
|
0x00010410, 0x00010000, 0x04010400, 0x00000400,
|
|
0x00000010, 0x04010010, 0x00000400, 0x00010410,
|
|
0x04000400, 0x00000010, 0x04000010, 0x04010000,
|
|
0x04010010, 0x04000000, 0x00010000, 0x04000410,
|
|
0x00000000, 0x04010410, 0x00010010, 0x04000010,
|
|
0x04010000, 0x04000400, 0x04000410, 0x00000000,
|
|
0x04010410, 0x00010400, 0x00010400, 0x00000410,
|
|
0x00000410, 0x00010010, 0x04000000, 0x04010400 };
|
|
|
|
static const U32 OrConstant[24] =
|
|
{ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
|
|
0x08000000, 0x04000000, 0x00800000, 0x00400000,
|
|
0x00200000, 0x00100000, 0x00080000, 0x00040000,
|
|
0x00008000, 0x00004000, 0x00002000, 0x00001000,
|
|
0x00000800, 0x00000400, 0x00000080, 0x00000040,
|
|
0x00000020, 0x00000010, 0x00000008, 0x00000004 };
|
|
|
|
BYTE XorClocks[8];
|
|
U32 XorResult[2];
|
|
U32 OrResult[32];
|
|
U32 wv[16]; // Work Values
|
|
int i, j;
|
|
|
|
|
|
// Xor together the two input clock values.
|
|
for( i = 0; i <= 7; i++ )
|
|
XorClocks[i] = pClock2[i] ^ pClock1[i];
|
|
|
|
// Process the input pClock1 value. The first 7 bits of each of the 8 bytes
|
|
// of the value are tested and, if the bit is on, several OrConstant[] values
|
|
// are or'ed into several OrRresult[] values. Before that however, ensure the
|
|
// OrRresult[] values contain nothing.
|
|
for( i = 0; i <= 31; i++ )
|
|
OrResult[i] = 0;
|
|
|
|
// Process the STCK value.
|
|
if ((pClock1[0] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[0] |= OrConstant[11];
|
|
OrResult[4] |= OrConstant[2];
|
|
OrResult[7] |= OrConstant[10];
|
|
OrResult[9] |= OrConstant[2];
|
|
OrResult[10] |= OrConstant[1];
|
|
OrResult[12] |= OrConstant[7];
|
|
OrResult[15] |= OrConstant[4];
|
|
OrResult[18] |= OrConstant[3];
|
|
OrResult[20] |= OrConstant[10];
|
|
OrResult[23] |= OrConstant[1];
|
|
OrResult[25] |= OrConstant[11];
|
|
OrResult[26] |= OrConstant[9];
|
|
OrResult[29] |= OrConstant[3];
|
|
OrResult[31] |= OrConstant[7];
|
|
}
|
|
if ((pClock1[0] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[1] |= OrConstant[6];
|
|
OrResult[2] |= OrConstant[1];
|
|
OrResult[4] |= OrConstant[7];
|
|
OrResult[7] |= OrConstant[4];
|
|
OrResult[8] |= OrConstant[6];
|
|
OrResult[13] |= OrConstant[8];
|
|
OrResult[14] |= OrConstant[4];
|
|
OrResult[17] |= OrConstant[11];
|
|
OrResult[18] |= OrConstant[9];
|
|
OrResult[21] |= OrConstant[3];
|
|
OrResult[22] |= OrConstant[11];
|
|
OrResult[25] |= OrConstant[5];
|
|
OrResult[26] |= OrConstant[8];
|
|
OrResult[28] |= OrConstant[0];
|
|
OrResult[31] |= OrConstant[2];
|
|
}
|
|
if ((pClock1[0] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[0] |= OrConstant[3];
|
|
OrResult[5] |= OrConstant[8];
|
|
OrResult[6] |= OrConstant[4];
|
|
OrResult[9] |= OrConstant[0];
|
|
OrResult[10] |= OrConstant[5];
|
|
OrResult[13] |= OrConstant[7];
|
|
OrResult[17] |= OrConstant[5];
|
|
OrResult[18] |= OrConstant[8];
|
|
OrResult[20] |= OrConstant[0];
|
|
OrResult[23] |= OrConstant[6];
|
|
OrResult[27] |= OrConstant[9];
|
|
OrResult[30] |= OrConstant[6];
|
|
}
|
|
if ((pClock1[0] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[0] |= OrConstant[21];
|
|
OrResult[3] |= OrConstant[22];
|
|
OrResult[4] |= OrConstant[14];
|
|
OrResult[7] |= OrConstant[16];
|
|
OrResult[10] |= OrConstant[15];
|
|
OrResult[12] |= OrConstant[20];
|
|
OrResult[14] |= OrConstant[12];
|
|
OrResult[17] |= OrConstant[19];
|
|
OrResult[18] |= OrConstant[18];
|
|
OrResult[21] |= OrConstant[18];
|
|
OrResult[23] |= OrConstant[17];
|
|
OrResult[25] |= OrConstant[20];
|
|
OrResult[26] |= OrConstant[13];
|
|
OrResult[30] |= OrConstant[17];
|
|
}
|
|
if ((pClock1[0] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[0] |= OrConstant[13];
|
|
OrResult[2] |= OrConstant[23];
|
|
OrResult[4] |= OrConstant[17];
|
|
OrResult[7] |= OrConstant[22];
|
|
OrResult[8] |= OrConstant[14];
|
|
OrResult[11] |= OrConstant[16];
|
|
OrResult[14] |= OrConstant[15];
|
|
OrResult[19] |= OrConstant[13];
|
|
OrResult[21] |= OrConstant[19];
|
|
OrResult[22] |= OrConstant[18];
|
|
OrResult[25] |= OrConstant[18];
|
|
OrResult[27] |= OrConstant[17];
|
|
OrResult[29] |= OrConstant[20];
|
|
OrResult[31] |= OrConstant[14];
|
|
}
|
|
if ((pClock1[0] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[0] |= OrConstant[18];
|
|
OrResult[3] |= OrConstant[15];
|
|
OrResult[4] |= OrConstant[16];
|
|
OrResult[6] |= OrConstant[19];
|
|
OrResult[9] |= OrConstant[14];
|
|
OrResult[10] |= OrConstant[23];
|
|
OrResult[12] |= OrConstant[17];
|
|
OrResult[15] |= OrConstant[22];
|
|
OrResult[17] |= OrConstant[12];
|
|
OrResult[19] |= OrConstant[23];
|
|
OrResult[20] |= OrConstant[22];
|
|
OrResult[23] |= OrConstant[21];
|
|
OrResult[27] |= OrConstant[13];
|
|
OrResult[29] |= OrConstant[19];
|
|
}
|
|
if ((pClock1[0] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[1] |= OrConstant[21];
|
|
OrResult[2] |= OrConstant[15];
|
|
OrResult[4] |= OrConstant[20];
|
|
OrResult[6] |= OrConstant[12];
|
|
OrResult[11] |= OrConstant[15];
|
|
OrResult[12] |= OrConstant[16];
|
|
OrResult[14] |= OrConstant[19];
|
|
OrResult[17] |= OrConstant[20];
|
|
OrResult[18] |= OrConstant[13];
|
|
OrResult[22] |= OrConstant[21];
|
|
OrResult[25] |= OrConstant[12];
|
|
OrResult[27] |= OrConstant[23];
|
|
OrResult[28] |= OrConstant[22];
|
|
}
|
|
if ((pClock1[1] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[1] |= OrConstant[7];
|
|
OrResult[2] |= OrConstant[11];
|
|
OrResult[5] |= OrConstant[5];
|
|
OrResult[6] |= OrConstant[8];
|
|
OrResult[8] |= OrConstant[0];
|
|
OrResult[11] |= OrConstant[6];
|
|
OrResult[15] |= OrConstant[9];
|
|
OrResult[17] |= OrConstant[4];
|
|
OrResult[18] |= OrConstant[6];
|
|
OrResult[23] |= OrConstant[8];
|
|
OrResult[24] |= OrConstant[4];
|
|
OrResult[27] |= OrConstant[0];
|
|
OrResult[28] |= OrConstant[5];
|
|
OrResult[31] |= OrConstant[3];
|
|
}
|
|
if ((pClock1[1] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[1] |= OrConstant[2];
|
|
OrResult[3] |= OrConstant[6];
|
|
OrResult[7] |= OrConstant[9];
|
|
OrResult[10] |= OrConstant[3];
|
|
OrResult[12] |= OrConstant[10];
|
|
OrResult[15] |= OrConstant[1];
|
|
OrResult[16] |= OrConstant[4];
|
|
OrResult[19] |= OrConstant[0];
|
|
OrResult[20] |= OrConstant[5];
|
|
OrResult[23] |= OrConstant[7];
|
|
OrResult[26] |= OrConstant[2];
|
|
OrResult[29] |= OrConstant[10];
|
|
OrResult[30] |= OrConstant[0];
|
|
}
|
|
if ((pClock1[1] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[0] |= OrConstant[6];
|
|
OrResult[2] |= OrConstant[3];
|
|
OrResult[4] |= OrConstant[10];
|
|
OrResult[7] |= OrConstant[1];
|
|
OrResult[9] |= OrConstant[11];
|
|
OrResult[10] |= OrConstant[9];
|
|
OrResult[13] |= OrConstant[3];
|
|
OrResult[14] |= OrConstant[11];
|
|
OrResult[18] |= OrConstant[2];
|
|
OrResult[21] |= OrConstant[10];
|
|
OrResult[23] |= OrConstant[2];
|
|
OrResult[24] |= OrConstant[1];
|
|
OrResult[26] |= OrConstant[7];
|
|
OrResult[29] |= OrConstant[4];
|
|
}
|
|
if ((pClock1[1] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[0] |= OrConstant[17];
|
|
OrResult[2] |= OrConstant[21];
|
|
OrResult[5] |= OrConstant[12];
|
|
OrResult[7] |= OrConstant[23];
|
|
OrResult[8] |= OrConstant[22];
|
|
OrResult[11] |= OrConstant[21];
|
|
OrResult[15] |= OrConstant[13];
|
|
OrResult[16] |= OrConstant[12];
|
|
OrResult[21] |= OrConstant[15];
|
|
OrResult[22] |= OrConstant[16];
|
|
OrResult[24] |= OrConstant[19];
|
|
OrResult[27] |= OrConstant[14];
|
|
OrResult[28] |= OrConstant[23];
|
|
}
|
|
if ((pClock1[1] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[1] |= OrConstant[14];
|
|
OrResult[2] |= OrConstant[13];
|
|
OrResult[6] |= OrConstant[21];
|
|
OrResult[9] |= OrConstant[12];
|
|
OrResult[11] |= OrConstant[23];
|
|
OrResult[12] |= OrConstant[22];
|
|
OrResult[15] |= OrConstant[21];
|
|
OrResult[16] |= OrConstant[15];
|
|
OrResult[18] |= OrConstant[20];
|
|
OrResult[20] |= OrConstant[12];
|
|
OrResult[25] |= OrConstant[15];
|
|
OrResult[26] |= OrConstant[16];
|
|
OrResult[28] |= OrConstant[19];
|
|
OrResult[31] |= OrConstant[20];
|
|
}
|
|
if ((pClock1[1] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[2] |= OrConstant[18];
|
|
OrResult[5] |= OrConstant[18];
|
|
OrResult[7] |= OrConstant[17];
|
|
OrResult[9] |= OrConstant[20];
|
|
OrResult[10] |= OrConstant[13];
|
|
OrResult[14] |= OrConstant[21];
|
|
OrResult[17] |= OrConstant[22];
|
|
OrResult[18] |= OrConstant[14];
|
|
OrResult[21] |= OrConstant[16];
|
|
OrResult[24] |= OrConstant[15];
|
|
OrResult[26] |= OrConstant[20];
|
|
OrResult[28] |= OrConstant[12];
|
|
OrResult[31] |= OrConstant[19];
|
|
}
|
|
if ((pClock1[1] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[3] |= OrConstant[21];
|
|
OrResult[7] |= OrConstant[13];
|
|
OrResult[9] |= OrConstant[19];
|
|
OrResult[10] |= OrConstant[18];
|
|
OrResult[13] |= OrConstant[18];
|
|
OrResult[15] |= OrConstant[17];
|
|
OrResult[16] |= OrConstant[19];
|
|
OrResult[19] |= OrConstant[14];
|
|
OrResult[20] |= OrConstant[23];
|
|
OrResult[22] |= OrConstant[17];
|
|
OrResult[25] |= OrConstant[22];
|
|
OrResult[26] |= OrConstant[14];
|
|
OrResult[29] |= OrConstant[16];
|
|
OrResult[30] |= OrConstant[22];
|
|
}
|
|
if ((pClock1[2] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[1] |= OrConstant[3];
|
|
OrResult[3] |= OrConstant[7];
|
|
OrResult[6] |= OrConstant[2];
|
|
OrResult[9] |= OrConstant[10];
|
|
OrResult[11] |= OrConstant[2];
|
|
OrResult[12] |= OrConstant[1];
|
|
OrResult[14] |= OrConstant[7];
|
|
OrResult[17] |= OrConstant[9];
|
|
OrResult[20] |= OrConstant[3];
|
|
OrResult[22] |= OrConstant[10];
|
|
OrResult[25] |= OrConstant[1];
|
|
OrResult[27] |= OrConstant[11];
|
|
OrResult[28] |= OrConstant[9];
|
|
OrResult[30] |= OrConstant[5];
|
|
}
|
|
if ((pClock1[2] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[0] |= OrConstant[0];
|
|
OrResult[3] |= OrConstant[2];
|
|
OrResult[4] |= OrConstant[1];
|
|
OrResult[6] |= OrConstant[7];
|
|
OrResult[9] |= OrConstant[4];
|
|
OrResult[10] |= OrConstant[6];
|
|
OrResult[15] |= OrConstant[8];
|
|
OrResult[17] |= OrConstant[1];
|
|
OrResult[19] |= OrConstant[11];
|
|
OrResult[20] |= OrConstant[9];
|
|
OrResult[23] |= OrConstant[3];
|
|
OrResult[24] |= OrConstant[11];
|
|
OrResult[27] |= OrConstant[5];
|
|
OrResult[28] |= OrConstant[8];
|
|
OrResult[31] |= OrConstant[10];
|
|
}
|
|
if ((pClock1[2] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[2] |= OrConstant[6];
|
|
OrResult[7] |= OrConstant[8];
|
|
OrResult[8] |= OrConstant[4];
|
|
OrResult[11] |= OrConstant[0];
|
|
OrResult[12] |= OrConstant[5];
|
|
OrResult[15] |= OrConstant[7];
|
|
OrResult[16] |= OrConstant[11];
|
|
OrResult[19] |= OrConstant[5];
|
|
OrResult[20] |= OrConstant[8];
|
|
OrResult[22] |= OrConstant[0];
|
|
OrResult[25] |= OrConstant[6];
|
|
OrResult[29] |= OrConstant[9];
|
|
OrResult[31] |= OrConstant[4];
|
|
}
|
|
if ((pClock1[2] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[2] |= OrConstant[17];
|
|
OrResult[5] |= OrConstant[22];
|
|
OrResult[6] |= OrConstant[14];
|
|
OrResult[9] |= OrConstant[16];
|
|
OrResult[12] |= OrConstant[15];
|
|
OrResult[14] |= OrConstant[20];
|
|
OrResult[17] |= OrConstant[13];
|
|
OrResult[19] |= OrConstant[19];
|
|
OrResult[20] |= OrConstant[18];
|
|
OrResult[23] |= OrConstant[18];
|
|
OrResult[25] |= OrConstant[17];
|
|
OrResult[27] |= OrConstant[20];
|
|
OrResult[28] |= OrConstant[13];
|
|
OrResult[30] |= OrConstant[23];
|
|
}
|
|
if ((pClock1[2] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[1] |= OrConstant[20];
|
|
OrResult[3] |= OrConstant[14];
|
|
OrResult[4] |= OrConstant[23];
|
|
OrResult[6] |= OrConstant[17];
|
|
OrResult[9] |= OrConstant[22];
|
|
OrResult[10] |= OrConstant[14];
|
|
OrResult[13] |= OrConstant[16];
|
|
OrResult[17] |= OrConstant[21];
|
|
OrResult[21] |= OrConstant[13];
|
|
OrResult[23] |= OrConstant[19];
|
|
OrResult[24] |= OrConstant[18];
|
|
OrResult[27] |= OrConstant[18];
|
|
OrResult[29] |= OrConstant[17];
|
|
OrResult[30] |= OrConstant[19];
|
|
}
|
|
if ((pClock1[2] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[1] |= OrConstant[19];
|
|
OrResult[5] |= OrConstant[15];
|
|
OrResult[6] |= OrConstant[16];
|
|
OrResult[8] |= OrConstant[19];
|
|
OrResult[11] |= OrConstant[14];
|
|
OrResult[12] |= OrConstant[23];
|
|
OrResult[14] |= OrConstant[17];
|
|
OrResult[16] |= OrConstant[21];
|
|
OrResult[19] |= OrConstant[12];
|
|
OrResult[21] |= OrConstant[23];
|
|
OrResult[22] |= OrConstant[22];
|
|
OrResult[25] |= OrConstant[21];
|
|
OrResult[29] |= OrConstant[13];
|
|
OrResult[30] |= OrConstant[12];
|
|
}
|
|
if ((pClock1[2] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[0] |= OrConstant[22];
|
|
OrResult[4] |= OrConstant[15];
|
|
OrResult[6] |= OrConstant[20];
|
|
OrResult[8] |= OrConstant[12];
|
|
OrResult[13] |= OrConstant[15];
|
|
OrResult[14] |= OrConstant[16];
|
|
OrResult[17] |= OrConstant[17];
|
|
OrResult[19] |= OrConstant[20];
|
|
OrResult[20] |= OrConstant[13];
|
|
OrResult[24] |= OrConstant[21];
|
|
OrResult[27] |= OrConstant[12];
|
|
OrResult[29] |= OrConstant[23];
|
|
OrResult[31] |= OrConstant[16];
|
|
}
|
|
if ((pClock1[3] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[0] |= OrConstant[5];
|
|
OrResult[3] |= OrConstant[3];
|
|
OrResult[4] |= OrConstant[11];
|
|
OrResult[7] |= OrConstant[5];
|
|
OrResult[8] |= OrConstant[8];
|
|
OrResult[10] |= OrConstant[0];
|
|
OrResult[13] |= OrConstant[6];
|
|
OrResult[16] |= OrConstant[7];
|
|
OrResult[19] |= OrConstant[4];
|
|
OrResult[20] |= OrConstant[6];
|
|
OrResult[25] |= OrConstant[8];
|
|
OrResult[26] |= OrConstant[4];
|
|
OrResult[29] |= OrConstant[0];
|
|
OrResult[30] |= OrConstant[9];
|
|
}
|
|
if ((pClock1[3] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[1] |= OrConstant[10];
|
|
OrResult[2] |= OrConstant[0];
|
|
OrResult[5] |= OrConstant[6];
|
|
OrResult[9] |= OrConstant[9];
|
|
OrResult[12] |= OrConstant[3];
|
|
OrResult[14] |= OrConstant[10];
|
|
OrResult[17] |= OrConstant[8];
|
|
OrResult[18] |= OrConstant[4];
|
|
OrResult[21] |= OrConstant[0];
|
|
OrResult[22] |= OrConstant[5];
|
|
OrResult[25] |= OrConstant[7];
|
|
OrResult[28] |= OrConstant[2];
|
|
OrResult[30] |= OrConstant[8];
|
|
}
|
|
if ((pClock1[3] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[1] |= OrConstant[4];
|
|
OrResult[4] |= OrConstant[3];
|
|
OrResult[6] |= OrConstant[10];
|
|
OrResult[9] |= OrConstant[1];
|
|
OrResult[11] |= OrConstant[11];
|
|
OrResult[12] |= OrConstant[9];
|
|
OrResult[15] |= OrConstant[3];
|
|
OrResult[17] |= OrConstant[7];
|
|
OrResult[20] |= OrConstant[2];
|
|
OrResult[23] |= OrConstant[10];
|
|
OrResult[25] |= OrConstant[2];
|
|
OrResult[26] |= OrConstant[1];
|
|
OrResult[28] |= OrConstant[7];
|
|
OrResult[31] |= OrConstant[9];
|
|
}
|
|
if ((pClock1[3] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[0] |= OrConstant[23];
|
|
OrResult[4] |= OrConstant[21];
|
|
OrResult[7] |= OrConstant[12];
|
|
OrResult[9] |= OrConstant[23];
|
|
OrResult[10] |= OrConstant[22];
|
|
OrResult[13] |= OrConstant[21];
|
|
OrResult[16] |= OrConstant[20];
|
|
OrResult[18] |= OrConstant[12];
|
|
OrResult[23] |= OrConstant[15];
|
|
OrResult[24] |= OrConstant[16];
|
|
OrResult[26] |= OrConstant[19];
|
|
OrResult[29] |= OrConstant[14];
|
|
OrResult[30] |= OrConstant[13];
|
|
}
|
|
if ((pClock1[3] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[0] |= OrConstant[19];
|
|
OrResult[3] |= OrConstant[20];
|
|
OrResult[4] |= OrConstant[13];
|
|
OrResult[8] |= OrConstant[21];
|
|
OrResult[11] |= OrConstant[12];
|
|
OrResult[13] |= OrConstant[23];
|
|
OrResult[14] |= OrConstant[22];
|
|
OrResult[18] |= OrConstant[15];
|
|
OrResult[20] |= OrConstant[20];
|
|
OrResult[22] |= OrConstant[12];
|
|
OrResult[27] |= OrConstant[15];
|
|
OrResult[28] |= OrConstant[16];
|
|
OrResult[31] |= OrConstant[17];
|
|
}
|
|
if ((pClock1[3] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[0] |= OrConstant[12];
|
|
OrResult[3] |= OrConstant[19];
|
|
OrResult[4] |= OrConstant[18];
|
|
OrResult[7] |= OrConstant[18];
|
|
OrResult[9] |= OrConstant[17];
|
|
OrResult[11] |= OrConstant[20];
|
|
OrResult[12] |= OrConstant[13];
|
|
OrResult[16] |= OrConstant[17];
|
|
OrResult[19] |= OrConstant[22];
|
|
OrResult[20] |= OrConstant[14];
|
|
OrResult[23] |= OrConstant[16];
|
|
OrResult[26] |= OrConstant[15];
|
|
OrResult[28] |= OrConstant[20];
|
|
OrResult[31] |= OrConstant[13];
|
|
}
|
|
if ((pClock1[3] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[1] |= OrConstant[16];
|
|
OrResult[2] |= OrConstant[22];
|
|
OrResult[5] |= OrConstant[21];
|
|
OrResult[9] |= OrConstant[13];
|
|
OrResult[11] |= OrConstant[19];
|
|
OrResult[12] |= OrConstant[18];
|
|
OrResult[15] |= OrConstant[18];
|
|
OrResult[16] |= OrConstant[16];
|
|
OrResult[18] |= OrConstant[19];
|
|
OrResult[21] |= OrConstant[14];
|
|
OrResult[22] |= OrConstant[23];
|
|
OrResult[24] |= OrConstant[17];
|
|
OrResult[27] |= OrConstant[22];
|
|
OrResult[28] |= OrConstant[14];
|
|
OrResult[31] |= OrConstant[23];
|
|
}
|
|
if ((pClock1[4] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[0] |= OrConstant[9];
|
|
OrResult[2] |= OrConstant[5];
|
|
OrResult[5] |= OrConstant[7];
|
|
OrResult[8] |= OrConstant[2];
|
|
OrResult[11] |= OrConstant[10];
|
|
OrResult[13] |= OrConstant[2];
|
|
OrResult[14] |= OrConstant[1];
|
|
OrResult[19] |= OrConstant[9];
|
|
OrResult[22] |= OrConstant[3];
|
|
OrResult[24] |= OrConstant[10];
|
|
OrResult[27] |= OrConstant[1];
|
|
OrResult[29] |= OrConstant[11];
|
|
OrResult[31] |= OrConstant[0];
|
|
}
|
|
if ((pClock1[4] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[0] |= OrConstant[8];
|
|
OrResult[3] |= OrConstant[10];
|
|
OrResult[5] |= OrConstant[2];
|
|
OrResult[6] |= OrConstant[1];
|
|
OrResult[8] |= OrConstant[7];
|
|
OrResult[11] |= OrConstant[4];
|
|
OrResult[12] |= OrConstant[6];
|
|
OrResult[16] |= OrConstant[10];
|
|
OrResult[19] |= OrConstant[1];
|
|
OrResult[21] |= OrConstant[11];
|
|
OrResult[22] |= OrConstant[9];
|
|
OrResult[25] |= OrConstant[3];
|
|
OrResult[26] |= OrConstant[11];
|
|
OrResult[29] |= OrConstant[5];
|
|
OrResult[30] |= OrConstant[2];
|
|
}
|
|
if ((pClock1[4] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[1] |= OrConstant[9];
|
|
OrResult[3] |= OrConstant[4];
|
|
OrResult[4] |= OrConstant[6];
|
|
OrResult[9] |= OrConstant[8];
|
|
OrResult[10] |= OrConstant[4];
|
|
OrResult[13] |= OrConstant[0];
|
|
OrResult[14] |= OrConstant[5];
|
|
OrResult[17] |= OrConstant[3];
|
|
OrResult[18] |= OrConstant[11];
|
|
OrResult[21] |= OrConstant[5];
|
|
OrResult[22] |= OrConstant[8];
|
|
OrResult[24] |= OrConstant[0];
|
|
OrResult[27] |= OrConstant[6];
|
|
OrResult[30] |= OrConstant[7];
|
|
}
|
|
if ((pClock1[4] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[1] |= OrConstant[1];
|
|
OrResult[2] |= OrConstant[4];
|
|
OrResult[5] |= OrConstant[0];
|
|
OrResult[6] |= OrConstant[5];
|
|
OrResult[9] |= OrConstant[7];
|
|
OrResult[12] |= OrConstant[2];
|
|
OrResult[15] |= OrConstant[10];
|
|
OrResult[16] |= OrConstant[0];
|
|
OrResult[19] |= OrConstant[6];
|
|
OrResult[23] |= OrConstant[9];
|
|
OrResult[26] |= OrConstant[3];
|
|
OrResult[28] |= OrConstant[10];
|
|
OrResult[31] |= OrConstant[8];
|
|
}
|
|
if ((pClock1[4] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[1] |= OrConstant[17];
|
|
OrResult[2] |= OrConstant[19];
|
|
OrResult[5] |= OrConstant[14];
|
|
OrResult[6] |= OrConstant[23];
|
|
OrResult[8] |= OrConstant[17];
|
|
OrResult[11] |= OrConstant[22];
|
|
OrResult[12] |= OrConstant[14];
|
|
OrResult[15] |= OrConstant[16];
|
|
OrResult[16] |= OrConstant[22];
|
|
OrResult[19] |= OrConstant[21];
|
|
OrResult[23] |= OrConstant[13];
|
|
OrResult[25] |= OrConstant[19];
|
|
OrResult[26] |= OrConstant[18];
|
|
OrResult[29] |= OrConstant[18];
|
|
OrResult[30] |= OrConstant[16];
|
|
}
|
|
if ((pClock1[4] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[1] |= OrConstant[13];
|
|
OrResult[2] |= OrConstant[12];
|
|
OrResult[7] |= OrConstant[15];
|
|
OrResult[8] |= OrConstant[16];
|
|
OrResult[10] |= OrConstant[19];
|
|
OrResult[13] |= OrConstant[14];
|
|
OrResult[14] |= OrConstant[23];
|
|
OrResult[18] |= OrConstant[21];
|
|
OrResult[21] |= OrConstant[12];
|
|
OrResult[23] |= OrConstant[23];
|
|
OrResult[24] |= OrConstant[22];
|
|
OrResult[27] |= OrConstant[21];
|
|
OrResult[30] |= OrConstant[20];
|
|
}
|
|
if ((pClock1[4] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[1] |= OrConstant[23];
|
|
OrResult[3] |= OrConstant[16];
|
|
OrResult[6] |= OrConstant[15];
|
|
OrResult[8] |= OrConstant[20];
|
|
OrResult[10] |= OrConstant[12];
|
|
OrResult[15] |= OrConstant[15];
|
|
OrResult[17] |= OrConstant[18];
|
|
OrResult[19] |= OrConstant[17];
|
|
OrResult[21] |= OrConstant[20];
|
|
OrResult[22] |= OrConstant[13];
|
|
OrResult[26] |= OrConstant[21];
|
|
OrResult[29] |= OrConstant[12];
|
|
OrResult[30] |= OrConstant[14];
|
|
}
|
|
if ((pClock1[5] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[1] |= OrConstant[0];
|
|
OrResult[2] |= OrConstant[9];
|
|
OrResult[5] |= OrConstant[3];
|
|
OrResult[6] |= OrConstant[11];
|
|
OrResult[9] |= OrConstant[5];
|
|
OrResult[10] |= OrConstant[8];
|
|
OrResult[12] |= OrConstant[0];
|
|
OrResult[15] |= OrConstant[6];
|
|
OrResult[16] |= OrConstant[1];
|
|
OrResult[18] |= OrConstant[7];
|
|
OrResult[21] |= OrConstant[4];
|
|
OrResult[22] |= OrConstant[6];
|
|
OrResult[27] |= OrConstant[8];
|
|
OrResult[28] |= OrConstant[4];
|
|
OrResult[31] |= OrConstant[11];
|
|
}
|
|
if ((pClock1[5] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[0] |= OrConstant[2];
|
|
OrResult[2] |= OrConstant[8];
|
|
OrResult[4] |= OrConstant[0];
|
|
OrResult[7] |= OrConstant[6];
|
|
OrResult[11] |= OrConstant[9];
|
|
OrResult[14] |= OrConstant[3];
|
|
OrResult[19] |= OrConstant[8];
|
|
OrResult[20] |= OrConstant[4];
|
|
OrResult[23] |= OrConstant[0];
|
|
OrResult[24] |= OrConstant[5];
|
|
OrResult[27] |= OrConstant[7];
|
|
OrResult[31] |= OrConstant[5];
|
|
}
|
|
if ((pClock1[5] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[0] |= OrConstant[7];
|
|
OrResult[3] |= OrConstant[9];
|
|
OrResult[6] |= OrConstant[3];
|
|
OrResult[8] |= OrConstant[10];
|
|
OrResult[11] |= OrConstant[1];
|
|
OrResult[13] |= OrConstant[11];
|
|
OrResult[14] |= OrConstant[9];
|
|
OrResult[16] |= OrConstant[5];
|
|
OrResult[19] |= OrConstant[7];
|
|
OrResult[22] |= OrConstant[2];
|
|
OrResult[25] |= OrConstant[10];
|
|
OrResult[27] |= OrConstant[2];
|
|
OrResult[28] |= OrConstant[1];
|
|
}
|
|
if ((pClock1[5] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[1] |= OrConstant[8];
|
|
OrResult[3] |= OrConstant[1];
|
|
OrResult[5] |= OrConstant[11];
|
|
OrResult[6] |= OrConstant[9];
|
|
OrResult[9] |= OrConstant[3];
|
|
OrResult[10] |= OrConstant[11];
|
|
OrResult[13] |= OrConstant[5];
|
|
OrResult[14] |= OrConstant[8];
|
|
OrResult[17] |= OrConstant[10];
|
|
OrResult[19] |= OrConstant[2];
|
|
OrResult[20] |= OrConstant[1];
|
|
OrResult[22] |= OrConstant[7];
|
|
OrResult[25] |= OrConstant[4];
|
|
OrResult[26] |= OrConstant[6];
|
|
OrResult[30] |= OrConstant[10];
|
|
}
|
|
if ((pClock1[5] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[0] |= OrConstant[16];
|
|
OrResult[3] |= OrConstant[17];
|
|
OrResult[5] |= OrConstant[20];
|
|
OrResult[6] |= OrConstant[13];
|
|
OrResult[10] |= OrConstant[21];
|
|
OrResult[13] |= OrConstant[12];
|
|
OrResult[15] |= OrConstant[23];
|
|
OrResult[17] |= OrConstant[16];
|
|
OrResult[20] |= OrConstant[15];
|
|
OrResult[22] |= OrConstant[20];
|
|
OrResult[24] |= OrConstant[12];
|
|
OrResult[29] |= OrConstant[15];
|
|
OrResult[31] |= OrConstant[18];
|
|
}
|
|
if ((pClock1[5] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[0] |= OrConstant[20];
|
|
OrResult[3] |= OrConstant[13];
|
|
OrResult[5] |= OrConstant[19];
|
|
OrResult[6] |= OrConstant[18];
|
|
OrResult[9] |= OrConstant[18];
|
|
OrResult[11] |= OrConstant[17];
|
|
OrResult[13] |= OrConstant[20];
|
|
OrResult[14] |= OrConstant[13];
|
|
OrResult[16] |= OrConstant[23];
|
|
OrResult[18] |= OrConstant[17];
|
|
OrResult[21] |= OrConstant[22];
|
|
OrResult[22] |= OrConstant[14];
|
|
OrResult[25] |= OrConstant[16];
|
|
OrResult[28] |= OrConstant[15];
|
|
}
|
|
if ((pClock1[5] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[0] |= OrConstant[14];
|
|
OrResult[3] |= OrConstant[23];
|
|
OrResult[4] |= OrConstant[22];
|
|
OrResult[7] |= OrConstant[21];
|
|
OrResult[11] |= OrConstant[13];
|
|
OrResult[13] |= OrConstant[19];
|
|
OrResult[14] |= OrConstant[18];
|
|
OrResult[17] |= OrConstant[15];
|
|
OrResult[18] |= OrConstant[16];
|
|
OrResult[20] |= OrConstant[19];
|
|
OrResult[23] |= OrConstant[14];
|
|
OrResult[24] |= OrConstant[23];
|
|
OrResult[26] |= OrConstant[17];
|
|
OrResult[29] |= OrConstant[22];
|
|
OrResult[31] |= OrConstant[12];
|
|
}
|
|
if ((pClock1[6] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[1] |= OrConstant[11];
|
|
OrResult[3] |= OrConstant[0];
|
|
OrResult[4] |= OrConstant[5];
|
|
OrResult[7] |= OrConstant[7];
|
|
OrResult[10] |= OrConstant[2];
|
|
OrResult[13] |= OrConstant[10];
|
|
OrResult[15] |= OrConstant[2];
|
|
OrResult[17] |= OrConstant[6];
|
|
OrResult[21] |= OrConstant[9];
|
|
OrResult[24] |= OrConstant[3];
|
|
OrResult[26] |= OrConstant[10];
|
|
OrResult[29] |= OrConstant[1];
|
|
OrResult[30] |= OrConstant[4];
|
|
}
|
|
if ((pClock1[6] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[1] |= OrConstant[5];
|
|
OrResult[2] |= OrConstant[2];
|
|
OrResult[5] |= OrConstant[10];
|
|
OrResult[7] |= OrConstant[2];
|
|
OrResult[8] |= OrConstant[1];
|
|
OrResult[10] |= OrConstant[7];
|
|
OrResult[13] |= OrConstant[4];
|
|
OrResult[14] |= OrConstant[6];
|
|
OrResult[16] |= OrConstant[3];
|
|
OrResult[18] |= OrConstant[10];
|
|
OrResult[21] |= OrConstant[1];
|
|
OrResult[23] |= OrConstant[11];
|
|
OrResult[24] |= OrConstant[9];
|
|
OrResult[27] |= OrConstant[3];
|
|
OrResult[28] |= OrConstant[11];
|
|
}
|
|
if ((pClock1[6] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[2] |= OrConstant[7];
|
|
OrResult[5] |= OrConstant[4];
|
|
OrResult[6] |= OrConstant[6];
|
|
OrResult[11] |= OrConstant[8];
|
|
OrResult[12] |= OrConstant[4];
|
|
OrResult[15] |= OrConstant[0];
|
|
OrResult[16] |= OrConstant[9];
|
|
OrResult[19] |= OrConstant[3];
|
|
OrResult[20] |= OrConstant[11];
|
|
OrResult[23] |= OrConstant[5];
|
|
OrResult[24] |= OrConstant[8];
|
|
OrResult[26] |= OrConstant[0];
|
|
OrResult[29] |= OrConstant[6];
|
|
OrResult[30] |= OrConstant[1];
|
|
}
|
|
if ((pClock1[6] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[0] |= OrConstant[10];
|
|
OrResult[3] |= OrConstant[8];
|
|
OrResult[4] |= OrConstant[4];
|
|
OrResult[7] |= OrConstant[0];
|
|
OrResult[8] |= OrConstant[5];
|
|
OrResult[11] |= OrConstant[7];
|
|
OrResult[14] |= OrConstant[2];
|
|
OrResult[16] |= OrConstant[8];
|
|
OrResult[18] |= OrConstant[0];
|
|
OrResult[21] |= OrConstant[6];
|
|
OrResult[25] |= OrConstant[9];
|
|
OrResult[28] |= OrConstant[3];
|
|
}
|
|
if ((pClock1[6] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[1] |= OrConstant[18];
|
|
OrResult[2] |= OrConstant[16];
|
|
OrResult[4] |= OrConstant[19];
|
|
OrResult[7] |= OrConstant[14];
|
|
OrResult[8] |= OrConstant[23];
|
|
OrResult[10] |= OrConstant[17];
|
|
OrResult[13] |= OrConstant[22];
|
|
OrResult[14] |= OrConstant[14];
|
|
OrResult[17] |= OrConstant[23];
|
|
OrResult[18] |= OrConstant[22];
|
|
OrResult[21] |= OrConstant[21];
|
|
OrResult[25] |= OrConstant[13];
|
|
OrResult[27] |= OrConstant[19];
|
|
OrResult[28] |= OrConstant[18];
|
|
OrResult[31] |= OrConstant[15];
|
|
}
|
|
if ((pClock1[6] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[2] |= OrConstant[20];
|
|
OrResult[4] |= OrConstant[12];
|
|
OrResult[9] |= OrConstant[15];
|
|
OrResult[10] |= OrConstant[16];
|
|
OrResult[12] |= OrConstant[19];
|
|
OrResult[15] |= OrConstant[14];
|
|
OrResult[16] |= OrConstant[13];
|
|
OrResult[20] |= OrConstant[21];
|
|
OrResult[23] |= OrConstant[12];
|
|
OrResult[25] |= OrConstant[23];
|
|
OrResult[26] |= OrConstant[22];
|
|
OrResult[29] |= OrConstant[21];
|
|
OrResult[30] |= OrConstant[15];
|
|
}
|
|
if ((pClock1[6] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[1] |= OrConstant[12];
|
|
OrResult[2] |= OrConstant[14];
|
|
OrResult[5] |= OrConstant[16];
|
|
OrResult[8] |= OrConstant[15];
|
|
OrResult[10] |= OrConstant[20];
|
|
OrResult[12] |= OrConstant[12];
|
|
OrResult[16] |= OrConstant[18];
|
|
OrResult[19] |= OrConstant[18];
|
|
OrResult[21] |= OrConstant[17];
|
|
OrResult[23] |= OrConstant[20];
|
|
OrResult[24] |= OrConstant[13];
|
|
OrResult[28] |= OrConstant[21];
|
|
OrResult[31] |= OrConstant[22];
|
|
}
|
|
if ((pClock1[7] & 0x80 ) == 0x80)
|
|
{
|
|
OrResult[0] |= OrConstant[4];
|
|
OrResult[3] |= OrConstant[11];
|
|
OrResult[4] |= OrConstant[9];
|
|
OrResult[7] |= OrConstant[3];
|
|
OrResult[8] |= OrConstant[11];
|
|
OrResult[11] |= OrConstant[5];
|
|
OrResult[12] |= OrConstant[8];
|
|
OrResult[14] |= OrConstant[0];
|
|
OrResult[17] |= OrConstant[2];
|
|
OrResult[18] |= OrConstant[1];
|
|
OrResult[20] |= OrConstant[7];
|
|
OrResult[23] |= OrConstant[4];
|
|
OrResult[24] |= OrConstant[6];
|
|
OrResult[29] |= OrConstant[8];
|
|
OrResult[31] |= OrConstant[1];
|
|
}
|
|
if ((pClock1[7] & 0x40 ) == 0x40)
|
|
{
|
|
OrResult[3] |= OrConstant[5];
|
|
OrResult[4] |= OrConstant[8];
|
|
OrResult[6] |= OrConstant[0];
|
|
OrResult[9] |= OrConstant[6];
|
|
OrResult[13] |= OrConstant[9];
|
|
OrResult[16] |= OrConstant[6];
|
|
OrResult[21] |= OrConstant[8];
|
|
OrResult[22] |= OrConstant[4];
|
|
OrResult[25] |= OrConstant[0];
|
|
OrResult[26] |= OrConstant[5];
|
|
OrResult[29] |= OrConstant[7];
|
|
OrResult[30] |= OrConstant[11];
|
|
}
|
|
if ((pClock1[7] & 0x20 ) == 0x20)
|
|
{
|
|
OrResult[0] |= OrConstant[1];
|
|
OrResult[5] |= OrConstant[9];
|
|
OrResult[8] |= OrConstant[3];
|
|
OrResult[10] |= OrConstant[10];
|
|
OrResult[13] |= OrConstant[1];
|
|
OrResult[15] |= OrConstant[11];
|
|
OrResult[17] |= OrConstant[0];
|
|
OrResult[18] |= OrConstant[5];
|
|
OrResult[21] |= OrConstant[7];
|
|
OrResult[24] |= OrConstant[2];
|
|
OrResult[27] |= OrConstant[10];
|
|
OrResult[29] |= OrConstant[2];
|
|
OrResult[31] |= OrConstant[6];
|
|
}
|
|
if ((pClock1[7] & 0x10 ) == 0x10)
|
|
{
|
|
OrResult[2] |= OrConstant[10];
|
|
OrResult[5] |= OrConstant[1];
|
|
OrResult[7] |= OrConstant[11];
|
|
OrResult[8] |= OrConstant[9];
|
|
OrResult[11] |= OrConstant[3];
|
|
OrResult[12] |= OrConstant[11];
|
|
OrResult[15] |= OrConstant[5];
|
|
OrResult[16] |= OrConstant[2];
|
|
OrResult[19] |= OrConstant[10];
|
|
OrResult[21] |= OrConstant[2];
|
|
OrResult[22] |= OrConstant[1];
|
|
OrResult[24] |= OrConstant[7];
|
|
OrResult[27] |= OrConstant[4];
|
|
OrResult[28] |= OrConstant[6];
|
|
OrResult[30] |= OrConstant[3];
|
|
}
|
|
if ((pClock1[7] & 0x08 ) == 0x08)
|
|
{
|
|
OrResult[1] |= OrConstant[15];
|
|
OrResult[3] |= OrConstant[18];
|
|
OrResult[5] |= OrConstant[17];
|
|
OrResult[7] |= OrConstant[20];
|
|
OrResult[8] |= OrConstant[13];
|
|
OrResult[12] |= OrConstant[21];
|
|
OrResult[15] |= OrConstant[12];
|
|
OrResult[16] |= OrConstant[14];
|
|
OrResult[19] |= OrConstant[16];
|
|
OrResult[22] |= OrConstant[15];
|
|
OrResult[24] |= OrConstant[20];
|
|
OrResult[26] |= OrConstant[12];
|
|
OrResult[30] |= OrConstant[18];
|
|
}
|
|
if ((pClock1[7] & 0x04 ) == 0x04)
|
|
{
|
|
OrResult[0] |= OrConstant[15];
|
|
OrResult[5] |= OrConstant[13];
|
|
OrResult[7] |= OrConstant[19];
|
|
OrResult[8] |= OrConstant[18];
|
|
OrResult[11] |= OrConstant[18];
|
|
OrResult[13] |= OrConstant[17];
|
|
OrResult[15] |= OrConstant[20];
|
|
OrResult[17] |= OrConstant[14];
|
|
OrResult[18] |= OrConstant[23];
|
|
OrResult[20] |= OrConstant[17];
|
|
OrResult[23] |= OrConstant[22];
|
|
OrResult[24] |= OrConstant[14];
|
|
OrResult[27] |= OrConstant[16];
|
|
OrResult[31] |= OrConstant[21];
|
|
}
|
|
if ((pClock1[7] & 0x02 ) == 0x02)
|
|
{
|
|
OrResult[1] |= OrConstant[22];
|
|
OrResult[3] |= OrConstant[12];
|
|
OrResult[5] |= OrConstant[23];
|
|
OrResult[6] |= OrConstant[22];
|
|
OrResult[9] |= OrConstant[21];
|
|
OrResult[13] |= OrConstant[13];
|
|
OrResult[15] |= OrConstant[19];
|
|
OrResult[19] |= OrConstant[15];
|
|
OrResult[20] |= OrConstant[16];
|
|
OrResult[22] |= OrConstant[19];
|
|
OrResult[25] |= OrConstant[14];
|
|
OrResult[26] |= OrConstant[23];
|
|
OrResult[28] |= OrConstant[17];
|
|
OrResult[30] |= OrConstant[21];
|
|
}
|
|
|
|
// Process the 32 OrResult[] values and the XorClocks value
|
|
// to produce 2 XorResult[] values.
|
|
FETCH_FW( wv[3], XorClocks+0 );
|
|
FETCH_FW( wv[4], XorClocks+4 );
|
|
j = 30; // Index to last two OrResult[] values.
|
|
wv[0] = 252; // 252 = 0x000000fc
|
|
wv[9] = 16; // 16 = 0x00000010
|
|
wv[2] = wv[3];
|
|
wv[5] = wv[4];
|
|
shift_right_dbl( &wv[2], &wv[3], 1 );
|
|
shift_right_dbl( &wv[4], &wv[5], 1 );
|
|
|
|
for( i = 0; i <= 15; i++ )
|
|
{
|
|
wv[2] = wv[5];
|
|
wv[6] = wv[5];
|
|
wv[7] = wv[5];
|
|
shift_right_dbl( &wv[6], &wv[7], 28 );
|
|
wv[5] ^= OrResult[j];
|
|
wv[7] ^= OrResult[j + 1];
|
|
shift_left_dbl( &wv[4], &wv[5], 8 );
|
|
shift_left_dbl( &wv[6], &wv[7], 8 );
|
|
wv[1] = wv[4];
|
|
wv[14] = wv[6];
|
|
shift_left_dbl( &wv[4], &wv[5], 8 );
|
|
shift_left_dbl( &wv[6], &wv[7], 8 );
|
|
wv[1] &= wv[0];
|
|
wv[14] &= wv[0];
|
|
wv[4] &= wv[0];
|
|
wv[6] &= wv[0];
|
|
wv[3] ^= XorConstant[0 + ( wv[1] / 4)];
|
|
wv[3] ^= XorConstant[64 + ( wv[14] / 4)];
|
|
wv[3] ^= XorConstant[128 + ( wv[4] / 4 )];
|
|
wv[3] ^= XorConstant[192 + ( wv[6] / 4 )];
|
|
shift_left_dbl( &wv[4], &wv[5], 8 );
|
|
shift_left_dbl( &wv[6], &wv[7], 8 );
|
|
wv[1] = wv[4];
|
|
wv[14] = wv[6];
|
|
shift_left_dbl( &wv[4], &wv[5], 8 );
|
|
shift_left_dbl( &wv[6], &wv[7], 8 );
|
|
wv[1] &= wv[0];
|
|
wv[14] &= wv[0];
|
|
wv[4] &= wv[0];
|
|
wv[6] &= wv[0];
|
|
wv[3] ^= XorConstant[256 + ( wv[1] / 4 )];
|
|
wv[3] ^= XorConstant[320 + ( wv[14] / 4 )];
|
|
wv[3] ^= XorConstant[384 + ( wv[4] / 4 )];
|
|
wv[3] ^= XorConstant[448 + ( wv[6] / 4 )];
|
|
wv[5] = wv[3];
|
|
wv[3] = wv[2];
|
|
j = j - 2; // Index to previous two OrResult[] values.
|
|
}
|
|
|
|
wv[6] = wv[5];
|
|
wv[7] = wv[6];
|
|
shift_left_dbl( &wv[2], &wv[3], 1 );
|
|
shift_left_dbl( &wv[6], &wv[7], 1 );
|
|
wv[3] = wv[6];
|
|
wv[4] = wv[2];
|
|
XorResult[0] = wv[3];
|
|
XorResult[1] = wv[4];
|
|
|
|
// Return the 2 XorResult[] values in the output pToken value.
|
|
STORE_FW( pToken+0, XorResult[0] );
|
|
STORE_FW( pToken+4, XorResult[1] );
|
|
|
|
return;
|
|
} /* End function gen_csv_sid() */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* shift_left_dbl() and shift_right_dl() */
|
|
/* ------------------------------------------------------------------ */
|
|
// These two functions emulate the action of the S/390 SLDL and SRDL
|
|
// machine instructions. The machine instructions treat an even-odd
|
|
// pair of 32-bit registers as a 64-bit value to be shifted left or
|
|
// right the specified number of bits. The machine instructions only
|
|
// require the even numbered register to be specified; these emulations
|
|
// require both 32-bit values to be specified.
|
|
|
|
void shift_left_dbl( U32* even, U32* odd, int number )
|
|
{
|
|
U64 dw;
|
|
|
|
dw = *even; // Combine the two
|
|
dw <<= 32; // U32 values into
|
|
dw |= *odd; // one U64 value
|
|
|
|
dw <<= number; // Shift left the appropriate number
|
|
|
|
*odd = (U32)dw; // Separate the U64
|
|
dw >>= 32; // value into
|
|
*even = (U32)dw; // two U32 values.
|
|
|
|
return;
|
|
} /* End function shift_left_dbl() */
|
|
|
|
void shift_right_dbl( U32* even, U32* odd, int number )
|
|
{
|
|
U64 dw;
|
|
|
|
dw = *even; // Combine the two
|
|
dw <<= 32; // U32 values into
|
|
dw |= *odd; // one U64 value
|
|
|
|
dw >>= number; // Shift right the appropriate number
|
|
|
|
*odd = (U32)dw; // Separate the U64
|
|
dw >>= 32; // value into
|
|
*even = (U32)dw; // two U32 values.
|
|
|
|
return;
|
|
} /* End function shift_right_dbl() */
|
|
|
|
|
|
#if defined(ENABLE_IPV6)
|
|
/* ------------------------------------------------------------------ */
|
|
/* calculate_icmpv6_checksum() */
|
|
/* ------------------------------------------------------------------ */
|
|
// This is not a general purpose function, it is solely for calculating
|
|
// the checksum of ICMPv6 packets sent to the guest on the y-side. The
|
|
// following restriction apply:-
|
|
// - If the ICMPv6 header and message has a length that is an odd number
|
|
// of bytes, they must be followed by a byte containing zero.
|
|
// - Any existing checksum in the ICMPv6 header will be over-written.
|
|
//
|
|
// The ICMPv6 header and message layout is:-
|
|
// byte 0 Type: specifies the format of the message.
|
|
// byte 1 Code: further qualifies the message
|
|
// bytes 2-3 Checksum.
|
|
// byte 4-n Message.
|
|
//
|
|
// The Hop-by-Hop Options extension header layout is:-
|
|
// byte 0 Next Header: will be 58 (0x3a), ICMPv6 header.
|
|
// byte 1 Header Extension Length: the header's overall length
|
|
// 0 = 8-bytes, 1 = 16-bytes, 2 = 24-bytes, etc.
|
|
// byte 2-n One or more option fields.
|
|
//
|
|
|
|
void calculate_icmpv6_checksum( PIP6FRM pIP6FRM, BYTE* pIcmpHdr, int iIcmpLen )
|
|
{
|
|
BYTE* pBytePtr;
|
|
int i,j;
|
|
U16 uTwobytes; // Two bytes of data
|
|
U32 uHighhalf; // High-order half of the checksum
|
|
U32 uChecksum; // The checksum
|
|
BYTE bPseudoHeader[40]; // 0-15 Source address
|
|
// 16-31 Destination address
|
|
// 32-35 Upper-layer packet length
|
|
// 36-38 zero
|
|
// 39 Next Header (i.e. 58 (0x3a))
|
|
|
|
|
|
// Clear the checksum in the ICMP header before calculating the checksum.
|
|
STORE_HW( pIcmpHdr+2, 0x0000 );
|
|
|
|
// Construct the Psuedo-Header for the checksum calculation.
|
|
memcpy( bPseudoHeader+0, pIP6FRM->bSrcAddr, 16 );
|
|
memcpy( bPseudoHeader+16, pIP6FRM->bDstAddr, 16 );
|
|
STORE_FW( bPseudoHeader+32, iIcmpLen );
|
|
for( i = 36; i <= 38; i++ )
|
|
bPseudoHeader[i] = 0x00;
|
|
bPseudoHeader[39] = 0x3A;
|
|
|
|
// Calculate the checksum.
|
|
uChecksum = 0;
|
|
for( i = 0; i <= 38; i += 2 )
|
|
{
|
|
FETCH_HW( uTwobytes, bPseudoHeader+i );
|
|
uChecksum += uTwobytes;
|
|
}
|
|
pBytePtr = pIcmpHdr; // Point to the ICMPv6 header.
|
|
j = iIcmpLen; // Get the length of the
|
|
j++; // ICMPv6 packet rounded up
|
|
j &= 0xFFFFFFFE; // to the next multiple of two.
|
|
for( i = 0; i <= j - 2; i += 2 )
|
|
{
|
|
FETCH_HW( uTwobytes, pBytePtr );
|
|
uChecksum += uTwobytes;
|
|
pBytePtr += 2;
|
|
}
|
|
uHighhalf = uChecksum >> 16; // Get the high-order half
|
|
// of the checksum value.
|
|
uChecksum &= 0x0000FFFF; // Get the low-order half.
|
|
uChecksum += uHighhalf; // Add the high-order half
|
|
// to the low-order half.
|
|
uHighhalf = uChecksum >> 16; // Get the high-order half
|
|
// of the checksum value again.
|
|
uChecksum &= 0x0000FFFF; // Get the low-order half.
|
|
uChecksum += uHighhalf; // Add the high-order half
|
|
// to the low-order half again
|
|
// to include any carry.
|
|
uChecksum ^= 0xFFFFFFFF; // Complement the bits.
|
|
uChecksum &= 0x0000FFFF; // Get a clean checksum.
|
|
uTwobytes = uChecksum; // Copy to a two-byte value.
|
|
|
|
// Set the checksum in the ICMP header.
|
|
STORE_HW( pIcmpHdr+2, uTwobytes );
|
|
|
|
return;
|
|
} /* End function calculate_icmpv6_checksum() */
|
|
#endif /* defined(ENABLE_IPV6) */
|
|
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* HDL stuff */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* Libtool static name collision resolution */
|
|
/* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
|
|
|
|
#if defined( HDL_USE_LIBTOOL )
|
|
#define hdl_ddev hdtptp_LTX_hdl_ddev
|
|
#define hdl_depc hdtptp_LTX_hdl_depc
|
|
#define hdl_reso hdtptp_LTX_hdl_reso
|
|
#define hdl_init hdtptp_LTX_hdl_init
|
|
#define hdl_fini hdtptp_LTX_hdl_fini
|
|
#endif
|
|
|
|
|
|
HDL_DEPENDENCY_SECTION;
|
|
{
|
|
HDL_DEPENDENCY( HERCULES );
|
|
HDL_DEPENDENCY( DEVBLK );
|
|
HDL_DEPENDENCY( SYSBLK );
|
|
HDL_DEPENDENCY( REGS );
|
|
}
|
|
END_DEPENDENCY_SECTION
|
|
|
|
|
|
HDL_RESOLVER_SECTION;
|
|
{
|
|
#if defined( WIN32 ) && !defined( _MSVC_ ) && !defined( HDL_USE_LIBTOOL )
|
|
#undef sysblk
|
|
HDL_RESOLVE_SYMPTR( psysblk, sysblk );
|
|
HDL_RESOLVE( etod_clock );
|
|
HDL_RESOLVE( device_attention );
|
|
#else
|
|
UNREFERENCED( getsym ); // (HDL_RESOLVER_SECTION parameter)
|
|
#endif
|
|
}
|
|
END_RESOLVER_SECTION
|
|
|
|
|
|
HDL_REGISTER_SECTION;
|
|
{
|
|
// Hercules's Our
|
|
// registered overriding
|
|
// entry-point entry-point
|
|
// name value
|
|
|
|
#if defined( OPTION_W32_CTCI )
|
|
HDL_REGISTER ( debug_tt32_stats, display_tt32_stats );
|
|
HDL_REGISTER ( debug_tt32_tracing, enable_tt32_debug_tracing );
|
|
#else
|
|
UNREFERENCED( regsym ); // (HDL_REGISTER_SECTION parameter)
|
|
#endif
|
|
}
|
|
END_REGISTER_SECTION
|
|
|
|
|
|
HDL_DEVICE_SECTION;
|
|
{
|
|
HDL_DEVICE( PTP, ptp_device_hndinfo );
|
|
}
|
|
END_DEVICE_SECTION
|