/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Chelsio Communications, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <sys/cdefs.h> #include "tcb_common.h" /***:----------------------------------------------------------------------- ***: externals ***:----------------------------------------------------------------------- */ extern _TCBVAR g_tcb_info4[]; extern _TCBVAR g_scb_info4[]; extern _TCBVAR g_fcb_info4[]; extern void t4_display_tcb_aux_0(_TCBVAR *tvp,int aux); extern void t4_display_tcb_aux_1(_TCBVAR *tvp,int aux); extern void t4_display_tcb_aux_2(_TCBVAR *tvp,int aux); extern void t4_display_tcb_aux_3(_TCBVAR *tvp,int aux); extern _TCBVAR g_tcb_info5[]; extern _TCBVAR g_scb_info5[]; extern _TCBVAR g_fcb_info5[]; extern void t5_display_tcb_aux_0(_TCBVAR *tvp,int aux); extern void t5_display_tcb_aux_1(_TCBVAR *tvp,int aux); extern void t5_display_tcb_aux_2(_TCBVAR *tvp,int aux); extern void t5_display_tcb_aux_3(_TCBVAR *tvp,int aux); extern _TCBVAR g_tcb_info6[]; extern _TCBVAR g_scb_info6[]; extern _TCBVAR g_fcb_info6[]; extern void t6_display_tcb_aux_0(_TCBVAR *tvp,int aux); extern void t6_display_tcb_aux_1(_TCBVAR *tvp,int aux); extern void t6_display_tcb_aux_2(_TCBVAR *tvp,int aux); extern void t6_display_tcb_aux_3(_TCBVAR *tvp,int aux); extern void t6_display_tcb_aux_4(_TCBVAR *tvp,int aux); /***:----------------------------------------------------------------------- ***: globals ***:----------------------------------------------------------------------- */ _TCBVAR *g_tcb_info=g_tcb_info5; _TCBVAR *g_scb_info=g_scb_info5; _TCBVAR *g_fcb_info=g_fcb_info5; static int g_tN=0; static int g_prntstyl=PRNTSTYL_COMP; static int g_got_scb=0; static int g_got_fcb=0; /***:----------------------------------------------------------------------- ***: error exit functions ***:----------------------------------------------------------------------- */ /**: err_exit functions *: ------------------ */ void tcb_prflush(void) { fflush(stdout); fflush(stderr); } void tcb_code_err_exit(char *fmt, ...) { va_list args; va_start(args, fmt); printf("Coding Error in: "); vprintf(fmt, args); printf("\n"); tcb_prflush(); va_end(args); exit(1); } /***:----------------------------------------------------------------------- ***: tcb_hexdump functions ***:----------------------------------------------------------------------- */ void tcb_hexdump(unsigned base, unsigned char *buf, unsigned int size) { unsigned offset; for (offset = 0; offset < size; ++offset) { if (!(offset % 16)) printf("\n0x%4.4x: ", base + offset); else if (!(offset % 8)) printf(" "); printf("%2.2x ", (unsigned char)buf[offset]); } } int tcb_strmatch_nc(char *cs, char *ct) { while (*cs) if (tolower(*cs++) != tolower(*ct++)) return (FALSE); return (!(*ct)); /*return TRUE if *ct NULL at same time as *cs==NULL*/ } /*: ------------------------------------------------------------------------- string functions tcb_strmatch_nc: Similar to exact match, but case insensitive. */ int tcb_strncmp_nc(char *cs, char *ct, int n) { /*case insensitive version of the standard strncmp() function */ int i = 0; int ret; ret = 0; for (i = 0; i < n && 0 == ret && !(EOS == *cs && EOS == *ct); ++i) { /* this is weird, but it matched GCC linux when strings don't * have any upper case characters. */ ret = tolower(*cs++) - tolower(*ct++); } return ret; } int tcb_startswith_nc(char *cs, char *ct) { /* return true if cs start with ct */ return (0 == tcb_strncmp_nc(cs, ct, (int)strlen(ct))); } /***:----------------------------------------------------------------------- ***: START OF WINDOWS FUNCTIONS ***:----------------------------------------------------------------------- */ /***:----------------------------------------------------------------------- ***: print utilities ***:----------------------------------------------------------------------- */ static int g_PR_indent=1; void PR(char *fmt, ...) { int fmt_len; va_list args; va_start(args,fmt); if (g_PR_indent) printf(" "); g_PR_indent=0; fmt_len=(int) strlen(fmt); if (fmt_len>0 && fmt[fmt_len-1]=='\n') g_PR_indent=1; vprintf(fmt,args); tcb_prflush(); va_end(args); } /***:----------------------------------------------------------------------- ***: val() ***:----------------------------------------------------------------------- */ _TCBVAR * lu_tcbvar(char *name) { _TCBVAR *tvp=g_tcb_info; while (tvp->name!=NULL) { if (tcb_strmatch_nc(name,tvp->name)) return tvp; else if (tcb_strmatch_nc(name,tvp->aka )) return tvp; tvp+=1; } tcb_code_err_exit("lu_tcbvar: bad name %s\n",name); return NULL; } unsigned val(char *name) { _TCBVAR *tvp; tvp=lu_tcbvar(name); return tvp->val; } ui64 val64(char *name) { _TCBVAR *tvp; tvp=lu_tcbvar(name); return tvp->rawval; } /***:----------------------------------------------------------------------- ***: get_tcb_bits ***:----------------------------------------------------------------------- */ static int get_tcb_bit(unsigned char *A, int bit) { int ret=0; int ix,shift; ix = 127 - (bit>>3); shift=bit&0x7; /* prdbg(" ix: %u, shift=%u\n",ix,shift); */ ret=(A[ix] >> shift) & 1; return ret; } static ui64 get_tcb_bits (unsigned char *A, int hi, int lo) { ui64 ret=0; if (lo>hi) { int temp=lo; lo=hi; hi=temp; } while (hi>=lo) { ret = (ret<<1) | get_tcb_bit(A,hi); --hi; } return ret; } void decompress_val(_TCBVAR *tvp,unsigned ulp_type,unsigned tx_max, unsigned rcv_nxt,unsigned rx_frag0_start_idx_raw) { unsigned rawval=(unsigned) tvp->rawval; switch(tvp->comp) { case COMP_NONE: tvp->val=rawval; break; case COMP_ULP: tvp->val=rawval; break; case COMP_TX_MAX: tvp->val=(tx_max - rawval) & 0xFFFFFFFF; break; case COMP_RCV_NXT: if (tcb_startswith_nc(tvp->name,"rx_frag")) { unsigned fragx=0; if (!tcb_strmatch_nc(tvp->name,"rx_frag0_start_idx_raw")) fragx=rawval; tvp->val=(rcv_nxt+rx_frag0_start_idx_raw+fragx) & 0xFFFFFFFF; } else { tvp->val=(rcv_nxt - rawval) & 0xFFFFFFFF; } break; case COMP_PTR: tvp->val=rawval; break; case COMP_LEN: { tvp->val=rawval; if (PM_MODE_RDDP==ulp_type || PM_MODE_DDP==ulp_type || PM_MODE_IANDP==ulp_type) { /* TP does this internally. Not sure if I should show the * unaltered value or the raw value. For now I * will display the raw value. For now I've added the code * mainly to stop windows compiler from warning about ulp_type * being an unreferenced parameter. */ tvp->val=0; tvp->val=rawval; /* comment this out to display altered value */ } } break; default: tcb_code_err_exit("decompress_val, bad switch: %d",tvp->comp); break; } } void get_tcb_field(_TCBVAR *tvp,unsigned char *buf) { assert(tvp->hi-tvp->lo+1<=64); assert(tvp->hi>=tvp->lo); tvp->rawval=get_tcb_bits(buf,tvp->lo,tvp->hi); /* assume no compression and 32-bit value for now */ tvp->val=(unsigned) (tvp->rawval & 0xFFFFFFFF); } /***:----------------------------------------------------------------------- ***: spr_* functions ***:----------------------------------------------------------------------- */ char * spr_tcp_state (unsigned state) { char *ret="UNKNOWN"; if ( 0 == state) {ret = "CLOSED";} else if ( 1 == state) {ret = "LISTEN";} else if ( 2 == state) {ret = "SYN_SENT";} else if ( 3 == state) {ret = "SYN_RCVD";} else if ( 4 == state) {ret = "ESTABLISHED";} else if ( 5 == state) {ret = "CLOSE_WAIT";} else if ( 6 == state) {ret = "FIN_WAIT_1";} else if ( 7 == state) {ret = "CLOSING";} else if ( 8 == state) {ret = "LAST_ACK";} else if ( 9 == state) {ret = "FIN_WAIT_2";} else if (10 == state) {ret = "TIME_WAIT";} else if (11 == state) {ret = "ESTABLISHED_RX";} else if (12 == state) {ret = "ESTABLISHED_TX";} else if (13 == state) {ret = "SYN_PEND";} else if (14 == state) {ret = "ESC_1_STATE";} else if (15 == state) {ret = "ESC_2_STATE";} return ret; } char * spr_cctrl_sel(unsigned sel0,unsigned sel1) { unsigned sel=(sel1<<1) | sel0; char *ret="UNKNOWN"; if ( 0 == sel) {ret = "Reno";} else if ( 1 == sel) {ret = "Tahoe";} else if ( 2 == sel) {ret = "NewReno";} else if ( 3 == sel) {ret = "HighSpeed";} return ret; } char * spr_ulp_type(unsigned ulp_type) { char *ret="UNKNOWN"; /*The tp.h PM_MODE_XXX call 1 DDP and 5 IANDP, but external * documentation (tcb.h" calls 5 ddp, and doesn't mention 1 or 3. */ if ( PM_MODE_PASS == ulp_type) {ret = "TOE";} else if ( PM_MODE_DDP == ulp_type) {ret = "DDP";} else if ( PM_MODE_ISCSI == ulp_type) {ret = "ISCSI";} else if ( PM_MODE_IWARP == ulp_type) {ret = "IWARP";} else if ( PM_MODE_RDDP == ulp_type) {ret = "RDMA";} else if ( PM_MODE_IANDP == ulp_type) {ret = "IANDP_DDP";} else if ( PM_MODE_FCOE == ulp_type) {ret = "FCoE";} else if ( PM_MODE_USER == ulp_type) {ret = "USER";} else if ( PM_MODE_TLS == ulp_type) {ret = "TLS";} else if ( PM_MODE_DTLS == ulp_type) {ret = "DTLS";} return ret; } char * spr_ip_version(unsigned ip_version) { char *ret="UNKNOWN"; if ( 0 == ip_version) {ret = "IPv4";} else if ( 1 == ip_version) {ret = "IPv6";} return ret; } /***:----------------------------------------------------------------------- ***: display_tcb() ***:----------------------------------------------------------------------- */ void display_tcb_compressed(_TCBVAR *tvp,int aux) { if (g_tN==4) { t4_display_tcb_aux_0(tvp,aux); if (1==aux) t4_display_tcb_aux_1(tvp,aux); else if (2==aux) t4_display_tcb_aux_2(tvp,aux); else if (3==aux) t4_display_tcb_aux_3(tvp,aux); } else if (g_tN==5) { t5_display_tcb_aux_0(tvp,aux); if (1==aux) t5_display_tcb_aux_1(tvp,aux); else if (2==aux) t5_display_tcb_aux_2(tvp,aux); else if (3==aux) t5_display_tcb_aux_3(tvp,aux); } else if (g_tN==6) { t6_display_tcb_aux_0(tvp,aux); if (1==aux) t6_display_tcb_aux_1(tvp,aux); else if (2==aux) t6_display_tcb_aux_2(tvp,aux); else if (3==aux) t6_display_tcb_aux_3(tvp,aux); else if (4==aux) t6_display_tcb_aux_4(tvp,aux); } } /***:----------------------------------------------------------------------- ***: parse_n_decode_tcb ***:----------------------------------------------------------------------- */ unsigned parse_tcb( _TCBVAR *base_tvp, unsigned char *buf) { /* parse the TCB */ _TCBVAR *tvp=base_tvp; unsigned ulp_type; int aux=1; /* assume TOE or iSCSI */ unsigned tx_max=0, rcv_nxt=0, rx_frag0_start_idx_raw=0; int got_tx_max=0, got_rcv_nxt=0, got_rx_frag0_start_idx_raw=0; /* parse the TCB */ while (tvp->name!=NULL) { get_tcb_field(tvp,buf); if (!got_tx_max && tcb_strmatch_nc("tx_max",tvp->name)) { tx_max=tvp->val; got_tx_max=1; } if (!got_rcv_nxt && tcb_strmatch_nc("rcv_nxt",tvp->name)) { rcv_nxt=tvp->val; got_rcv_nxt=1; } if (!got_rx_frag0_start_idx_raw && tcb_strmatch_nc("rx_frag0_start_idx_raw",tvp->name)) { rx_frag0_start_idx_raw=tvp->val; got_rx_frag0_start_idx_raw=1; } tvp+=1; } tvp=base_tvp; ulp_type=tvp->val; /* ULP type is always first variable in TCB */ if (PM_MODE_IANDP==ulp_type || PM_MODE_FCOE==ulp_type) aux=3; else if (PM_MODE_RDDP==ulp_type) aux=2; else if (6==g_tN && (PM_MODE_TLS==ulp_type || PM_MODE_DTLS==ulp_type)) aux=4; else aux=1; assert(got_tx_max && got_rcv_nxt && got_rx_frag0_start_idx_raw); /* decompress the compressed values */ tvp=base_tvp; while (tvp->name!=NULL) { decompress_val(tvp,ulp_type,tx_max,rcv_nxt,rx_frag0_start_idx_raw); tvp+=1; } return aux; } void parse_scb( _TCBVAR *base_tvp, unsigned char *buf) { /* parse the SCB */ _TCBVAR *tvp=base_tvp; while (tvp->name!=NULL) { if (tcb_strmatch_nc("scb_slush",tvp->name)) { /* the scb_slush field is all of remaining memory */ tvp->rawval=0; tvp->val=0; } else { get_tcb_field(tvp,buf); } tvp+=1; } } void parse_fcb( _TCBVAR *base_tvp, unsigned char *buf) { /* parse the FCB */ _TCBVAR *tvp=base_tvp; while (tvp->name!=NULL) { get_tcb_field(tvp,buf); tvp+=1; } } void display_list_tcb(_TCBVAR *base_tvp,int aux) { _TCBVAR *tvp=base_tvp; while (tvp->name!=NULL) { if (tvp->aux==0 || tvp->aux==aux) { if (tvp->hi-tvp->lo+1<=32) { printf(" %4d:%4d %31s: %10u (0x%1x)",tvp->lo,tvp->hi,tvp->name, (unsigned) tvp->rawval,(unsigned) tvp->rawval); if (COMP_TX_MAX==tvp->comp || COMP_RCV_NXT==tvp->comp) printf(" -> %1u (0x%x)", tvp->val,tvp->val); } else { printf(" %4d:%4d %31s: 0x%1llx",tvp->lo,tvp->hi,tvp->name, tvp->rawval); } printf("\n"); } tvp+=1; } } void display_tcb(_TCBVAR *tvp,unsigned char *buf,int aux) { if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_RAW) { tcb_hexdump(0,buf,128); printf("\n"); } if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_LIST) { display_list_tcb(tvp,aux); } if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_COMP) { display_tcb_compressed(tvp,aux); } } void parse_n_display_tcb(unsigned char *buf) { _TCBVAR *tvp=g_tcb_info; int aux; aux=parse_tcb(tvp,buf); display_tcb(tvp,buf,aux); } void parse_n_display_scb(unsigned char *buf) { _TCBVAR *tvp=g_scb_info; parse_scb(tvp,buf); if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_RAW) { tcb_hexdump(0,buf,128); printf("\n"); } if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_LIST || g_prntstyl==PRNTSTYL_COMP) { display_list_tcb(tvp,0); } } void parse_n_display_fcb(unsigned char *buf) { _TCBVAR *tvp=g_fcb_info; parse_fcb(tvp,buf); if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_RAW) { tcb_hexdump(0,buf,128); printf("\n"); } if (g_prntstyl==PRNTSTYL_VERBOSE || g_prntstyl==PRNTSTYL_LIST || g_prntstyl==PRNTSTYL_COMP) { display_list_tcb(tvp,0); } } void parse_n_display_xcb(unsigned char *buf) { if (g_got_scb) parse_n_display_scb(buf); else if (g_got_fcb) parse_n_display_fcb(buf); else parse_n_display_tcb(buf); } /***:----------------------------------------------------------------------- ***: swizzle_tcb ***:----------------------------------------------------------------------- */ void swizzle_tcb(unsigned char *buf) { int i,j,k; for (i=0, j=128-16 ; i<j ; i+=16, j-=16) { unsigned char temp; for (k=0; k<16; ++k) { temp=buf[i+k]; buf[i+k]=buf[j+k]; buf[j+k]=temp; } } } /***:----------------------------------------------------------------------- ***: END OF WINDOWS FUNCTIONS ***:----------------------------------------------------------------------- */ void set_tidtype(unsigned int tidtype) { if (tidtype == TIDTYPE_SCB) { g_got_scb = 1; } else if (tidtype == TIDTYPE_FCB) { g_got_fcb = 1; } else { g_got_scb = 0; g_got_fcb = 0; } } void set_tcb_info(unsigned int tidtype, unsigned int cardtype) { set_tidtype(tidtype); g_tN = cardtype; if (4 == g_tN) { g_tcb_info = g_tcb_info4; g_scb_info = g_scb_info4; g_fcb_info = g_fcb_info4; } else if (5 == g_tN) { g_tcb_info = g_tcb_info5; g_scb_info = g_scb_info5; g_fcb_info = g_fcb_info5; } else if (6 == g_tN) { g_tcb_info = g_tcb_info6; g_scb_info = g_scb_info6; g_fcb_info = g_fcb_info6; } } void set_print_style(unsigned int prntstyl) { g_prntstyl=prntstyl; }