/*
 * dsock.c -- pstat-based HP-UX socket and stream processing functions for lsof
 */


/*
 * Copyright 1999 Purdue Research Foundation, West Lafayette, Indiana
 * 47907.  All rights reserved.
 *
 * Written by Victor A. Abell
 *
 * This software is not subject to any license of the American Telephone
 * and Telegraph Company or the Regents of the University of California.
 *
 * Permission is granted to anyone to use this software for any purpose on
 * any computer system, and to alter it and redistribute it freely, subject
 * to the following restrictions:
 *
 * 1. Neither the authors nor Purdue University are responsible for any
 *    consequences of the use of this software.
 *
 * 2. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Credit to the authors and Purdue
 *    University must appear in documentation and sources.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 4. This notice may not be removed or altered.
 */

#ifndef lint
static char copyright[] =
"@(#) Copyright 1999 Purdue Research Foundation.\nAll rights reserved.\n";
#endif


#include "lsof.h"


/*
 * Local function prototypes
 */

#if	defined(PS_STR_XPORT_DATA)
_PROTOTYPE(static void make_sock,(struct pst_fileinfo2 *f,
				  struct pst_stream *sh,
				  struct pst_socket *s));
#endif	/* defined(PS_STR_XPORT_DATA) */

_PROTOTYPE(static void printpsproto,(uint32_t p));


/*
 * Local macros
 */

#if	defined(HASIPv6)

/*
 * IPv6_2_IPv4()  -- macro to define the address of an IPv4 address contained
 *		     in an IPv6 address
 */

#define IPv6_2_IPv4(v6)	(((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12)
#endif	/* defined(HASIPv6) */


/*
 * build_IPstates() -- build the TCP and UDP state tables
 */

void
build_IPstates()
{
	if (!TcpSt) {
	    (void) enter_IPstate("TCP", "CLOSED", PS_TCPS_CLOSED);
	    (void) enter_IPstate("TCP", "IDLE", PS_TCPS_IDLE);
	    (void) enter_IPstate("TCP", "BOUND", PS_TCPS_BOUND);
	    (void) enter_IPstate("TCP", "LISTEN", PS_TCPS_LISTEN);
	    (void) enter_IPstate("TCP", "SYN_SENT", PS_TCPS_SYN_SENT);
	    (void) enter_IPstate("TCP", "SYN_RCVD", PS_TCPS_SYN_RCVD);
	    (void) enter_IPstate("TCP", "ESTABLISHED", PS_TCPS_ESTABLISHED);
	    (void) enter_IPstate("TCP", "CLOSE_WAIT", PS_TCPS_CLOSE_WAIT);
	    (void) enter_IPstate("TCP", "FIN_WAIT_1", PS_TCPS_FIN_WAIT_1);
	    (void) enter_IPstate("TCP", "CLOSING", PS_TCPS_CLOSING);
	    (void) enter_IPstate("TCP", "LAST_ACK", PS_TCPS_LAST_ACK);
	    (void) enter_IPstate("TCP", "FIN_WAIT_2", PS_TCPS_FIN_WAIT_2);
	    (void) enter_IPstate("TCP", "TIME_WAIT", PS_TCPS_TIME_WAIT);
	    (void) enter_IPstate("TCP", (char *)NULL, 0);
	}
	if (!UdpSt) {
	    (void) enter_IPstate("UDP", "Uninitialized", PS_TS_UNINIT);
	    (void) enter_IPstate("UDP", "Unbound", PS_TS_UNBND);
	    (void) enter_IPstate("UDP", "Wait_BIND_REQ_Ack", PS_TS_WACK_BREQ);
	    (void) enter_IPstate("UDP", "Wait_UNBIND_REQ_Ack", PS_TS_WACK_UREQ);
	    (void) enter_IPstate("UDP", "Idle", PS_TS_IDLE);
	    (void) enter_IPstate("UDP", "Wait_OPT_REQ_Ack", PS_TS_WACK_OPTREQ);
	    (void) enter_IPstate("UDP", "Wait_CONN_REQ_Ack", PS_TS_WACK_CREQ);
	    (void) enter_IPstate("UDP", "Wait_CONN_REQ_Confirm",
		PS_TS_WCON_CREQ);
	    (void) enter_IPstate("UDP", "Wait_CONN_IND_Response",
		PS_TS_WRES_CIND);
	    (void) enter_IPstate("UDP", "Wait_CONN_RES_Ack", PS_TS_WACK_CRES);
	    (void) enter_IPstate("UDP", "Wait_Data_Xfr", PS_TS_DATA_XFER);
	    (void) enter_IPstate("UDP", "Wait_Read_Release", PS_TS_WIND_ORDREL);
	    (void) enter_IPstate("UDP", "Wait_Write_Release",
		PS_TS_WREQ_ORDREL);
	    (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack",
		PS_TS_WACK_DREQ6);
	    (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack",
		PS_TS_WACK_DREQ7);
	    (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack",
		PS_TS_WACK_DREQ9);
	    (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack",
		PS_TS_WACK_DREQ10);
	    (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack",
		PS_TS_WACK_DREQ11);
	    (void) enter_IPstate("UDP", "Internal", PS_TS_WACK_ORDREL);
	    (void) enter_IPstate("UDP", (char *)NULL, 0);
	}
}


#if	defined(PS_STR_XPORT_DATA)
/*
 * make_sock() -- make a socket from the eXPORT data in a stream's head
 */

static void
make_sock(f, sh, s)
	struct pst_fileinfo2 *f;		/* pst_fileinfo2 */
	struct pst_stream *sh;			/* stream head */
	struct pst_socket *s;			/* constructed socket */
{
	size_t sz;
/*
 * Zero the destination pst_socket structure  and propagate its file and node
 * IDs from the stream head.  Also propagate the linger time. 
 */
	(void)memset((void *)s, 0, sizeof(struct pst_socket));
	s->pst_hi_fileid = sh->val.head.pst_hi_fileid;
	s->pst_lo_fileid = sh->val.head.pst_lo_fileid;
	s->pst_hi_nodeid = sh->val.head.pst_hi_nodeid;
	s->pst_lo_nodeid = sh->val.head.pst_lo_nodeid;
	s->pst_linger = sh->pst_str_xport_linger;
/*
 * Convert stream family to socket family and stream protocol to socket
 * protocol.
 *
 * This could be avoided if PSTAT were to use a common set of family and
 * protocol symbols.
 */
	switch (sh->pst_str_xport_family) {
	    case PS_STR_XPORT_AFINET:
		s->pst_family = PS_AF_INET;
		break;
	    case PS_STR_XPORT_AFINET6:
		s->pst_family = PS_AF_INET6;
		break;
	    default:
		s->pst_family = sh->pst_str_xport_family;
	}
	switch (sh->pst_str_xport_protocol) {
	    case PS_STR_XPORT_TCP_PROTO:
		s->pst_protocol = PS_PROTO_TCP;
		break;
	    case PS_STR_XPORT_UDP_PROTO:
		s->pst_protocol = PS_PROTO_UDP;
		break;
	    default:
		s->pst_protocol = sh->pst_str_xport_protocol;
	}
/*
 * Copy stream size information.
 */
	s->pst_qlimit = sh->pst_str_xport_qlimit;
	s->pst_qlen = sh->pst_str_xport_qlen;
	s->pst_idata = sh->pst_str_xport_idata;
	s->pst_ibufsz = sh->pst_str_xport_ibufsz;
	s->pst_rwnd = sh->pst_str_xport_rwnd;
	s->pst_swnd = sh->pst_str_xport_swnd;
	s->pst_odata = sh->pst_str_xport_odata;
	s->pst_obufsz = sh->pst_str_xport_obufsz;
/*
 * Propagate protocol state from stream symbol values to socket ones.
 *
 * This could be avoided if PSTAT were to use a common set of protocol
 * state symbols.
 */
	if (s->pst_protocol == PS_PROTO_TCP) {
	    switch (sh->pst_str_xport_pstate) {

#if	defined(PS_STR_XPORT_TCPS_CLOSED) && defined(PS_TCPS_CLOSED) \
	&& (PS_STR_XPORT_TCPS_CLOSED != PS_TCPS_CLOSED)
	    case PS_STR_XPORT_TCPS_CLOSED:
		s->pst_pstate = PS_TCPS_CLOSED;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_IDLE) && defined(PS_TCPS_IDLE) \
	&& (PS_STR_XPORT_TCPS_IDLE != PS_TCPS_IDLE)
	    case PS_STR_XPORT_TCPS_IDLE:
		s->pst_pstate = PS_TCPS_IDLE;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_BOUND) && defined(PS_TCPS_BOUND) \
	&& (PS_STR_XPORT_TCPS_BOUND != PS_TCPS_BOUND)
	    case PS_STR_XPORT_TCPS_BOUND:
		s->pst_pstate = PS_TCPS_BOUND;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_LISTEN) && defined(PS_TCPS_LISTEN) \
	&& (PS_STR_XPORT_TCPS_LISTEN != PS_TCPS_LISTEN)
	    case PS_STR_XPORT_TCPS_LISTEN:
		s->pst_pstate = PS_TCPS_LISTEN;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_SYN_SENT) && defined(PS_TCPS_SYN_SENT) \
	&& (PS_STR_XPORT_TCPS_SYN_SENT != PS_TCPS_SYN_SENT)
	    case PS_STR_XPORT_TCPS_SYN_SENT:
		s->pst_pstate = PS_TCPS_SYN_SENT;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_SYN_RCVD) && defined(PS_TCPS_SYN_RCVD) \
	&& (PS_STR_XPORT_TCPS_SYN_RCVD != PS_TCPS_SYN_RCVD)
	    case PS_STR_XPORT_TCPS_SYN_RCVD:
		s->pst_pstate = PS_TCPS_SYN_RCVD;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_ESTABLISHED) && defined(PS_TCPS_ESTABLISHED) \
	&& (PS_STR_XPORT_TCPS_ESTABLISHED != PS_TCPS_ESTABLISHED)
	    case PS_STR_XPORT_TCPS_ESTABLISHED:
		s->pst_pstate = PS_TCPS_ESTABLISHED;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_CLOSE_WAIT) && defined(PS_TCPS_CLOSE_WAIT) \
	&& (PS_STR_XPORT_TCPS_CLOSE_WAIT != PS_TCPS_CLOSE_WAIT)
	    case PS_STR_XPORT_TCPS_CLOSE_WAIT:
		s->pst_pstate = PS_TCPS_CLOSE_WAIT;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_FIN_WAIT_1) && defined(PS_TCPS_FIN_WAIT_1) \
	&& (PS_STR_XPORT_TCPS_FIN_WAIT_1 != PS_TCPS_FIN_WAIT_1)
	    case PS_STR_XPORT_TCPS_FIN_WAIT_1:
		s->pst_pstate = PS_TCPS_FIN_WAIT_1;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_CLOSING) && defined(PS_TCPS_CLOSING) \
	&& (PS_STR_XPORT_TCPS_CLOSING != PS_TCPS_CLOSING)
	    case PS_STR_XPORT_TCPS_CLOSING:
		s->pst_pstate = PS_TCPS_CLOSING;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_LAST_ACK) && defined(PS_TCPS_LAST_ACK) \
	&& (PS_STR_XPORT_TCPS_LAST_ACK != PS_TCPS_LAST_ACK)
	    case PS_STR_XPORT_TCPS_LAST_ACK:
		s->pst_pstate = PS_TCPS_LAST_ACK;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_FIN_WAIT_2) && defined(PS_TCPS_FIN_WAIT_2) \
	&& (PS_STR_XPORT_TCPS_FIN_WAIT_2 != PS_TCPS_FIN_WAIT_2)
	    case PS_STR_XPORT_TCPS_FIN_WAIT_2:
		s->pst_pstate = PS_TCPS_FIN_WAIT_2;
		break;
#endif

#if	defined(PS_STR_XPORT_TCPS_TIME_WAIT) && defined(PS_TCPS_TIME_WAIT) \
	&& (PS_STR_XPORT_TCPS_TIME_WAIT != PS_TCPS_TIME_WAIT)
	    case PS_STR_XPORT_TCPS_TIME_WAIT:
		s->pst_pstate = PS_TCPS_TIME_WAIT;
		break;
#endif

	    default:
		s->pst_pstate = sh->pst_str_xport_pstate;
	    }
	} else if (s->pst_protocol == PS_PROTO_UDP) {
	    switch (sh->pst_str_xport_pstate) {

#if	defined(PS_STR_XPORT_TS_UNINIT) && defined(PS_TS_UNINIT) \
	&& (PS_STR_XPORT_TS_UNINIT != PS_TS_UNINIT)
	    case PS_STR_XPORT_TS_UNINIT:
		s->pst_pstate = PS_TS_UNINIT;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_UNBND) && defined(PS_TS_UNBND) \
	&& (PS_STR_XPORT_TS_UNBND != PS_TS_UNBND)
	    case PS_STR_XPORT_TS_UNBND:
		s->pst_pstate = PS_TS_UNBND;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_BREQ) && defined(PS_TS_WACK_BREQ) \
	&& (PS_STR_XPORT_TS_WACK_BREQ != PS_TS_WACK_BREQ)
	    case PS_STR_XPORT_TS_WACK_BREQ:
		s->pst_pstate = PS_TS_WACK_BREQ;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_UREQ) && defined(PS_TS_WACK_UREQ) \
	&& (PS_STR_XPORT_TS_WACK_UREQ != PS_TS_WACK_UREQ)
	    case PS_STR_XPORT_TS_WACK_UREQ:
		s->pst_pstate = PS_TS_WACK_UREQ;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_IDLE) && defined(PS_TS_IDLE) \
	&& (PS_STR_XPORT_TS_IDLE != PS_TS_IDLE)
	    case PS_STR_XPORT_TS_IDLE:
		s->pst_pstate = PS_TS_IDLE;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_OPTREQ) && defined(PS_TS_WACK_OPTREQ) \
	&& (PS_STR_XPORT_TS_WACK_OPTREQ != PS_TS_WACK_OPTREQ)
	    case PS_STR_XPORT_TS_WACK_OPTREQ:
		s->pst_pstate = PS_TS_WACK_OPTREQ;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_CREQ) && defined(PS_TS_WACK_CREQ) \
	&& (PS_STR_XPORT_TS_WACK_CREQ != PS_TS_WACK_CREQ)
	    case PS_STR_XPORT_TS_WACK_CREQ:
		s->pst_pstate = PS_TS_WACK_CREQ;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WCON_CREQ) && defined(PS_TS_WCON_CREQ) \
	&& (PS_STR_XPORT_TS_WCON_CREQ != PS_TS_WCON_CREQ)
	    case PS_STR_XPORT_TS_WCON_CREQ:
		s->pst_pstate = PS_TS_WCON_CREQ;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WRES_CIND) && defined(PS_TS_WRES_CIND) \
	&& (PS_STR_XPORT_TS_WRES_CIND != PS_TS_WRES_CIND)
	    case PS_STR_XPORT_TS_WRES_CIND:
		s->pst_pstate = PS_TS_WRES_CIND;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_CRES) && defined(PS_TS_WACK_CRES) \
	&& (PS_STR_XPORT_TS_WACK_CRES != PS_TS_WACK_CRES)
	    case PS_STR_XPORT_TS_WACK_CRES:
		s->pst_pstate = PS_TS_WACK_CRES;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_DATA_XFER) && defined(PS_TS_DATA_XFER) \
	&& (PS_STR_XPORT_TS_DATA_XFER != PS_TS_DATA_XFER)
	    case PS_STR_XPORT_TS_DATA_XFER:
		s->pst_pstate = PS_TS_DATA_XFER;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WIND_ORDREL) && defined(PS_TS_WIND_ORDREL) \
	&& (PS_STR_XPORT_TS_WIND_ORDREL != PS_TS_WIND_ORDREL)
	    case PS_STR_XPORT_TS_WIND_ORDREL:
		s->pst_pstate = PS_TS_WIND_ORDREL;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WREQ_ORDREL) && defined(PS_TS_WREQ_ORDREL) \
	&& (PS_STR_XPORT_TS_WREQ_ORDREL != PS_TS_WREQ_ORDREL)
	    case PS_STR_XPORT_TS_WREQ_ORDREL:
		s->pst_pstate = PS_TS_WREQ_ORDREL;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_DREQ6) && defined(PS_TS_WACK_DREQ6) \
	&& (PS_STR_XPORT_TS_WACK_DREQ6 != PS_TS_WACK_DREQ6)
	    case PS_STR_XPORT_TS_WACK_DREQ6:
		s->pst_pstate = PS_TS_WACK_DREQ6;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_DREQ7) && defined(PS_TS_WACK_DREQ7) \
	&& (PS_STR_XPORT_TS_WACK_DREQ7 != PS_TS_WACK_DREQ7)
	    case PS_STR_XPORT_TS_WACK_DREQ7:
		s->pst_pstate = PS_TS_WACK_DREQ7;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_DREQ9) && defined(PS_TS_WACK_DREQ9) \
	&& (PS_STR_XPORT_TS_WACK_DREQ9 != PS_TS_WACK_DREQ9)
	    case PS_STR_XPORT_TS_WACK_DREQ9:
		s->pst_pstate = PS_TS_WACK_DREQ9;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_DREQ10) && defined(PS_TS_WACK_DREQ10) \
	&& (PS_STR_XPORT_TS_WACK_DREQ10 != PS_TS_WACK_DREQ10)
	    case PS_STR_XPORT_TS_WACK_DREQ10:
		s->pst_pstate = PS_TS_WACK_DREQ10;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_DREQ11) && defined(PS_TS_WACK_DREQ11) \
	&& (PS_STR_XPORT_TS_WACK_DREQ11 != PS_TS_WACK_DREQ11)
	    case PS_STR_XPORT_TS_WACK_DREQ11:
		s->pst_pstate = PS_TS_WACK_DREQ11;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_WACK_ORDREL) && defined(PS_TS_WACK_ORDREL) \
	&& (PS_STR_XPORT_TS_WACK_ORDREL != PS_TS_WACK_ORDREL)
	    case PS_STR_XPORT_TS_WACK_ORDREL:
		s->pst_pstate = PS_TS_WACK_ORDREL;
		break;
#endif

#if	defined(PS_STR_XPORT_TS_NOSTATES) && defined(PS_TS_NOSTATES) \
	&& (PS_STR_XPORT_TS_NOSTATES != PS_TS_NOSTATES)
	    case PS_STR_XPORT_TS_NOSTATES:
		s->pst_pstate = PS_TS_NOSTATES;
		break;
#endif

	    default:
		s->pst_pstate = sh->pst_str_xport_pstate;
	    }
	} else
	    s->pst_pstate = sh->pst_str_xport_pstate;
/*
 * Now propagate the bound and remote address information from pst_stream
 * to the pst_socket structure.  Validate the copy lengths.
 */
	sz = (size_t)sh->pst_str_xport_boundaddr_len;
	if (sz > sizeof(s->pst_boundaddr))
	    sz = sizeof(s->pst_boundaddr);
	if ((s->pst_boundaddr_len = sz)) {
	    (void) memcpy((void *)s->pst_boundaddr,
			  (const void *)sh->pst_str_xport_boundaddr, sz);
	}
	sz = (size_t)sh->pst_str_xport_remaddr_len;
	if (sz > sizeof(s->pst_remaddr))
	    sz = sizeof(s->pst_remaddr);
	if ((s->pst_remaddr_len = sz)) {
	    (void) memcpy((void *)s->pst_remaddr,
			  (const void *)sh->pst_str_xport_remaddr, sz);
	}
}
#endif	/* defined(PS_STR_XPORT_DATA) */


/*
 * printpsproto() -- print PSTAT protocol name
 */

static void
printpsproto(p)
	uint32_t p;			/* protocol number */
{
	int i;
	static int m = -1;
	char *s;

	switch (p) {
	case PS_PROTO_IP:
	    s = "IP";
	    break;
	case PS_PROTO_ICMP:
	    s = "ICMP";
	    break;
	case PS_PROTO_IGMP:
	    s = "IGMP";
	    break;
	case PS_PROTO_GGP:
	    s = "GGP";
	    break;
	case PS_PROTO_IPIP:
	    s = "IPIP";
	    break;
	case PS_PROTO_TCP:
	    s = "TCP";
	    break;
	case PS_PROTO_EGP:
	    s = "EGP";
	    break;
	case PS_PROTO_IGP:
	    s = "IGP";
	    break;
	case PS_PROTO_PUP:
	    s = "PUP";
	    break;
	case PS_PROTO_UDP:
	    s = "UDP";
	    break;
	case PS_PROTO_IDP:
	    s = "IDP";
	    break;
	case PS_PROTO_XTP:
	    s = "XTP";
	    break;
	case PS_PROTO_ESP:
	    s = "ESP";
	    break;
	case PS_PROTO_AH:
	    s = "AH";
	    break;
	case PS_PROTO_OSPF:
	    s = "OSPF";
	    break;
	case PS_PROTO_IPENCAP:
	    s = "IPENCAP";
	    break;
	case PS_PROTO_ENCAP:
	    s = "ENCAP";
	    break;
	case PS_PROTO_PXP:
	    s = "PXP";
	    break;
	case PS_PROTO_RAW:
	    s = "RAW";
	    break;
	default:
	    s = (char *)NULL;
	}
	if (s)
	    (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, s);
	else {
	    if (m < 0) {
		for (i = 0, m = 1; i < IPROTOL-2; i++)
		    m *= 10;
	    }
	    if (m > p)
		(void) snpf(Lf->iproto, sizeof(Lf->iproto), "%d?", p);
	    else
		(void) snpf(Lf->iproto, sizeof(Lf->iproto), "*%d?",
		    p % (m/10));
	}
}


/*
 * print_tcptpi() -- print TCP/TPI info
 */

void
print_tcptpi(nl)
	int nl;				/* 1 == '\n' required */
{
	char *cp = (char *)NULL;
	char  sbuf[128];
	int i;
	int ps = 0;
	unsigned int u;

	if (Ftcptpi & TCPTPI_STATE) {
	    switch (Lf->lts.type) {
	    case 0:				/* TCP */
		if (!TcpSt)
		    (void) build_IPstates();
		if ((i = Lf->lts.state.i + TcpStOff) < 0 || i >= TcpNstates) {
		    (void) snpf(sbuf, sizeof(sbuf), "UknownState_%d",
			Lf->lts.state.i);
		    cp = sbuf;
		} else
		    cp = TcpSt[i];
		break;
	    case 1:				/* UDP */
		if (!UdpSt)
		    (void) build_IPstates();
		if ((u = Lf->lts.state.ui + UdpStOff) > UdpNstates) {
		    (void) snpf(sbuf, sizeof(sbuf), "UNKNOWN_TPI_STATE_%u",
			Lf->lts.state.ui);
		    cp = sbuf;
		} else
		    cp = UdpSt[u];
	    }
	    if (cp) {
		if (Ffield)
		    (void) printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);
		else {
		    putchar('(');
		    (void) fputs(cp, stdout);
		}
	    ps++;
	    }
	}

#if	defined(HASTCPTPIQ)
	if (Ftcptpi & TCPTPI_QUEUES) {
	    if (Lf->lts.rqs) {
		if (Ffield)
			putchar(LSOF_FID_TCPTPI);
		else {
		    if (ps)
			putchar(' ');
		    else
			putchar('(');
		}
		(void) printf("QR=%lu", Lf->lts.rq);
		if (Ffield)
		    putchar(Terminator);
		ps++;
	    }
	    if (Lf->lts.sqs) {
		if (Ffield)
			putchar(LSOF_FID_TCPTPI);
		else {
		    if (ps)
			putchar(' ');
		    else
			putchar('(');
		}
		(void) printf("QS=%lu", Lf->lts.sq);
		if (Ffield)
		    putchar(Terminator);
		ps++;
	    }
	}
#endif	/* defined(HASTCPTPIQ) */

#if	defined(HASSOOPT)
	if (Ftcptpi & TCPTPI_FLAGS) {
	    int opt;

	    if ((opt = Lf->lts.opt) || Lf->lts.qlens || Lf->lts.qlims) {
		char sep = ' ';

		if (Ffield)
		    sep = LSOF_FID_TCPTPI;
		else if (!ps)
		    sep = '(';
		(void) printf("%cSO", sep);
		ps++;
		sep = '=';

# if	defined(PS_SO_ACCEPTCONN)
		if (opt & PS_SO_ACCEPTCONN) {
		    (void) printf("%cACCEPTCONN", sep);
		    opt &= ~PS_SO_ACCEPTCONN;
		    sep = ',';
		}
# endif	/* defined(PS_SO_ACCEPTCONN) */

# if	defined(PS_SO_BROADCAST)
		if (opt & PS_SO_BROADCAST) {
		    (void) printf("%cBROADCAST", sep);
		    opt &= ~PS_SO_BROADCAST;
		    sep = ',';
		}
# endif	/* defined(PS_SO_BROADCAST) */

# if	defined(PS_SO_DEBUG)
		if (opt & PS_SO_DEBUG) {
		    (void) printf("%cDEBUG", sep);
		    opt &= ~PS_SO_DEBUG;
		    sep = ',';
		}
# endif	/* defined(PS_SO_DEBUG) */

# if	defined(PS_SO_DONTROUTE)
		if (opt & PS_SO_DONTROUTE) {
		    (void) printf("%cDONTROUTE", sep);
		    opt &= ~PS_SO_DONTROUTE;
		    sep = ',';
		}
# endif	/* defined(PS_SO_DONTROUTE) */

# if	defined(PS_SO_GETIFADDR)
		if (opt & PS_SO_GETIFADDR) {
		    (void) printf("%cGETIFADDR", sep);
		    opt &= ~PS_SO_GETIFADDR;
		    sep = ',';
		}
# endif	/* defined(PS_SO_GETIFADDR) */

# if	defined(PS_SO_INPCB_COPY)
		if (opt & PS_SO_INPCB_COPY) {
		    (void) printf("%cINPCB_COPY", sep);
		    opt &= ~PS_SO_INPCB_COPY;
		    sep = ',';
		}
# endif	/* defined(PS_SO_INPCB_COPY) */

# if	defined(PS_SO_KEEPALIVE)
		if (opt & PS_SO_KEEPALIVE) {
		    (void) printf("%cKEEPALIVE", sep);
		    if (Lf->lts.kai)
			(void) printf("=%d", Lf->lts.kai);
		    opt &= ~PS_SO_KEEPALIVE;
		    sep = ',';
		}
# endif	/* defined(PS_SO_KEEPALIVE) */

# if	defined(PS_SO_LINGER)
		if (opt & PS_SO_LINGER) {
		    (void) printf("%cLINGER", sep);
		    if (Lf->lts.ltm)
			(void) printf("=%d", Lf->lts.ltm);
		    opt &= ~PS_SO_LINGER;
		    sep = ',';
		}
# endif	/* defined(PS_SO_LINGER) */

# if	defined(PS_SO_OOBINLINE)
		if (opt & PS_SO_OOBINLINE) {
		    (void) printf("%cOOBINLINE", sep);
		    opt &= ~PS_SO_OOBINLINE;
		    sep = ',';
		}
# endif	/* defined(PS_SO_OOBINLINE) */

# if	defined(PS_SO_PMTU)
		if (opt & PS_SO_PMTU) {
		    (void) printf("%cPMTU", sep);
		    opt &= ~PS_SO_PMTU;
		    sep = ',';
		}
# endif	/* defined(PS_SO_PMTU) */

		if (Lf->lts.qlens) {
		    (void) printf("%cQLEN=%u", sep, Lf->lts.qlen);
		    sep = ',';
		}
		if (Lf->lts.qlims) {
		    (void) printf("%cQLIM=%u", sep, Lf->lts.qlim);
		    sep = ',';
		}

# if	defined(PS_SO_REUSEADDR)
		if (opt & PS_SO_REUSEADDR) {
		    (void) printf("%cREUSEADDR", sep);
		    opt &= ~PS_SO_REUSEADDR;
		    sep = ',';
		}
# endif	/* defined(PS_SO_REUSEADDR) */

# if	defined(PS_SO_REUSEPORT)
		if (opt & PS_SO_REUSEPORT) {
		    (void) printf("%cREUSEPORT", sep);
		    opt &= ~PS_SO_REUSEPORT;
		    sep = ',';
		}
# endif	/* defined(PS_SO_REUSEPORT) */

# if	defined(PS_SO_USELOOPBACK)
		if (opt & PS_SO_USELOOPBACK) {
		    (void) printf("%cUSELOOPBACK", sep);
		    opt &= ~PS_SO_USELOOPBACK;
		    sep = ',';
		}
# endif	/* defined(PS_SO_USELOOPBACK) */

		if (opt)
		    (void) printf("%cUNKNOWN=%#x", sep, opt);
		if (Ffield)
		    putchar(Terminator);
	    }
	}
#endif	/* defined(HASSOOPT) */

#if	defined(HASSOSTATE)
	if (Ftcptpi & TCPTPI_FLAGS) {
	    int ss;

	    if ((ss = Lf->lts.ss)) {
		char sep = ' ';

		if (Ffield)
		    sep = LSOF_FID_TCPTPI;
		else if (!ps)
		    sep = '(';
		(void) printf("%cSS", sep);
		ps++;
		sep = '=';

# if	defined(PS_SS_ASYNC)
		if (ss & PS_SS_ASYNC) {
		    (void) printf("%cASYNC", sep);
		    ss &= ~PS_SS_ASYNC;
		    sep = ',';
		}
# endif	/* defined(PS_SS_ASYNC) */

# if	defined(PS_SS_BOUND)
		if (ss & PS_SS_BOUND) {
		    (void) printf("%cBOUND", sep);
		    ss &= ~PS_SS_BOUND;
		    sep = ',';
		}
# endif	/* defined(PS_SS_BOUND) */

# if	defined(PS_SS_CANTRCVMORE)
		if (ss & PS_SS_CANTRCVMORE) {
		    (void) printf("%cCANTRCVMORE", sep);
		    ss &= ~PS_SS_CANTRCVMORE;
		    sep = ',';
		}
# endif	/* defined(PS_SS_CANTRCVMORE) */

# if	defined(PS_SS_CANTSENDMORE)
		if (ss & PS_SS_CANTSENDMORE) {
		    (void) printf("%cCANTSENDMORE", sep);
		    ss &= ~PS_SS_CANTSENDMORE;
		    sep = ',';
		}
# endif	/* defined(PS_SS_CANTSENDMORE) */

# if	defined(PS_SS_ISCONNECTED)
		if (ss & PS_SS_ISCONNECTED) {
		    (void) printf("%cISCONNECTED", sep);
		    ss &= ~PS_SS_ISCONNECTED;
		    sep = ',';
		}
# endif	/* defined(PS_SS_ISCONNECTED) */

# if	defined(PS_SS_ISCONNECTING)
		if (ss & PS_SS_ISCONNECTING) {
		    (void) printf("%cISCONNECTING", sep);
		    ss &= ~PS_SS_ISCONNECTING;
		    sep = ',';
		}
# endif	/* defined(PS_SS_ISCONNECTING) */

# if	defined(PS_SS_ISDISCONNECTI)
		if (ss & PS_SS_ISDISCONNECTI) {
		    (void) printf("%cISDISCONNECTI", sep);
		    ss &= ~PS_SS_ISDISCONNECTI;
		    sep = ',';
		}
# endif	/* defined(PS_SS_ISDISCONNECTI) */

# if	defined(PS_SS_INTERRUPTED)
		if (ss & PS_SS_INTERRUPTED) {
		    (void) printf("%cINTERRUPTED", sep);
		    ss &= ~PS_SS_INTERRUPTED;
		    sep = ',';
		}
# endif	/* defined(PS_SS_INTERRUPTED) */

# if	defined(PS_SS_NBIO)
		if (ss & PS_SS_NBIO) {
		    (void) printf("%cNBIO", sep);
		    ss &= ~PS_SS_NBIO;
		    sep = ',';
		}
# endif	/* defined(PS_SS_NBIO) */

# if	defined(PS_SS_NOFDREF)
		if (ss & PS_SS_NOFDREF) {
		    (void) printf("%cNOFDREF", sep);
		    ss &= ~PS_SS_NOFDREF;
		    sep = ',';
		}
# endif	/* defined(PS_SS_NOFDREF) */

# if	defined(PS_SS_NOUSER)
		if (ss & PS_SS_NOUSER) {
		    (void) printf("%cNOUSER", sep);
		    ss &= ~PS_SS_NOUSER;
		    sep = ',';
		}
# endif	/* defined(PS_SS_NOUSER) */

# if	defined(PS_SS_NOWAIT)
		if (ss & PS_SS_NOWAIT) {
		    (void) printf("%cNOWAIT", sep);
		    ss &= ~PS_SS_NOWAIT;
		    sep = ',';
		}
# endif	/* defined(PS_SS_NOWAIT) */

# if	defined(PS_SS_PRIV)
		if (ss & PS_SS_PRIV) {
		    (void) printf("%cPRIV", sep);
		    ss &= ~PS_SS_PRIV;
		    sep = ',';
		}
# endif	/* defined(PS_SS_PRIV) */

# if	defined(PS_SS_RCVATMARK)
		if (ss & PS_SS_RCVATMARK) {
		    (void) printf("%cRCVATMARK", sep);
		    ss &= ~PS_SS_RCVATMARK;
		    sep = ',';
		}
# endif	/* defined(PS_SS_RCVATMARK) */

# if	defined(PS_SS_XOPEN_EXT1)
		if (ss & PS_SS_XOPEN_EXT1) {
		    (void) printf("%cXOPEN_EXT1", sep);
		    ss &= ~PS_SS_XOPEN_EXT1;
		    sep = ',';
		}
# endif	/* defined(PS_SS_XOPEN_EXT1) */

		if (ss)
		    (void) printf("%cUNKNOWN=%#x", sep, ss);
		if (Ffield)
		    putchar(Terminator);
	    }
	}
#endif	/* defined(HASSOSTATE) */

#if	defined(HASTCPTPIW)
	if (Ftcptpi & TCPTPI_WINDOWS) {
	    if (Lf->lts.rws) {
		if (Ffield)
			putchar(LSOF_FID_TCPTPI);
		else {
		    if (ps)
			putchar(' ');
		    else
			putchar('(');
		}
		(void) printf("WR=%lu", Lf->lts.rw);
		if (Ffield)
		    putchar(Terminator);
		ps++;
	    }
	    if (Lf->lts.wws) {
		if (Ffield)
			putchar(LSOF_FID_TCPTPI);
		else {
		    if (ps)
			putchar(' ');
		    else
			putchar('(');
		}
		(void) printf("WW=%lu", Lf->lts.ww);
		if (Ffield)
		    putchar(Terminator);
		ps++;
	    }
	}
#endif	/* defined(HASTCPTPIW) */

	if (Ftcptpi && !Ffield && ps)
	    putchar(')');
	if (nl)
	    putchar('\n');
}


/*
 * process_socket() -- process socket
 */

void
process_socket(f, s)
	struct pst_fileinfo2 *f;		/* file information */
	struct pst_socket *s;			/* optional socket information
						 * NULL == none */
{
	int af, err, fp, lp, tx;
	char buf[1024], tbuf[32];
	unsigned char *fa = (unsigned char *)NULL;
	unsigned char *la = (unsigned char *)NULL;
	size_t len;
	KA_T na, nau;
	char *nma = (char *)NULL;
	struct pst_filedetails pd;
	struct sockaddr_in *sa;
	int sx;

#if	defined(HASIPv6)
	struct sockaddr_in6 *sa6;
#endif	/* defined(HASIPv6) */

	struct sockaddr_un *ua;
/*
 * Read socket info, as required, so that the protocol state names can be
 * tested as soon as possible.
 */
	if (!s) {
	    if (!(s = read_sock(f))) {
		(void) snpf(Namech, Namechl,
		    "can't read pst_socket%s%s", errno ? ": " : "",
		    errno ? strerror(errno) : "");
		(void) enter_nm(Namech);
		return;
	    }
	}
/*
 * Collect protocol details so the protocol state name might be tested,
 * as requested by options.
 */
	switch (s->pst_family) {
	case PS_AF_INET:
	    af = 4;
	    break;

#if	defined(HASIPv6)
	case PS_AF_INET6:
	    af = 6;
	    break;
#endif	/* defined(HASIPv6) */

	default:
	    af = -1;
	}
	switch (s->pst_protocol) {
	case PS_PROTO_TCP:
	    sx = (int)s->pst_pstate + TcpStOff;
	    tx = 0;
	    break;
	case PS_PROTO_UDP:
	    sx = (unsigned int)s->pst_pstate + UdpStOff;
	    tx = 1;
	    break;
	default:
	    sx = tx = -1;
	}
/*
 * Test the protocol state and name, setting the SELNET flag where possible.
 */
	switch (tx) {
	case 0:					/* TCP */
	    if (TcpStXn) {

	    /*
	     * Check for TCP state exclusion.
	     */
		if (sx >= 0 && sx < TcpNstates) {
		    if (TcpStX[sx]) {
			Lf->sf |= SELEXCLF;
			return;
		    }
		}
	    }
	    if (TcpStIn) {
		if (sx >= 0 && sx < TcpNstates) {
		    if (TcpStI[sx])
			TcpStI[sx] = 2;
		    else {
			Lf->sf |= SELEXCLF;
			return;
		    }
		}
	    }
	    break;
	case 1:					/* UDP */
	    if (UdpStXn) {

	    /*
	     * Check for UDP state exclusion.
	     */
		if (sx >= 0 && sx < UdpNstates) {
		    if (UdpStX[sx]) {
			Lf->sf |= SELEXCLF;
			return;
		    }
		}
	    }
	    if (UdpStIn) {
		if (sx >= 0 && sx < UdpNstates) {
		    if (UdpStI[sx])
			UdpStI[sx] = 2;
		    else {
			Lf->sf |= SELEXCLF;
			return;
		    }
		}
	    }
	    break;
	}
/*
 * Set default type.
 */
	(void) snpf(Lf->type, sizeof(Lf->type), "sock");
	Lf->inp_ty = 2;
/*
 * Generate and save node ID.
 */
	na = (KA_T)(((KA_T)(f->psf_hi_nodeid & 0xffffffff) << 32)
	   |        (KA_T)(f->psf_lo_nodeid & 0xffffffff));

#if	defined(HASFSTRUCT)
	if (na && (Fsv & FSV_NI)) {
	    if (na) {
		Lf->fna = na;
		Lf->fsv |= FSV_NI;
	    }
	}
#endif	/* defined(HASFSTRUCT) */

/*
 * Save size information, as requested.
 */
	if (Fsize) {
	    if (Lf->access == 'r')
		Lf->sz = (SZOFFTYPE)s->pst_idata;
	    else if (Lf->access == 'w')
		Lf->sz = (SZOFFTYPE)s->pst_odata;
	    else
		Lf->sz = (SZOFFTYPE)(s->pst_idata + s->pst_odata);
	    Lf->sz_def = 1;
	} else
	    Lf->off_def = 1;
	
#if     defined(HASTCPTPIQ)
/*
 * Enter queue sizes.
 */
	switch (s->pst_family) {
	case PS_AF_INET:
	case PS_AF_INET6:
	    Lf->lts.rq = (unsigned long)s->pst_idata;
	    Lf->lts.sq = (unsigned long)s->pst_odata;
	    Lf->lts.rqs = Lf->lts.sqs = (unsigned char)1;
	}
#endif  /* defined(HASTCPTPIQ) */

#if	defined(HASSOOPT)
/*
 * Enter socket options.
 */
	Lf->lts.opt = (unsigned int)s->pst_options;
	Lf->lts.ltm = (unsigned int)s->pst_linger;
	Lf->lts.qlen = (unsigned int)s->pst_qlen;
	Lf->lts.qlim = (unsigned int)s->pst_qlimit;
	Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1;
#endif	/* defined(HASSOOPT) */

#if	defined(HASSOSTATE)
/*
 * Enter socket state flags.
 */
	Lf->lts.ss = (unsigned int)s->pst_state;
#endif	/* defined(HASSOSTATE) */

#if	defined(HASTCPTPIW)
/*
 * Enter window sizes.
 */
	switch (s->pst_family) {
	case PS_AF_INET:
	case PS_AF_INET6:
	    Lf->lts.rw = (unsigned long)s->pst_rwnd;
	    Lf->lts.ww = (unsigned long)s->pst_swnd;
	    Lf->lts.rws = Lf->lts.wws = (unsigned char)1;
	}
#endif	/* defined(HASTCPTPIW) */

/*
 * Process socket by the associated domain family.
 */
	switch (s->pst_family) {
	case PS_AF_INET:
	    if (Fnet && (!FnetTy || (FnetTy != 6)))
		Lf->sf |= SELNET;
	    (void) snpf(Lf->type, sizeof(Lf->type),
	    
#if	defined(HASIPv6)
		"IPv4"
#else	/* !defined(HASIPv6) */
		"inet"
#endif	/* defined(HASIPv6) */

	    );
	    printpsproto(s->pst_protocol);
	    enter_dev_ch(print_kptr(na, (char *)NULL, 0));
	    switch (s->pst_protocol) {
	    case PS_PROTO_TCP:
		Lf->lts.type = 0;
		Lf->lts.state.i = (int)s->pst_pstate;
		break;
	    case PS_PROTO_UDP:
		Lf->lts.type = 1;
		Lf->lts.state.ui = (unsigned int)s->pst_pstate;
	    }
	/*
	 * Enter local and remote addresses, being careful to generate
	 * proper IPv4 address alignment by copying, since IPv4 addresses
	 * may not be properly aligned in pst_boundaddr[] and pst_remaddr[].
	 */
	    if ((size_t)s->pst_boundaddr_len == sizeof(struct sockaddr_in)) {
		sa = (struct sockaddr_in *)s->pst_boundaddr;
		la = (unsigned char *)&sa->sin_addr;
		lp = (int)htons(sa->sin_port);
	    }
	    if ((size_t)s->pst_remaddr_len == sizeof(struct sockaddr_in)) {
		sa = (struct sockaddr_in *)s->pst_remaddr;
		fp = (int)htons(sa->sin_port);
		if ((sa->sin_addr.s_addr != INADDR_ANY) || fp)
		    fa = (unsigned char *)&sa->sin_addr;
	    }
	    if (fa || la)
		(void) ent_inaddr(la, lp, fa, fp, AF_INET);
	    break;

#if	defined(HASIPv6)
	case PS_AF_INET6:
	    af = AF_INET6;
	    if (Fnet && (!FnetTy || (FnetTy != 4)))
		Lf->sf |= SELNET;
	    (void) snpf(Lf->type, sizeof(Lf->type), "IPv6");
	    printpsproto(s->pst_protocol);
	    enter_dev_ch(print_kptr(na, (char *)NULL, 0));
	    switch (s->pst_protocol) {
	    case PS_PROTO_TCP:
		Lf->lts.type = 0;
		Lf->lts.state.i = (int)s->pst_pstate;
		break;
	    case PS_PROTO_UDP:
		Lf->lts.type = 1;
		Lf->lts.state.ui = (unsigned int)s->pst_pstate;
	    }
	/*
	 * Enter local and remote addresses, being careful to generate
	 * proper IPv6 address alignment by copying, since IPv6 addresses
	 * may not be properly aligned in pst_boundaddr[] and pst_remaddr[].
	 */
	    if ((size_t)s->pst_boundaddr_len == sizeof(struct sockaddr_in6)) {
		sa6 = (struct sockaddr_in6 *)s->pst_boundaddr;
		la = (unsigned char *)&sa6->sin6_addr;
		lp = (int)htons(sa6->sin6_port);
	    }
	    if ((size_t)s->pst_remaddr_len == sizeof(struct sockaddr_in6)) {
		sa6 = (struct sockaddr_in6 *)s->pst_remaddr;
		if ((fp = (int)htons(sa6->sin6_port))
		||  !IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
		    fa = (unsigned char *)&sa6->sin6_addr;
	    }
	    if (la || fa) {
		if ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la))
		||  (fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa)))
		{
		    if (la)
			la = (unsigned char *)IPv6_2_IPv4(la);
		    if (fa)
			fa = (unsigned char *)IPv6_2_IPv4(fa);
		    af = AF_INET;
		}
	    }
	    if (fa || la)
		(void) ent_inaddr(la, lp, fa, fp, af);
	    break;
#endif	/* defined(HASIPv6) */

	case PS_AF_UNIX:
	    if (Funix)
		Lf->sf |= SELUNX;
	    (void) snpf(Lf->type, sizeof(Lf->type), "unix");
	    if (((len = (size_t)s->pst_boundaddr_len) > 0)
	    &&  (len <= sizeof(struct sockaddr_un)))
	    {
		ua = (struct sockaddr_un *)s->pst_boundaddr;
		if (ua->sun_path[0]) {

		/*
		 * The AF_UNIX socket has a bound address (file path).
		 *
		 * Save it.  If there is a low nodeid, put that in
		 * parentheses after the name.  If there is a low peer
		 * nodeid, put that in the parentheses, too.
		 */
		    s->pst_boundaddr[PS_ADDR_SZ - 1] = '\0';
		    if (s->pst_lo_nodeid) {
			(void) snpf(buf, sizeof(buf), "(%s%s%s)",
			    print_kptr((KA_T)s->pst_lo_nodeid,
				       tbuf, sizeof(tbuf)),
			    s->pst_peer_lo_nodeid ? "->" : "",
			    s->pst_peer_lo_nodeid ?
			    		print_kptr((KA_T)s->pst_peer_lo_nodeid,
						   (char *)NULL, 0)
					: ""
			);
			len = strlen(buf) + 1;
			if (!(nma = (char *)malloc((MALLOC_S)len))) {
			    (void) fprintf(stderr,
				"%s: no unix nma space(1): PID %ld, FD %s",
				Pn, (long)Lp->pid, Lf->fd);
			}
			(void) snpf(nma, len, "%s", buf);
			Lf->nma = nma;
		    }
		/*
		 * Read the pst_filedetails for the bound address and process
		 * them as for a regular file.  The already-entered file type,
		 * file name, size or offset, and name appendix will be
		 * preserved.
		 */
		    if ((nau = read_det(&f->psf_fid, f->psf_hi_fileid,
					f->psf_lo_fileid, f->psf_hi_nodeid,
					f->psf_lo_nodeid, &pd)))
		    {
			enter_nm(ua->sun_path);
			(void) process_finfo(&pd, &f->psf_fid, &f->psf_id, nau);
			return;
		    } else {

		    /*
		     * Couldn't read file details.  Erase any name appendix.
		     * Put the socket nodeid in the DEVICE column, put the
		     * bound address (path) in the NAME column, and build
		     * a new name appendix with the peer address.  Add an
		     * error message if pstat_getfiledetails() set errno to
		     * something other than ENOENT.
		     */
			if ((err = errno) == ENOENT)
			    err = 0;
			if (nma) {
			    (void) free((MALLOC_P *)nma);
			    Lf->nma = (char *)NULL;
			}
			if (s->pst_lo_nodeid) {
	    		    enter_dev_ch(print_kptr((KA_T)s->pst_lo_nodeid,
					 (char *)NULL, 0));
			}
			(void) snpf(Namech, Namechl, "%s", ua->sun_path);
			if (err || s->pst_peer_lo_nodeid) {
			    (void) snpf(buf, sizeof(buf),
				"%s%s%s%s%s%s%s",
				err ? "(Error: " : "",
				err ? strerror(err) : "",
				err ? ")" : "",
				(err && s->pst_peer_lo_nodeid) ? " " : "",
				s->pst_peer_lo_nodeid ? "(->" : "",
				s->pst_peer_lo_nodeid ?
					print_kptr((KA_T)s->pst_peer_lo_nodeid,
						   (char *)NULL, 0)
				:	"",
				s->pst_peer_lo_nodeid ? ")" : ""
			    );
			    len = strlen(buf) + 1;
			    if (!(nma = (char *)malloc((MALLOC_S)len))) {
				(void) fprintf(stderr,
				    "%s: no unix nma space(2): PID %ld, FD %s",
				    Pn, (long)Lp->pid, Lf->fd);
			    }
			    (void) snpf(nma, len, "%s", buf);
			    Lf->nma = nma;
			}
			if (Sfile && is_file_named(ua->sun_path, 0))
			    Lf->sf |= SELNM;
			break;
		    }
		}
	    }
	/*
	 * If the UNIX socket has no bound address (file path), display the
	 * low nodeid in the DEVICE column and the peer's low nodeid in the
	 * NAME column.
	 */
	    if (s->pst_peer_lo_nodeid) {
		(void) snpf(Namech, Namechl, "->%s",
		    print_kptr((KA_T)s->pst_peer_lo_nodeid, (char *)NULL, 0));
	    }
	    if (s->pst_lo_nodeid)
		enter_dev_ch(print_kptr((KA_T)s->pst_lo_nodeid,(char *)NULL,0));
	    break;
	default:
	    (void) snpf(Namech, Namechl, "unsupported family: AF_%d",
		s->pst_family);
	}
	if (Namech[0])
	    enter_nm(Namech);
}


/*
 * process_stream() -- process stream
 */

void
process_stream(f, ckscko)
	struct pst_fileinfo2 *f;		/* pst_fileinfo2 */
	int ckscko;				/* socket file only checking
						 * if 1 */
{
	struct clone *cl;
	char *cp;
	struct l_dev *dp = (struct l_dev *)NULL;
	int hx, i, ncx, nsn, nsr;
	size_t nb, nl;
	KA_T na;
	static int nsa = 0;
	dev_t rdev;
	static struct pst_stream *s = (struct pst_stream *)NULL;
	struct pst_socket sck;
	static size_t sz = sizeof(struct pst_stream);

#if	!defined(PS_STR_XPORT_DATA)
/*
 * If socket file only checking is enabled and this HP-UX PSTAT instance
 * doesn't support TCP or UDP stream eXPORT data, return without further
 * action.
 */
	if (ckscko == 1)
		return;
#endif	/* !defined(PS_STR_XPORT_DATA) */

/*
 * Generate and save node ID.
 */
	na = (KA_T)(((KA_T)(f->psf_hi_nodeid & 0xffffffff) << 32)
	   |		(KA_T)(f->psf_lo_nodeid & 0xffffffff));

#if	defined(HASFSTRUCT)
	if (na && (Fsv & FSV_NI)) {
	    Lf->fna = na;
	    Lf->fsv |= FSV_NI;
	}
#endif	/* defined(HASFSTRUCT) */

/*
 * Enter type.
 */
	switch (f->psf_ftype) {
	case PS_TYPE_STREAMS:
	    cp = "STR";
	    break;
	case PS_TYPE_SOCKET:
	    if (f->psf_subtype == PS_SUBTYPE_SOCKSTR) {
		cp = "STSO";
		break;
	    }
	    /* fall through */
	default:
	    cp = "unkn";
	}
	(void) snpf(Lf->type, sizeof(Lf->type), "%s", cp);
/*
 * Allocate sufficient space for stream structures, then read them.
 */
	if ((nsn = f->psf_nstrentt) && (nsn >= nsa)) {
	    nb = (size_t)(nsn * sizeof(struct pst_stream));
	    if (s)
		s = (struct pst_stream *)realloc((MALLOC_P *)s, nb);
	    else
		s = (struct pst_stream *)malloc(nb);
	    if (!s) {
		(void) fprintf(stderr,
		    "%s: no space for %ld pst_stream bytes\n", Pn, (long)nb);
		Exit(1);
	    }
	    nsa = nsn;
	}
	errno = 0;
	if ((nsr = pstat_getstream(s, sz, (size_t)nsn, 0, &f->psf_fid)) < 1) {
	    if (nsn) {
		(void) snpf(Namech, Namechl,
		    "can't read %d stream structures%s%s", nsn,
		    errno ? ": " : "", errno ? strerror(errno) : "");
		enter_nm(Namech);
	    } else
		enter_nm("no stream structures present");
	    return;
	}
/*
 * Find the stream head.
 */
	for (hx = 0; hx < nsn; hx++) {
	    if (s[hx].type == PS_STR_HEAD)
		break;
	}
	if (hx >= nsn) { 
	    enter_nm("no stream head located");
	    return;
	}
/*
 * Make sure the stream head's fileid and nodeid match the ones in the
 * pst_fileino2 structure.
 */
	if ((f->psf_hi_fileid != s[hx].val.head.pst_hi_fileid)
	 |  (f->psf_lo_fileid != s[hx].val.head.pst_lo_fileid)
	 |  (f->psf_hi_nodeid != s[hx].val.head.pst_hi_nodeid)
	 |  (f->psf_lo_nodeid != s[hx].val.head.pst_lo_nodeid)) {
	    enter_nm("no matching stream data available");
	    return;
	}

#if	defined(PS_STR_XPORT_DATA)
/*
 * See if this stream has eXPORT data available and is a TCP or
 * UDP stream.
 */
	if ((s[hx].pst_extn_flags & PS_STR_XPORT_DATA)
	&&  ((s[hx].pst_str_xport_protocol == PS_STR_XPORT_TCP_PROTO)
	||   (s[hx].pst_str_xport_protocol == PS_STR_XPORT_UDP_PROTO))
	) {

	/*
	 * Make a socket from the eXPORT data and process it.
	 */
	    (void) make_sock(f, &s[hx], &sck);
	    (void) process_socket(f, &sck);
	    return;
	} else if (ckscko || Selinet) {

	/*
	 * If socket file or Internet file only processing is enabled, return.
	 */
	    return;
	}
#endif	/* defined(PS_STR_XPORT_DATA) */

/*
 * Enter size from stream head's structure, if requested.
 */
	if (Fsize) {
	    if (Lf->access == 'r') {
		Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_rbytes;
		Lf->sz_def = 1;
	    } else if (Lf->access == 'w') {
		Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_wbytes;
		Lf->sz_def = 1;
	    } else if (Lf->access == 'u') {
		Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_rbytes
		       + (SZOFFTYPE)s[hx].val.head.pst_wbytes;
		Lf->sz_def = 1;
	    }
	}
/*
 * Get the the device number from the stream head.
 *
 * If the stream is a clone:
 *
 *	if there's a clone list, search it for the device, based on the stream
 *	    head's minor device number only;
 *	if there's no clone list, search Devtp[], using a device number made
 *	    from the stream head's major and minor device numbers;
 *	set the printable clone device number to one whose major device number
 *	    is the stream head's minor device number, and whose minor device
 *	    number is the stream head's device sequence number.
 *
 * If the stream isn't a clone, make the device number from the stream head's
 * major and minor numbers, and look up the non-clone device number in Devtp[].
 */
	if (!Sdev)
	    readdev(0);
	if (s[hx].val.head.pst_flag & PS_STR_ISACLONE) {
	    if (HaveCloneMaj && (CloneMaj == s[hx].val.head.pst_dev_major)) {
		for (cl = Clone; cl; cl = cl->next) {
		    if (GET_MIN_DEV(Devtp[cl->dx].rdev)
		    ==  s[hx].val.head.pst_dev_minor)
		    {
			dp = &Devtp[cl->dx];
			break;
		    }
		}
	    } else {
		rdev = makedev(s[hx].val.head.pst_dev_major,
			       s[hx].val.head.pst_dev_minor);
		dp = lkupdev(&DevDev, &rdev, 0, 1);
	    }
	    rdev = makedev(s[hx].val.head.pst_dev_minor,
			   s[hx].val.head.pst_dev_seq);
	} else {
	    rdev = makedev(s[hx].val.head.pst_dev_major,
			   s[hx].val.head.pst_dev_minor);
	    dp = lkupdev(&DevDev, &rdev, 0, 1);
	}
	Lf->dev = DevDev;
	Lf->rdev = rdev;
	Lf->dev_def = Lf->rdev_def = 1;
/*
 * If the device was located, enter the device name and save the node number.
 *
 * If the device wasn't located, save a positive file ID number from the
 * pst_fileinfo as a node number.
 */
	if (dp) {
	    (void) snpf(Namech, Namechl, "%s", dp->name);
	    ncx = strlen(Namech);
	    Lf->inode = (INODETYPE)dp->inode;
	    Lf->inp_ty = 1;
	} else {
	    ncx = (size_t)0;
	    if (f->psf_id.psf_fileid > 0) {
		Lf->inode = (INODETYPE)f->psf_id.psf_fileid;
		Lf->inp_ty = 1;
	    }
	}
/*
 * Enter stream module names.
 */
	for (i = 1; i < nsr; i++) {
	    if (!(nl = strlen(s[i].val.module.pst_name)))
		continue;
	    if (ncx) {
		if ((ncx + 2) > (Namechl - 1))
		    break;
		(void) snpf(&Namech[ncx], Namechl - ncx, "->");
		ncx += 2;
	    }
	    if ((ncx + nl) > (Namechl - 1))
		break;
	    (void) snpf(Namech+ncx,Namechl-ncx,"%s",s[i].val.module.pst_name);
	    ncx += nl;
	}
/*
 * Set node type.
 *
 * Set offset defined if file size not requested or if no size was
 * obtained from the stream head.
 */
	Lf->ntype = N_STREAM;
	Lf->is_stream = 1;
	if (!Fsize || (Fsize && !Lf->sz_def))
	    Lf->off_def = 1;
/*
 * Test for specified file.
 */
	if ((f->psf_subtype == PS_SUBTYPE_CHARDEV)
	||  (f->psf_subtype == PS_SUBTYPE_BLKDEV))
	    i = 1;
	else
	    i = 0;
	if (Sfile && is_file_named((char *)NULL, i))
	    Lf->sf |= SELNM;
/*
 * Enter any name characters.
 */
	if (Namech[0])
	    enter_nm(Namech);
}


/*
 * read_sock() -- read pst_socket info for file
 */

struct pst_socket *
read_sock(f)
	struct pst_fileinfo2 *f;		/* file information */
{
	static struct pst_socket s;

	errno = 0;
	if (f) {
	    if (pstat_getsocket(&s, sizeof(s), &f->psf_fid) > 0
	    &&  f->psf_hi_fileid == s.pst_hi_fileid
	    &&  f->psf_lo_fileid == s.pst_lo_fileid
	    &&  f->psf_hi_nodeid == s.pst_hi_nodeid
	    &&  f->psf_lo_nodeid == s.pst_lo_nodeid)
		return(&s);
	}
	return((struct pst_socket *)NULL);
}
