/*
 * dsock.c - /dev/kmem-based HP-UX socket processing functions for lsof
 */

/*
 * Copyright 1994 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 1994 Purdue Research Foundation.\nAll rights reserved.\n";
#endif

#if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
#    define _INO_T
typedef int ino_t;
#    define _TIME_T
typedef int time_t;
#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */

#include "common.h"

#if HPUXV >= 800 && defined(HPUX_CCITT)
#    include <x25/x25addrstr.h>
#    include <x25/x25stat.h>
#    include <x25/x25str.h>
#    include <x25/x25config.h>
#    include <x25/x25L3.h>
#endif /* HPUXV>=800 && defined(HPUX_CCITT) */

/*
 * Local definitions
 */

#if defined(HASTCPOPT)
#    define TF_NODELAY 0x1 /* TCP_NODELAY (Nagle algorithm) */
#endif                     /* defined(HASTCPOPT) */

#if HPUXV >= 1030
/*
 * print_tcptpi() - print TCP/TPI info
 */

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

    if (Ftcptpi & TCPTPI_STATE) {
        switch ((t = Lf->lts.type)) {
        case 0: /* TCP */
            switch ((i = Lf->lts.state.i)) {
            case TCPS_CLOSED:
                cp = "CLOSED";
                break;
            case TCPS_IDLE:
                cp = "IDLE";
                break;
            case TCPS_BOUND:
                cp = "BOUND";
                break;
            case TCPS_LISTEN:
                cp = "LISTEN";
                break;
            case TCPS_SYN_SENT:
                cp = "SYN_SENT";
                break;
            case TCPS_SYN_RCVD:
                cp = "SYN_RCVD";
                break;
            case TCPS_ESTABLISHED:
                cp = "ESTABLISHED";
                break;
            case TCPS_CLOSE_WAIT:
                cp = "CLOSE_WAIT";
                break;
            case TCPS_FIN_WAIT_1:
                cp = "FIN_WAIT_1";
                break;
            case TCPS_CLOSING:
                cp = "CLOSING";
                break;
            case TCPS_LAST_ACK:
                cp = "LAST_ACK";
                break;
            case TCPS_FIN_WAIT_2:
                cp = "FIN_WAIT_2";
                break;
            case TCPS_TIME_WAIT:
                cp = "TIME_WAIT";
                break;
            default:
                (void)snpf(sbuf, sizeof(sbuf), "UknownState_%d", i);
                cp = sbuf;
            }
            break;
        case 1: /* TPI */
            switch ((u = Lf->lts.state.ui)) {
            case TS_UNINIT:
                cp = "Uninitialized";
                break;
            case TS_UNBND:
                cp = "Unbound";
                break;
            case TS_WACK_BREQ:
                cp = "Wait_BIND_REQ_Ack";
                break;
            case TS_WACK_UREQ:
                cp = "Wait_UNBIND_REQ_Ack";
                break;
            case TS_IDLE:
                cp = "Idle";
                break;
            case TS_WACK_OPTREQ:
                cp = "Wait_OPT_REQ_Ack";
                break;
            case TS_WACK_CREQ:
                cp = "Wait_CONN_REQ_Ack";
                break;
            case TS_WCON_CREQ:
                cp = "Wait_CONN_REQ_Confirm";
                break;
            case TS_WRES_CIND:
                cp = "Wait_CONN_IND_Response";
                break;
            case TS_WACK_CRES:
                cp = "Wait_CONN_RES_Ack";
                break;
            case TS_DATA_XFER:
                cp = "Wait_Data_Xfr";
                break;
            case TS_WIND_ORDREL:
                cp = "Wait_Read_Release";
                break;
            case TS_WREQ_ORDREL:
                cp = "Wait_Write_Release";
                break;
            case TS_WACK_DREQ6:
            case TS_WACK_DREQ7:
            case TS_WACK_DREQ9:
            case TS_WACK_DREQ10:
            case TS_WACK_DREQ11:
                cp = "Wait_DISCON_REQ_Ack";
                break;
            case TS_WACK_ORDREL:
                cp = "Internal";
                break;
            default:
                (void)snpf(sbuf, sizeof(sbuf), "UNKNOWN_TPI_STATE_%u", u);
                cp = sbuf;
            }
        }
        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 ||
            Lf->lts.rbszs || Lf->lts.sbsz) {
            char sep = ' ';

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

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

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

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

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

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

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

            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(SO_REUSEADDR)
            if (opt & SO_REUSEADDR) {
                (void)printf("%cREUSEADDR", sep);
                opt &= ~SO_REUSEADDR;
                sep = ',';
            }
#        endif /* defined(SO_REUSEADDR) */

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

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

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

#    if defined(HASTCPOPT)
    if (Ftcptpi & TCPTPI_FLAGS) {
        int topt;

        if ((topt = Lf->lts.topt) || Lf->lts.msss) {
            char sep = ' ';

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

            if (Lf->lts.msss) {
                (void)printf("%cMSS=%lu", sep, Lf->lts.mss);
                sep = ',';
            }

#        if defined(TF_NODELAY)
            if (topt & TF_NODELAY) {
                (void)printf("%cNODELAY", sep);
                topt &= ~TF_NODELAY;
                sep = ',';
            }
#        endif /* defined(TF_NODELAY) */

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

#    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');
}
#endif /* HPUXV>=1030 */

#if defined(DTYPE_LLA)
/*
 * process_lla() - process link level access socket file
 */

void process_lla(la) KA_T la; /* link level CB address in kernel */
{
    char *ep;
    struct lla_cb lcb;
    size_t sz;

    Lf->type = LSOF_FILE_LINK_LEVEL_ACCESS;
    Lf->inp_ty = 2;
    enter_dev_ch(print_kptr(la, (char *)NULL, 0));
    /*
     * Read link level access control block.
     */
    if (!la || kread(ctx, (KA_T)la, (char *)&lcb, sizeof(lcb))) {
        (void)snpf(Namech, Namechl, "can't read LLA CB (%s)",
                   print_kptr(la, (char *)NULL, 0));
        enter_nm(Namech);
        return;
    }
    /*
     * Determine access mode.
     */
    if ((lcb.lla_flags & LLA_FWRITE | LLA_FREAD) == LLA_FWRITE)
        Lf->access = LSOF_FILE_ACCESS_WRITE;
    else if ((lcb.lla_flags & LLA_FWRITE | LLA_FREAD) == LLA_FREAD)
        Lf->access = LSOF_FILE_ACCESS_READ;
    else if (lcb.lla_flags & LLA_FWRITE | LLA_FREAD)
        Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
    /*
     * Determine the open mode, if possible.
     */
    if (lcb.lla_flags & LLA_IS_ETHER)
        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "Ether");
    else if (lcb.lla_flags & (LLA_IS_8025 | LLA_IS_SNAP8025 | LLA_IS_FA8025)) {
        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "802.5");
        if (lcb.lla_flags & LLA_IS_SNAP8025)
            (void)snpf(Namech, Namechl, "SNAP");
        else if (lcb.lla_flags & LLA_IS_FA8025)
            (void)snpf(Namech, Namechl, "function address");
    }
    /*
     * Add any significant flags.
     */
    if (lcb.lla_flags & ~(LLA_FWRITE | LLA_FREAD)) {
        ep = endnm(&sz);
        (void)snpf(ep, sz, "%s(flags = %#x)", (ep == Namech) ? "" : " ",
                   lcb.lla_flags);
    }
    if (Namech[0])
        enter_nm(Namech);
}
#endif /* DTYPE_LLA */

/*
 * process_socket() - process socket
 */

void process_socket(sa) KA_T sa; /* socket address in kernel */
{
    unsigned char *fa = (unsigned char *)NULL;
    char *ep, tbuf[32];
    int fam;
    int fp, mbl, lp;
    unsigned char *la = (unsigned char *)NULL;
    struct protosw p;
    struct socket s;
    size_t sz;
    struct unpcb uc, unp;
    struct sockaddr_un *ua = (struct sockaddr_un *)NULL;
    struct sockaddr_un un;

#if HPUXV >= 800
    struct domain d;

#    if defined(HPUX_CCITT)
    int i;
    struct x25pcb xp;
    struct x25pcb_extension xpe;
#    endif /* defined(HPUX_CCITT) */

#    if HPUXV < 1030
    struct mbuf mb;
    struct inpcb inp;
    struct rawcb raw;
    struct tcpcb t;
#    else  /* HPUXV>=1030 */
    struct datab db;
    static char *dbf = (char *)NULL;
    static int dbl = 0;
    struct msgb mb;
    struct sockbuf rb, sb;
#    endif /* HPUXV<1030 */
#endif     /* HPUXV>=800 */

    Lf->type = LSOF_FILE_SOCKET;
    Lf->inp_ty = 2;
    /*
     * Read socket structure.
     */
    if (!sa) {
        enter_nm("no socket address");
        return;
    }
    if (kread(ctx, (KA_T)sa, (char *)&s, sizeof(s))) {
        (void)snpf(Namech, Namechl, "can't read socket struct from %s",
                   print_kptr(sa, (char *)NULL, 0));
        enter_nm(Namech);
        return;
    }
    /*
     * Read protocol switch and domain structure (HP-UX 8 and above).
     */
    if (!s.so_type) {
        (void)snpf(Namech, Namechl, "no socket type");
        enter_nm(Namech);
        return;
    }
    if (!s.so_proto || kread(ctx, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
        (void)snpf(Namech, Namechl, "no protocol switch");
        enter_nm(Namech);
        return;
    }

#if HPUXV >= 800
    if (kread(ctx, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
        (void)snpf(Namech, Namechl, "can't read domain struct from %s",
                   print_kptr((KA_T)p.pr_domain, (char *)NULL, 0));
        enter_nm(Namech);
        return;
    }
#endif /* HPUXV>=800 */

#if HPUXV < 1030
    /*
     * Save size information for HP-UX < 10.30.
     */
    if (Lf->access == LSOF_FILE_ACCESS_READ)
        Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc;
    else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
        Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc;
    else
        Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc);
    Lf->sz_def = 1;

#    if defined(HASTCPTPIQ)
    Lf->lts.rq = s.so_rcv.sb_cc;
    Lf->lts.sq = s.so_snd.sb_cc;
    Lf->lts.rqs = Lf->lts.sqs = 1;
#    endif /* defined(HASTCPTPIQ) */
#endif     /* HPUXV<1030 */

    /*
     * Process socket by the associated domain family.
     */

#if HPUXV >= 800
    switch ((fam = d.dom_family))
#else  /* HPUXV<800 */
    switch ((fam = p.pr_family))
#endif /* HPUXV>=800 */

    {

#if HPUXV >= 800 && HPUXV < 1030 && defined(HPUX_CCITT)
        /*
         * Process an HP-UX [89].x CCITT X25 domain socket.
         */
    case AF_CCITT:
        if (Fnet)
            Lf->sf |= SELNET;
        Lf->type = LSOF_FILE_X25;
        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL, "CCITT");
        /*
         * Get the X25 PCB and its extension.
         */
        if (!s.so_pcb || kread(ctx, (KA_T)s.so_pcb, (char *)&xp, sizeof(xp))) {
            (void)snpf(Namech, Namechl, "can't read x.25 pcb at %s",
                       print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        enter_dev_ch(print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
        if (!xp.x25pcb_extend ||
            kread(ctx, (KA_T)xp.x25pcb_extend, (char *)&xpe, sizeof(xpe))) {
            (void)snpf(Namech, Namechl,
                       "can't read x.25 pcb (%s) extension at %s",
                       print_kptr((KA_T)s.so_pcb, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)xp.x25pcb_extend, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        /*
         * Format local address.
         */
        for (i = 0; i < xpe.x25pcbx_local_addr.x25hostlen / 2; i++) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, "%02x", xpe.x25pcbx_local_addr.x25_host[i]);
        }
        if (i * 2 != xpe.x25pcbx_local_addr.x25hostlen) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, "%01x", xpe.x25pcbx_local_addr.x25_host[i] >> 4);
        }
        /*
         * Display the virtual connection number, if it's defined.
         */
        if (xp.x25pcb_vcn >= 0) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, ":%d", xp.x25pcb_vcn + 1);
        }
        /*
         * Format peer address, if there is one.
         */
        if (xpe.x25pcbx_peer_addr.x25hostlen > 0) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, "->");
            for (i = 0; i < xpe.x25pcbx_peer_addr.x25hostlen / 2; i++) {
                ep = endnm(&sz);
                (void)snpf(ep, sz, "%02x", xpe.x25pcbx_peer_addr.x25_host[i]);
            }
            if (i * 2 != xpe.x25pcbx_peer_addr.x25hostlen) {
                ep = endnm(&sz);
                (void)snpf(ep, sz, "%01x",
                           xpe.x25pcbx_peer_addr.x25_host[i] >> 4);
            }
        }
        enter_nm(Namech);
        break;
#endif /* HPUXV>=800 && HPUXV<1030 && defined(HPUX_CCITT) */

        /*
         * Process an Internet domain socket.
         */
    case AF_INET:
        if (Fnet)
            Lf->sf |= SELNET;
        Lf->type = LSOF_FILE_INET;
        printiproto(ctx, p.pr_protocol);

#if HPUXV >= 1030
        /*
         * Handle HP-UX 10.30 and above socket streams.
         */
        if (s.so_sth) {

            KA_T ip, pcb;
            char *pn = (char *)NULL;
            /*
             * Read module information.
             */
            if (read_mi((KA_T)s.so_sth, &ip, &pcb, &pn))
                return;
            if (ip && pcb) {

                /*
                 * If IP and TCP or UDP modules are present, process as a
                 * stream socket.
                 */
                process_stream_sock(ip, pcb, pn, VNON);
                return;
            }
            /*
             * If an IP module's PCB address is present, print it as the
             * device characters.
             */

            if (ip && !Lf->dev_def)
                enter_dev_ch(print_kptr(ip, (char *)NULL, 0));
            if (!strlen(Namech)) {

                /*
                 * If there are no NAME field characters, enter an error
                 * message.
                 */
                if (!ip) {
                    (void)snpf(Namech, Namechl,
                               "no IP module for stream socket");
                } else {
                    (void)snpf(Namech, Namechl,
                               "no TCP/UDP module for stream socket");
                }
            }
            enter_nm(Namech);
            return;
        }
#else  /* HPUXV<1030 */

        /*
         * Read protocol control block.
         */
        if (!s.so_pcb) {
            enter_nm("no protocol control block");
            return;
        }
        if (s.so_type == SOCK_RAW) {

            /*
             * Print raw socket information.
             */
            if (kread(ctx, (KA_T)s.so_pcb, (char *)&raw, sizeof(raw)) ||
                (struct socket *)sa != (struct socket *)raw.rcb_socket) {
                (void)snpf(Namech, Namechl, "can't read rawcb at %s",
                           print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            enter_dev_ch(print_kptr(
                (KA_T)(raw.rcb_pcb ? raw.rcb_pcb : s.so_pcb), (char *)NULL, 0));
            if (raw.rcb_laddr.sa_family == AF_INET)
                la = (unsigned char *)&raw.rcb_laddr.sa_data[2];
            else if (raw.rcb_laddr.sa_family)
                printrawaddr(&raw.rcb_laddr);
            if (raw.rcb_faddr.sa_family == AF_INET)
                fa = (unsigned char *)&raw.rcb_faddr.sa_data[2];
            else if (raw.rcb_faddr.sa_family) {
                ep = endnm(&sz);
                (void)snpf(ep, sz, "->");
                printrawaddr(&raw.rcb_faddr);
            }
            if (fa || la)
                (void)ent_inaddr(la, -1, fa, -1, AF_INET);
        } else {

            /*
             * Print Internet socket information.
             */
            if (kread(ctx, (KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) {
                (void)snpf(Namech, Namechl, "can't read inpcb at %s",
                           print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            enter_dev_ch(
                print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb : s.so_pcb),
                           (char *)NULL, 0));
            la = (unsigned char *)&inp.inp_laddr;
            lp = (int)ntohs(inp.inp_lport);
            if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
                fa = (unsigned char *)&inp.inp_faddr;
                fp = (int)ntohs(inp.inp_fport);
            }
            if (fa || la)
                (void)ent_inaddr(la, lp, fa, fp, AF_INET);
            if (p.pr_protocol == IPPROTO_TCP && inp.inp_ppcb &&
                kread(ctx, (KA_T)inp.inp_ppcb, (char *)&t, sizeof(t)) == 0) {
                Lf->lts.type = 0;
                Lf->lts.state.i = (int)t.t_state;
            }
        }
        break;
#endif /* HPUXV>=1030 */

        /*
         * Process a Unix domain socket.
         */
    case AF_UNIX:
        if (Funix)
            Lf->sf |= SELUNX;
        Lf->type = LSOF_FILE_UNIX;

#if HPUXV >= 1030
        /*
         * Save size information for HP-UX 10.30 and above.
         */
        if (!s.so_rcv || kread(ctx, (KA_T)s.so_rcv, (char *)&rb, sizeof(rb)))
            rb.sb_cc = 0;
        if (!s.so_snd || kread(ctx, (KA_T)s.so_snd, (char *)&sb, sizeof(sb)))
            sb.sb_cc = 0;
        if (Lf->access == LSOF_FILE_ACCESS_READ)
            Lf->sz = (SZOFFTYPE)rb.sb_cc;
        else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
            Lf->sz = (SZOFFTYPE)sb.sb_cc;
        else
            Lf->sz = (SZOFFTYPE)(rb.sb_cc + sb.sb_cc);
        Lf->sz_def = 1;
#endif /* HPUXV>=1030 */

        /*
         * Read Unix protocol control block and the Unix address structure.
         */
        enter_dev_ch(print_kptr(sa, (char *)NULL, 0));
        if (kread(ctx, (KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) {
            (void)snpf(Namech, Namechl, "can't read unpcb at %s",
                       print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
            break;
        }
        if ((struct socket *)sa != unp.unp_socket) {
            (void)snpf(Namech, Namechl, "unp_socket (%s) mismatch",
                       print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0));
            break;
        }

#if HPUXV < 1030
        /*
         * Read UNIX domain socket address information for HP-UX below 10.30.
         */
        if (unp.unp_addr) {
            if (kread(ctx, (KA_T)unp.unp_addr, (char *)&mb, sizeof(mb))) {
                (void)snpf(Namech, Namechl, "can't read unp_addr at %s",
                           print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0));
                break;
            }
            ua = (struct sockaddr_un *)(((char *)&mb) + mb.m_off);
            mbl = mb.m_len;
        }
#else  /* HPUXV>=1030 */
        /*
         * Obtain UNIX domain socket address information for HP-UX 10.30 and
         * above.
         */
        if (unp.unp_ino) {
            Lf->inode = (INODETYPE)unp.unp_ino;
            Lf->inp_ty = 1;
        }
        ua = (struct sockaddr_un *)NULL;
        mbl = 0;
        if (unp.unp_addr &&
            kread(ctx, (KA_T)unp.unp_addr, (char *)&mb, sizeof(mb)) == 0 &&
            mb.b_datap &&
            kread(ctx, (KA_T)mb.b_datap, (char *)&db, sizeof(db)) == 0) {
            if (db.db_base) {
                if (dbl < (db.db_size + 1)) {
                    dbl = db.db_size + 1;
                    if (dbf)
                        dbf = (char *)realloc((MALLOC_P *)dbf, (MALLOC_S)dbl);
                    else
                        dbf = (char *)malloc((MALLOC_S)dbl);
                    if (!dbf) {
                        (void)fprintf(
                            stderr,
                            "%s: no space (%d) for UNIX socket address\n", Pn,
                            dbl);
                        Error(ctx);
                    }
                }
                if (kread(ctx, (KA_T)db.db_base, dbf, db.db_size) == 0) {
                    mbl = db.db_size;
                    dbf[mbl] = '\0';
                    ua = (struct sockaddr_un *)dbf;
                }
            }
        }
#endif /* HPUXV>=1030 */

        if (!ua) {
            ua = &un;
            (void)bzero((char *)ua, sizeof(un));
            ua->sun_family = AF_UNSPEC;
        }
        /*
         * Print information on Unix socket that has no address bound
         * to it, although it may be connected to another Unix domain
         * socket as a pipe.
         */
        if (ua->sun_family != AF_UNIX) {
            if (ua->sun_family == AF_UNSPEC) {
                if (unp.unp_conn) {
                    if (kread(ctx, (KA_T)unp.unp_conn, (char *)&uc, sizeof(uc)))
                        (void)snpf(
                            Namech, Namechl, "can't read unp_conn at %s",
                            print_kptr((KA_T)unp.unp_conn, (char *)NULL, 0));
                    else
                        (void)snpf(
                            Namech, Namechl, "->%s",
                            print_kptr((KA_T)uc.unp_socket, (char *)NULL, 0));
                } else
                    (void)snpf(Namech, Namechl, "->(none)");
            } else
                (void)snpf(Namech, Namechl, "unknown sun_family (%d)",
                           ua->sun_family);
            break;
        }
        if (ua->sun_path[0]) {
            if (mbl >= sizeof(struct sockaddr_un))
                mbl = sizeof(struct sockaddr_un) - 1;
            *((char *)ua + mbl) = '\0';
            if (Sfile && is_file_named(ua->sun_path, 0))
                Lf->sf |= SELNM;
            if (!Namech[0])
                (void)snpf(Namech, Namechl, "%s", ua->sun_path);
        } else
            (void)snpf(Namech, Namechl, "no address");
        break;
    default:
        printunkaf(fam, 1);
    }
    if (Namech[0])
        enter_nm(Namech);
}

#if HPUXV >= 1030
/*
 * process_stream_sock() - process stream socket
 */

void process_stream_sock(ip, pcb, pn, vt) KA_T ip; /* IP module's q_ptr */
KA_T pcb;                                          /* protocol's q_ptr */
char *pn;                                          /* protocol name */
enum vtype vt;                                     /* vnode type */
{
    unsigned char *fa = (unsigned char *)NULL;
    char *ep;
    int fp, lp, rq, sq;
    struct ipc_s ic;
    unsigned char *la = (unsigned char *)NULL;
    size_t sz;
    u_short pt;
    struct tcp_s tc;
    tcph_t th;
    struct udp_s ud;
    /*
     * Set file type and protocol.  If AF_INET selection is in effect, set its
     * flag.
     */
    if (Fnet)
        Lf->sf |= SELNET;
    Lf->type = LSOF_FILE_INET;
    if (pn) {
        (void)snpf(Lf->iproto, sizeof(Lf->iproto), pn);
        Lf->inp_ty = 2;
    } else if (Sfile && (vt != VNON) && Lf->dev_def && (Lf->inp_ty == 1)) {

        /*
         * If the protocol name isn't known and this stream socket's vnode type
         * isn't VNON, the stream socket will be handled mostly as a stream.
         * Thus, a named file check is appropriate.
         */
        if (is_file_named((char *)NULL, (vt == VCHR) ? 1 : 0))
            Lf->sf |= SELNM;
    }
    /*
     * Get IP structure.
     */
    *Namech = '\0';
    if (!ip || kread(ctx, ip, (char *)&ic, sizeof(ic))) {
        ep = endnm(&sz);
        (void)snpf(ep, sz, "%scan't read IP control structure from %s",
                   sz ? " " : "", print_kptr(ip, (char *)NULL, 0));
        enter_nm(Namech);
        return;
    }
    if (!Lf->dev_def)
        enter_dev_ch(print_kptr(ip, (char *)NULL, 0));
    /*
     * Check for protocol control block address.  Enter if non-NULL and clear
     * device definition flag.
     */
    if (!pcb) {
        ep = endnm(&sz);
        (void)snpf(ep, sz, "%ssocket stream has no TCP or UDP module",
                   sz ? " " : "");
        enter_nm(Namech);
        return;
    }
    /*
     * Select processing by protocol name.
     */
    if (pn && !strcmp(pn, "TCP")) {

        /*
         * Process TCP socket.
         */
        if (kread(ctx, pcb, (char *)&tc, sizeof(tc))) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, "%scan't read TCP PCB from %s", sz ? " " : "",
                       print_kptr(pcb, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        /*
         * Save TCP address.
         */
        la = (unsigned char *)&ic.ipc_tcp_laddr;
        pt = (u_short)ic.ipc_tcp_lport;
        if (((struct in_addr *)la)->s_addr == INADDR_ANY && pt == 0) {

            /*
             * If the ipc_s structure has no local address, use the local
             * address in its tcp_iph structure, and the port number in its
             * tcph structure.
             */
            la = (unsigned char *)&tc.tcp_u.tcp_u_iph.iph_src[0];
            if (tc.tcp_hdr_len && tc.tcp_tcph &&
                kread(ctx, (KA_T)tc.tcp_tcph, (char *)&th, sizeof(th)) == 0)
                pt = (u_short)th.th_lport;
        }
        lp = (int)ntohs(pt);
        if ((int)ic.ipc_tcp_faddr != INADDR_ANY ||
            (u_short)ic.ipc_tcp_fport != 0) {
            fa = (unsigned char *)&ic.ipc_tcp_faddr;
            fp = (int)ntohs((u_short)ic.ipc_tcp_fport);
        }
        if (fa || la)
            (void)ent_inaddr(la, lp, fa, fp, AF_INET);
        /*
         * Save TCP state and size information.
         */
        Lf->lts.type = 0;
        Lf->lts.state.i = (int)tc.tcp_state;

#    if defined(HASTCPTPIQ) || defined(HASTCPTPIW)
#        if defined(HASTCPTPIW)
        Lf->lts.rw = (int)tc.tcp_rwnd;
        Lf->lts.ww = (int)tc.tcp_swnd;
        Lf->lts.rws = Lf->lts.wws = 1;
#        endif /* defined(HASTCPTPIW) */

        if ((rq = (int)tc.tcp_rnxt - (int)tc.tcp_rack - 1) < 0)
            rq = 0;
        if ((sq = (int)tc.tcp_snxt - (int)tc.tcp_suna - 1) < 0)
            sq = 0;

#        if defined(HASTCPTPIQ)
        Lf->lts.rq = (unsigned long)rq;
        Lf->lts.sq = (unsigned long)sq;
        Lf->lts.rqs = Lf->lts.sqs = 1;
#        endif /* defined(HASTCPTPIQ) */

        if (Lf->access == LSOF_FILE_ACCESS_READ)
            Lf->sz = (SZOFFTYPE)rq;
        else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
            Lf->sz = (SZOFFTYPE)sq;
        else
            Lf->sz = (SZOFFTYPE)(rq + sq);
        Lf->sz_def = 1;

#    endif /* defined(HASTCPTPIQ) || defined(HASTCPTPIW) */

#    if defined(HASTCPOPT)

        /*
         * Save TCP options and values..
         */
        if (tc.tcp_naglim == (uint)1)
            Lf->lts.topt |= TF_NODELAY;
        Lf->lts.mss = (unsigned long)tc.tcp_mss;
        Lf->lts.msss = (unsigned char)1;
#    endif /* defined(HASTCPOPT) */

#    if defined(HASSOOPT)

        /*
         * Save socket options.
         */
        if (tc.tcp_broadcast)
            Lf->lts.opt |= SO_BROADCAST;
        if (tc.tcp_so_debug)
            Lf->lts.opt |= SO_DEBUG;
        if (tc.tcp_dontroute)
            Lf->lts.opt |= SO_DONTROUTE;
        if (tc.tcp_keepalive_intrvl && (tc.tcp_keepalive_intrvl != 7200000)) {
            Lf->lts.opt |= SO_KEEPALIVE;
            Lf->lts.kai = (unsigned int)tc.tcp_keepalive_intrvl;
        }
        if (tc.tcp_lingering) {
            Lf->lts.opt |= SO_LINGER;
            Lf->lts.ltm = (unsigned int)tc.tcp_linger;
        }
        if (tc.tcp_oobinline)
            Lf->lts.opt |= SO_OOBINLINE;
        if (tc.tcp_reuseaddr)
            Lf->lts.opt |= SO_REUSEADDR;
        if (tc.tcp_reuseport)
            Lf->lts.opt |= SO_REUSEPORT;
        if (tc.tcp_useloopback)
            Lf->lts.opt |= SO_USELOOPBACK;
        Lf->lts.qlen = (unsigned int)tc.tcp_conn_ind_cnt;
        Lf->lts.qlim = (unsigned int)tc.tcp_conn_ind_max;
        if (Lf->lts.qlen || Lf->lts.qlim)
            Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1;
#    endif /* defined(HASSOOPT) */

        Namech[0] = '\0';
        return;
    } else if (pn && !strcmp(pn, "UDP")) {

        /*
         * Process UDP socket.
         */
        if (kread(ctx, pcb, (char *)&ud, sizeof(ud))) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, "%scan't read UDP PCB from %s", sz ? " " : "",
                       print_kptr(pcb, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        /*
         * Save UDP address and TPI state.
         */
        la = (unsigned char *)&ic.ipc_udp_addr;
        pt = (u_short)ic.ipc_udp_port;
        if (((struct in_addr *)la)->s_addr == INADDR_ANY && pt == 0) {

            /*
             * If the ipc_s structure has no local address, use the one in the
             * udp_s structure.
             */
            pt = (u_short)ud.udp_port[0];
        }
        (void)ent_inaddr(la, (int)ntohs(pt), (unsigned char *)NULL, -1,
                         AF_INET);
        Lf->lts.type = 1;
        Lf->lts.state.ui = (unsigned int)ud.udp_state;
        Namech[0] = '\0';
        return;
    } else {

        /*
         * Record an unknown protocol.
         */
        ep = endnm(&sz);
        (void)snpf(ep, sz, "%sunknown stream protocol: %s", sz ? " " : "",
                   pn ? pn : "NUll");
    }
    if (Namech[0])
        enter_nm(Namech);
}
#endif /* HPUXV>=1030 */
