Skip to main content

     
  TPF : Library : Newsletters

Why MATIP User Exits

Al Brajnikoff, IBM TPF Development

The two Mapping of Airline Traffic over Internet Protocol (MATIP) releases (APAR PJ26161 on PUT 9 and APAR PJ26963 on PUT 11) provide a number of user exits that you need to customize for MATIP to work correctly. The user exits divide into two types: those for TPF as a server and those for TPF as a client. Naturally, some exits are used for both directions of message flow.

Server User Exits

MATIP message traffic is handled identically as much as possible, irrespective of message type. When a TPF server receives a Type-A Conversational session open request from a MATIP client, the session manager code checks the number of agent set control units (or ASCUs) that are being defined by the incoming client request. If the number of ASCUs passed by the client side is zero, the session manager calls the ASCU List user exit, UMATAS, to see whether there are ASCUs predefined for the sort of message that is requesting the session. Type-A host-to-host and Type-B sessions do not pass ASCU lists and, therefore, skip this user exit.

Our list of ASCUs (two-byte ASCUlist) in the example is very simple, but yours might be more complex depending on your ACSA/A2CS configuration. For instance, we define some 2-byte ASCUs, we say how many there are in the list (11), we copy the list into a pointer to a pointer to char supplied by the caller, and return the number of ASCUs in the list.

unsigned short two_byte_ASCUlist[20] =  {0x0100, 0x0902, 0x1501,
                                         0x0903, 0x1305, 0xD404,
                                         0xD004, 0xD202, 0xFE16,                                          
                                         0x0901, 0xD001, 0};
     :                                                      
 if (ASCU_size == 2)                                    
 { 
       numASCUs = 11; 
       *list = (unsigned char *)malloc (numASCUs * 2);
       memcpy (*list, two_byte_ASCUlist, numASCUs * 2);

     :
 return(numASCUs);

The ASCUlist that is returned is added to the session definition and will be used for more transmissions for this session. An ASCUlist can also be read into main storage from offline storage during MATIP start. This ASCUlist is defined using the ZMATP DEFINE and ZMATP ADD functional messages (commands).

If the number of ASCUs is not zero or if the session open request is for Type-A host-to-host or Type-B sessions, the Security user exit, UMATSE, is called.

The IP address and session-type-specific information (ASCUlist, H1H2, or flow ID) for the remote client is passed to the Security exit. The Security exit contains code that ensures TPF servers only start sessions with recognized remote hosts.

Type-A Conversational sessions present a list of ASCUs to the user exit while Type-A host-to-host and Type-B sessions present the IP address of the remote host and either H1H2 or resource identifier to the user exit. The Security user exit goes through the information and selects only those ASCUs that are defined. The ASCUs not found in the user exit list are removed from the list of acceptable ASCUs and are added to a reject list. The rejected ASCUs are not validated for the session. Both lists are returned to the caller when the user exit is completed, along with the number of ASCUs in each list. If there are ASCUs to be rejected, they are included in the Session Open Response with an indication that they were not defined in the session. If all ASCUs are acceptable, the list of acceptable ASCUs is returned to the remote host.

Type-A host-to-host and Type-B sessions are easier to verify because they have only the IP address and either the H1H2 or resource identifier to verify against. If the incoming IP address for the remote client is not in a list with the correct characteristic, the session request is rejected. A return code indicates whether the remote host is acceptable or not.

When a MATIP inbound session is open and data is flowing, other user exits come into play. One is the flow identifier user exit, UMATFI. This exit is for Type-A host-to-host messages and it allows messages to be distinguished from each other so that journaling (logging) can be performed. The types of hosts distinguished during UMATFI include IATA host-to-host traffic subtype and SITA host-to-host traffic subtype.

When a destination (an LNIATA) cannot be determined from the MATIP session block or the data packet for a message, the Assign LNIATA user exit, UMATAL, is called to determine one. The UMATAL user exit is especially important for IP Bridge devices. This user exit is also used for outbound (client) Type-A Conversational sessions with 4-byte ASCUs. In the following example for Type-A Conversational sessions, the H1H2, A1A2, and terminal address (TA) characteristics are searched for in the table. If they are found, the LNIATA associated with them is returned for use. If not found, the Router user exit is called if the message packet is inbound. If an outbound Type-A Conversational session cannot determine an LNIATA, the message packet is dropped.

#define CONVERSATIONAL_LNIATAS    {     \ 
{0x1111, 0x2205, 0x01, 0x00D40404},     \
{0x1111, 0x2205, 0x02, 0x00D40405},     \ 
{0x1111, 0x2205, 0x03, 0x00D40406},     \ 
{0x1111, 0x2205, 0x04, 0x00D00404},     \
   :
struct conv_lniata         
{                          
    unsigned short H1H2;   
    unsigned short A1A2;   
    unsigned char  TA;     
    unsigned int   lniata; 
};                         
   :
 struct conv_lniata  table[] = CONVERSATIONAL_LNIATAS; 
   :
for (i = 0;  i < MAXCONV_LNIATAS; i++)                          
{                                                              
     if (table[i].H1H2 == msg_ID->H1H2)                       
     {                                                       
          if (table[i].A1A2 == msg_ID->A1A2)                
          {
               if (memcmp (&table[i].TA, &msg_ID->TA, 1)  == 0)
               {
                    *lniata = table[i].lniata; 
                    i = MAXCONV_LNIATAS; 
                    found = 1; 
               }  /* end if TA's are equal */ 
          }  /* end if A1A2's are equal */ 

     }  /* end if H1H2's are equal */

The Router user exit, UMATRO, is called when routing cannot be determined by the UMATAL user exit. For Type-A host-to-host and Type-B messages, the Router user exit identifies an associated application on the basis of H1H2 and flow ID or high-level designator (HLD). By analyzing this information in the Router user exit, routing can be done without requiring applications to have WGTA table entries. The easiest way to do this is to call the appropriate application directly in the UMATRO user exit.

Before the messages are routed to their appropriate applications, they are shuttled through the Translation user exit, UMATTR. This user exit translates message text from the encoding specified when the session was opened to the EBCDIC encoding. The possible encodings are padded Baudot, IPARS, and ASCII. Similarly, for outbound messages, the translation takes place from EBCDIC to what was specified during session open. UMATTR could be used to make translations to and from other code pages as well. For this, translation would use EBCDIC as either the source or the target depending on the direction of message flow.

Client User Exits

When TPF acts as a client, it starts outbound traffic to a remote host. Some of the same user exits we have already seen come into play as well as some new ones. When a message is routed from a TPF application for the first time to a MATIP device, a new session is started. To start this session, an association between an LNIATA and a host name is used to determine where to send the message. An LNIATA can be associated with a host name in the Check Host user exit, UMATCH.

#define LNIATA_TBL             {          \
{0x00123456, "HOST1.POK.IBM.COM"  },      \
{0x00555555, "HOST2.POK.IBM.COM"  },      \
{0, ""                } } ;
   :
STRUCT MATIP_IP_addr typea_table[] = LNIATA_TBL ;

:

host_rec = (struct host_record *) NULL ;

 /* search type a table */
 if (host_rec == (struct host_record *) NULL)
    {
     iii = 0 ;
     while (iii >= 0)
       {
          if (typea_table[iii].h_lniata == lniata)
             {
                host_rec =
                   lookup_host(typea_table[iii].hostname)  ;
                if (host_rec != NULL)
                   return (host_rec) ;
                }
          ++iii ;
          if (typea_table[iii].h_lniata == 0) iii = -1 ;
          } ;
      }
return (NULL) ;

In the previous example there are two hosts and two LNIATAs listed. The code goes through the list of LNIATAs looking for the one that was passed. If the passed LNIATA is found, the host associated with it is checked by looking it up in the online MATIP host name table. If the host has been defined to MATIP previously, a pointer to the host record in the table is returned to the caller. The host record contains, among other things, a 256-byte area for users. This user exit is one place where this user area could be manipulated.

When the Check Host user exit returns, the remote host is verified to be on the network by doing address resolution on the host name. Its current IP address is requested from the name server as well. The IP address and LNIATA are given to the Session Start user exit, UMATSS, to pick up the MATIP characteristics for the session being opened.

In the example that follows, the Type-A Conversational sessions are listed according to their LNIATAs. The LNIATA table is searched for an LNIATA specified by the caller. Once found, the IP address, session type, session ID (H1H2), encoding, subtype, and multiplexing characteristics are set for the session from the table data. Similar code can be written for Type-A host-to-host and Type-B sessions. For Type-A host-to-host and Type B, the IP address is used as the distinguishing characteristic.

struct MATIP_lniata              
 {                               
  unsigned int h_lniata;         
  unsigned int h_ipaddr;         
  unsigned int h_session_type;   
  unsigned int h_session_ID;     
  char         h_encoding;       
  char         h_subtype;        
  char         h_multiplex;      
 };                              
   :
#define CONV_LNIATA          {                               \ 
{0x00D40103, 0x0975935C, 0x42, 0x00001111, 0x02, 0x01, 0x01},\ 
{0x00D40104, 0x0975938B, 0x42, 0x00001111, 0x02, 0x01, 0x02},\ 
{0x00D40105, 0x09756BBD, 0x42, 0x00001111, 0x02, 0x01, 0x00},\
   :
struct MATIP_lniata  table[] = CONV_LNIATA;      
   :

for (i = 0;  i <  MAX_LNIATA; i++)                       
  {                                                       
      if (table[i]. h_lniata == *lniata)                  
      {                                                   
         Ip_addr = table[i].h_ipaddr;                     
        *session_type = table[i].h_session_type;          
        memcpy(session_ID, &(table[i].h_session_ID), 4);  
        *encoding = table[i].h_encoding;                  
        *subtype = table[i].h_subtype;                    
        *multiplex = table[i].h_multiplex;                
        i = MAX_LNIATA;                                   
        rc = 0;                                           
      }                                                   
  :

Outbound (client) Type-A Conversational sessions define their ASCUlists during the Assign LNIATA user exit just as inbound (server) ones do. So, the UMATAL user exit is called during Session Open for TPF clients as well as for TPF servers.

Why MATIP user exits? The MATIP user exits provide customers with strong control over the configuration and the security of their MATIP network.