1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2018 Chelsio Communications, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include "tcb_common.h"
33
34/***:-----------------------------------------------------------------------
35 ***: externals
36 ***:-----------------------------------------------------------------------
37 */
38
39extern _TCBVAR g_tcb_info4[];
40extern _TCBVAR g_scb_info4[];
41extern _TCBVAR g_fcb_info4[];
42extern void t4_display_tcb_aux_0(_TCBVAR *tvp,int aux);
43extern void t4_display_tcb_aux_1(_TCBVAR *tvp,int aux);
44extern void t4_display_tcb_aux_2(_TCBVAR *tvp,int aux);
45extern void t4_display_tcb_aux_3(_TCBVAR *tvp,int aux);
46
47extern _TCBVAR g_tcb_info5[];
48extern _TCBVAR g_scb_info5[];
49extern _TCBVAR g_fcb_info5[];
50extern void t5_display_tcb_aux_0(_TCBVAR *tvp,int aux);
51extern void t5_display_tcb_aux_1(_TCBVAR *tvp,int aux);
52extern void t5_display_tcb_aux_2(_TCBVAR *tvp,int aux);
53extern void t5_display_tcb_aux_3(_TCBVAR *tvp,int aux);
54
55extern _TCBVAR g_tcb_info6[];
56extern _TCBVAR g_scb_info6[];
57extern _TCBVAR g_fcb_info6[];
58extern void t6_display_tcb_aux_0(_TCBVAR *tvp,int aux);
59extern void t6_display_tcb_aux_1(_TCBVAR *tvp,int aux);
60extern void t6_display_tcb_aux_2(_TCBVAR *tvp,int aux);
61extern void t6_display_tcb_aux_3(_TCBVAR *tvp,int aux);
62extern void t6_display_tcb_aux_4(_TCBVAR *tvp,int aux);
63
64/***:-----------------------------------------------------------------------
65 ***: globals
66 ***:-----------------------------------------------------------------------
67 */
68
69_TCBVAR *g_tcb_info=g_tcb_info5;
70_TCBVAR *g_scb_info=g_scb_info5;
71_TCBVAR *g_fcb_info=g_fcb_info5;
72static int g_tN=0;
73
74static int g_prntstyl=PRNTSTYL_COMP;
75
76static int g_got_scb=0;
77static int g_got_fcb=0;
78
79
80/***:-----------------------------------------------------------------------
81***: error exit functions
82***:-----------------------------------------------------------------------
83*/
84
85/**: err_exit functions
86*:  ------------------
87*/
88
89void tcb_prflush(void)
90{
91    fflush(stdout);
92    fflush(stderr);
93}
94
95
96void tcb_code_err_exit(char *fmt, ...)
97{
98  va_list args;
99  va_start(args, fmt);
100  printf("Coding Error in: ");
101  vprintf(fmt, args);
102  printf("\n");
103  tcb_prflush();
104  va_end(args);
105  exit(1);
106}
107
108/***:-----------------------------------------------------------------------
109***: tcb_hexdump functions
110***:-----------------------------------------------------------------------
111*/
112
113void
114tcb_hexdump(unsigned base, unsigned char *buf, unsigned int size)
115{
116    unsigned offset;
117
118    for (offset = 0; offset < size; ++offset) {
119        if (!(offset % 16)) printf("\n0x%4.4x: ", base + offset);
120        else if (!(offset % 8)) printf(" ");
121        printf("%2.2x ", (unsigned char)buf[offset]);
122    }
123}
124
125int tcb_strmatch_nc(char *cs, char *ct) {
126    while (*cs)
127        if (tolower(*cs++) != tolower(*ct++)) return (FALSE);
128    return (!(*ct));  /*return TRUE if *ct NULL at same time as *cs==NULL*/
129}
130
131
132/*: -------------------------------------------------------------------------
133string functions
134tcb_strmatch_nc:     Similar to exact match, but case insensitive.
135*/
136
137
138int
139tcb_strncmp_nc(char *cs, char *ct, int n)
140{
141    /*case insensitive version of the standard strncmp() function */
142    int i = 0;
143    int ret;
144
145
146    ret = 0;
147    for (i = 0; i < n && 0 == ret && !(EOS == *cs && EOS == *ct); ++i) {
148        /* this is weird, but it matched GCC linux when strings don't
149        * have any upper case characters.
150        */
151        ret = tolower(*cs++) - tolower(*ct++);
152    }
153    return ret;
154}
155
156int
157tcb_startswith_nc(char *cs, char *ct)
158{ /* return true if cs start with ct */
159    return (0 == tcb_strncmp_nc(cs, ct, (int)strlen(ct)));
160}
161
162
163
164
165/***:-----------------------------------------------------------------------
166 ***: START OF WINDOWS FUNCTIONS
167 ***:-----------------------------------------------------------------------
168 */
169
170
171/***:-----------------------------------------------------------------------
172 ***: print utilities
173 ***:-----------------------------------------------------------------------
174 */
175
176static int g_PR_indent=1;
177
178void PR(char *fmt, ...)
179{
180  int fmt_len;
181  va_list args;
182  va_start(args,fmt);
183
184  if (g_PR_indent) printf("  ");
185  g_PR_indent=0;
186  fmt_len=(int) strlen(fmt);
187  if (fmt_len>0 && fmt[fmt_len-1]=='\n') g_PR_indent=1;
188
189  vprintf(fmt,args);
190  tcb_prflush();
191  va_end(args);
192}
193
194
195/***:-----------------------------------------------------------------------
196 ***: val()
197 ***:-----------------------------------------------------------------------
198 */
199
200_TCBVAR *
201lu_tcbvar(char *name)
202{
203  _TCBVAR *tvp=g_tcb_info;
204
205  while (tvp->name!=NULL) {
206    if      (tcb_strmatch_nc(name,tvp->name)) return tvp;
207    else if (tcb_strmatch_nc(name,tvp->aka )) return tvp;
208    tvp+=1;
209  }
210  tcb_code_err_exit("lu_tcbvar: bad name %s\n",name);
211  return NULL;
212}
213
214unsigned
215val(char *name)
216{
217  _TCBVAR *tvp;
218
219  tvp=lu_tcbvar(name);
220  return tvp->val;
221}
222
223ui64
224val64(char *name)
225{
226  _TCBVAR *tvp;
227
228  tvp=lu_tcbvar(name);
229  return tvp->rawval;
230}
231
232
233
234/***:-----------------------------------------------------------------------
235 ***: get_tcb_bits
236 ***:-----------------------------------------------------------------------
237 */
238
239
240static int
241get_tcb_bit(unsigned char *A, int bit)
242{
243  int ret=0;
244  int ix,shift;
245
246  ix = 127 - (bit>>3);
247  shift=bit&0x7;
248  /*  prdbg("  ix: %u, shift=%u\n",ix,shift); */
249  ret=(A[ix] >> shift) & 1;
250  return ret;
251}
252
253static ui64
254get_tcb_bits (unsigned char  *A, int hi, int lo)
255{
256  ui64 ret=0;
257
258  if (lo>hi) {
259    int temp=lo;
260    lo=hi;
261    hi=temp;
262  }
263
264  while (hi>=lo) {
265    ret = (ret<<1) | get_tcb_bit(A,hi);
266    --hi;
267  }
268
269  return ret;
270}
271
272
273void
274decompress_val(_TCBVAR *tvp,unsigned ulp_type,unsigned tx_max,
275	       unsigned rcv_nxt,unsigned rx_frag0_start_idx_raw)
276{
277  unsigned rawval=(unsigned) tvp->rawval;
278
279  switch(tvp->comp) {
280  case COMP_NONE: tvp->val=rawval;  break;
281  case COMP_ULP:  tvp->val=rawval;  break;
282  case COMP_TX_MAX:
283    tvp->val=(tx_max - rawval) & 0xFFFFFFFF;
284    break;
285  case COMP_RCV_NXT:
286    if (tcb_startswith_nc(tvp->name,"rx_frag")) {
287      unsigned fragx=0;
288      if (!tcb_strmatch_nc(tvp->name,"rx_frag0_start_idx_raw"))
289	fragx=rawval;
290      tvp->val=(rcv_nxt+rx_frag0_start_idx_raw+fragx) & 0xFFFFFFFF;
291    } else {
292      tvp->val=(rcv_nxt - rawval) & 0xFFFFFFFF;
293    }
294    break;
295  case COMP_PTR: tvp->val=rawval;  break;
296  case COMP_LEN:
297    {
298      tvp->val=rawval;
299      if (PM_MODE_RDDP==ulp_type ||  PM_MODE_DDP==ulp_type ||
300	  PM_MODE_IANDP==ulp_type) {
301	/* TP does this internally.  Not sure if I should show the
302	 *  unaltered value or the raw value.  For now I
303	 *  will diplay the raw value.  For now I've added the code
304	 *  mainly to stop windows compiler from warning about ulp_type
305	 *  being an unreferenced parameter.
306	 */
307	tvp->val=0;
308	tvp->val=rawval;  /* comment this out to display altered value */
309      }
310    }
311    break;
312  default:
313    tcb_code_err_exit("decompress_val, bad switch: %d",tvp->comp);
314    break;
315  }
316
317
318
319}
320
321
322void
323get_tcb_field(_TCBVAR *tvp,unsigned char *buf)
324{
325  assert(tvp->hi-tvp->lo+1<=64);
326  assert(tvp->hi>=tvp->lo);
327
328  tvp->rawval=get_tcb_bits(buf,tvp->lo,tvp->hi);
329  /* assume no compression and 32-bit value for now */
330  tvp->val=(unsigned) (tvp->rawval & 0xFFFFFFFF);
331
332
333}
334
335
336/***:-----------------------------------------------------------------------
337 ***: spr_* functions
338 ***:-----------------------------------------------------------------------
339 */
340
341char *
342spr_tcp_state (unsigned state)
343{
344  char *ret="UNKNOWN";
345
346  if      ( 0 == state) {ret = "CLOSED";}
347  else if ( 1 == state) {ret = "LISTEN";}
348  else if ( 2 == state) {ret = "SYN_SENT";}
349  else if ( 3 == state) {ret = "SYN_RCVD";}
350  else if ( 4 == state) {ret = "ESTABLISHED";}
351  else if ( 5 == state) {ret = "CLOSE_WAIT";}
352  else if ( 6 == state) {ret = "FIN_WAIT_1";}
353  else if ( 7 == state) {ret = "CLOSING";}
354  else if ( 8 == state) {ret = "LAST_ACK";}
355  else if ( 9 == state) {ret = "FIN_WAIT_2";}
356  else if (10 == state) {ret = "TIME_WAIT";}
357  else if (11 == state) {ret = "ESTABLISHED_RX";}
358  else if (12 == state) {ret = "ESTABLISHED_TX";}
359  else if (13 == state) {ret = "SYN_PEND";}
360  else if (14 == state) {ret = "ESC_1_STATE";}
361  else if (15 == state) {ret = "ESC_2_STATE";}
362
363  return ret;
364}
365
366char *
367spr_cctrl_sel(unsigned sel0,unsigned sel1)
368{
369  unsigned sel=(sel1<<1) | sel0;
370  char *ret="UNKNOWN";
371
372  if      ( 0 == sel) {ret = "Reno";}
373  else if ( 1 == sel) {ret = "Tahoe";}
374  else if ( 2 == sel) {ret = "NewReno";}
375  else if ( 3 == sel) {ret = "HighSpeed";}
376
377  return ret;
378}
379
380
381char *
382spr_ulp_type(unsigned ulp_type)
383{
384  char *ret="UNKNOWN";
385
386  /*The tp.h PM_MODE_XXX call 1 DDP and 5 IANDP, but external
387   * documentation (tcb.h" calls 5 ddp, and doesn't mention 1 or 3.
388   */
389
390  if      ( PM_MODE_PASS  == ulp_type) {ret = "TOE";}
391  else if ( PM_MODE_DDP   == ulp_type) {ret = "DDP";}
392  else if ( PM_MODE_ISCSI == ulp_type) {ret = "ISCSI";}
393  else if ( PM_MODE_IWARP == ulp_type) {ret = "IWARP";}
394  else if ( PM_MODE_RDDP  == ulp_type) {ret = "RDMA";}
395  else if ( PM_MODE_IANDP == ulp_type) {ret = "IANDP_DDP";}
396  else if ( PM_MODE_FCOE  == ulp_type) {ret = "FCoE";}
397  else if ( PM_MODE_USER  == ulp_type) {ret = "USER";}
398  else if ( PM_MODE_TLS   == ulp_type) {ret = "TLS";}
399  else if ( PM_MODE_DTLS  == ulp_type) {ret = "DTLS";}
400
401  return ret;
402}
403
404char *
405spr_ip_version(unsigned ip_version)
406{
407  char *ret="UNKNOWN";
408
409  if      ( 0 == ip_version) {ret = "IPv4";}
410  else if ( 1 == ip_version) {ret = "IPv6";}
411
412  return ret;
413}
414
415
416
417/***:-----------------------------------------------------------------------
418 ***: display_tcb()
419 ***:-----------------------------------------------------------------------
420 */
421
422void
423display_tcb_compressed(_TCBVAR *tvp,int aux)
424{
425
426  if (g_tN==4) {
427    t4_display_tcb_aux_0(tvp,aux);
428    if      (1==aux) t4_display_tcb_aux_1(tvp,aux);
429    else if (2==aux) t4_display_tcb_aux_2(tvp,aux);
430    else if (3==aux) t4_display_tcb_aux_3(tvp,aux);
431
432  } else if (g_tN==5) {
433    t5_display_tcb_aux_0(tvp,aux);
434    if      (1==aux) t5_display_tcb_aux_1(tvp,aux);
435    else if (2==aux) t5_display_tcb_aux_2(tvp,aux);
436    else if (3==aux) t5_display_tcb_aux_3(tvp,aux);
437  } else if (g_tN==6) {
438    t6_display_tcb_aux_0(tvp,aux);
439    if      (1==aux) t6_display_tcb_aux_1(tvp,aux);
440    else if (2==aux) t6_display_tcb_aux_2(tvp,aux);
441    else if (3==aux) t6_display_tcb_aux_3(tvp,aux);
442    else if (4==aux) t6_display_tcb_aux_4(tvp,aux);
443  }
444}
445
446
447
448
449/***:-----------------------------------------------------------------------
450 ***: parse_n_decode_tcb
451 ***:-----------------------------------------------------------------------
452 */
453
454
455unsigned
456parse_tcb( _TCBVAR *base_tvp, unsigned char *buf)
457{   /* parse the TCB */
458  _TCBVAR *tvp=base_tvp;
459  unsigned ulp_type;
460  int aux=1;  /* assume TOE or iSCSI */
461  unsigned tx_max=0, rcv_nxt=0, rx_frag0_start_idx_raw=0;
462  int got_tx_max=0, got_rcv_nxt=0, got_rx_frag0_start_idx_raw=0;
463
464
465  /* parse the TCB */
466  while (tvp->name!=NULL) {
467    get_tcb_field(tvp,buf);
468    if (!got_tx_max && tcb_strmatch_nc("tx_max",tvp->name)) {
469      tx_max=tvp->val;
470      got_tx_max=1;
471    }
472    if (!got_rcv_nxt && tcb_strmatch_nc("rcv_nxt",tvp->name)) {
473      rcv_nxt=tvp->val;
474      got_rcv_nxt=1;
475    }
476    if (!got_rx_frag0_start_idx_raw &&
477	tcb_strmatch_nc("rx_frag0_start_idx_raw",tvp->name)) {
478      rx_frag0_start_idx_raw=tvp->val;
479      got_rx_frag0_start_idx_raw=1;
480    }
481    tvp+=1;
482  }
483
484  tvp=base_tvp;
485  ulp_type=tvp->val;  /* ULP type is always first variable in TCB */
486  if (PM_MODE_IANDP==ulp_type || PM_MODE_FCOE==ulp_type) aux=3;
487  else if (PM_MODE_RDDP==ulp_type) aux=2;
488  else if (6==g_tN && (PM_MODE_TLS==ulp_type || PM_MODE_DTLS==ulp_type)) aux=4;
489  else aux=1;
490
491  assert(got_tx_max && got_rcv_nxt && got_rx_frag0_start_idx_raw);
492
493  /* decompress the compressed values */
494  tvp=base_tvp;
495  while (tvp->name!=NULL) {
496    decompress_val(tvp,ulp_type,tx_max,rcv_nxt,rx_frag0_start_idx_raw);
497    tvp+=1;
498  }
499
500  return aux;
501}
502
503
504
505void
506parse_scb( _TCBVAR *base_tvp, unsigned char *buf)
507{   /* parse the SCB */
508  _TCBVAR *tvp=base_tvp;
509
510  while (tvp->name!=NULL) {
511    if (tcb_strmatch_nc("scb_slush",tvp->name)) {
512      /* the scb_slush field is all of remaining memory */
513      tvp->rawval=0;
514      tvp->val=0;
515    } else {
516      get_tcb_field(tvp,buf);
517    }
518    tvp+=1;
519  }
520}
521
522
523void
524parse_fcb( _TCBVAR *base_tvp, unsigned char *buf)
525{   /* parse the FCB */
526  _TCBVAR *tvp=base_tvp;
527
528  while (tvp->name!=NULL) {
529    get_tcb_field(tvp,buf);
530    tvp+=1;
531  }
532}
533
534
535void
536display_list_tcb(_TCBVAR *base_tvp,int aux)
537{
538  _TCBVAR *tvp=base_tvp;
539  while (tvp->name!=NULL) {
540    if (tvp->aux==0 || tvp->aux==aux) {
541      if (tvp->hi-tvp->lo+1<=32) {
542	printf("  %4d:%4d %31s: %10u (0x%1x)",tvp->lo,tvp->hi,tvp->name,
543	       (unsigned) tvp->rawval,(unsigned) tvp->rawval);
544	if (COMP_TX_MAX==tvp->comp || COMP_RCV_NXT==tvp->comp)
545	  printf("  -> %1u (0x%x)", tvp->val,tvp->val);
546      } else {
547	printf("  %4d:%4d %31s: 0x%1llx",tvp->lo,tvp->hi,tvp->name,
548	       tvp->rawval);
549      }
550      printf("\n");
551    }
552    tvp+=1;
553  }
554}
555
556void
557display_tcb(_TCBVAR *tvp,unsigned char *buf,int aux)
558{
559  if (g_prntstyl==PRNTSTYL_VERBOSE ||
560      g_prntstyl==PRNTSTYL_RAW) {
561    tcb_hexdump(0,buf,128);
562    printf("\n");
563  }
564
565  if (g_prntstyl==PRNTSTYL_VERBOSE ||
566      g_prntstyl==PRNTSTYL_LIST) {
567    display_list_tcb(tvp,aux);
568  }
569
570  if (g_prntstyl==PRNTSTYL_VERBOSE ||
571      g_prntstyl==PRNTSTYL_COMP) {
572    display_tcb_compressed(tvp,aux);
573  }
574
575}
576
577void
578parse_n_display_tcb(unsigned char *buf)
579{
580  _TCBVAR *tvp=g_tcb_info;
581  int aux;
582
583  aux=parse_tcb(tvp,buf);
584  display_tcb(tvp,buf,aux);
585}
586
587void
588parse_n_display_scb(unsigned char *buf)
589{
590  _TCBVAR *tvp=g_scb_info;
591
592  parse_scb(tvp,buf);
593  if (g_prntstyl==PRNTSTYL_VERBOSE ||
594      g_prntstyl==PRNTSTYL_RAW) {
595    tcb_hexdump(0,buf,128);
596    printf("\n");
597  }
598  if (g_prntstyl==PRNTSTYL_VERBOSE ||
599      g_prntstyl==PRNTSTYL_LIST ||
600      g_prntstyl==PRNTSTYL_COMP) {
601    display_list_tcb(tvp,0);
602  }
603}
604
605void
606parse_n_display_fcb(unsigned char *buf)
607{
608  _TCBVAR *tvp=g_fcb_info;
609
610  parse_fcb(tvp,buf);
611  if (g_prntstyl==PRNTSTYL_VERBOSE ||
612      g_prntstyl==PRNTSTYL_RAW) {
613    tcb_hexdump(0,buf,128);
614    printf("\n");
615  }
616
617  if (g_prntstyl==PRNTSTYL_VERBOSE ||
618      g_prntstyl==PRNTSTYL_LIST ||
619      g_prntstyl==PRNTSTYL_COMP) {
620    display_list_tcb(tvp,0);
621  }
622}
623
624void
625parse_n_display_xcb(unsigned char *buf)
626{
627  if      (g_got_scb) parse_n_display_scb(buf);
628  else if (g_got_fcb) parse_n_display_fcb(buf);
629  else                parse_n_display_tcb(buf);
630}
631
632/***:-----------------------------------------------------------------------
633 ***: swizzle_tcb
634 ***:-----------------------------------------------------------------------
635 */
636
637void
638swizzle_tcb(unsigned char *buf)
639{
640  int i,j,k;
641
642  for (i=0, j=128-16 ; i<j ; i+=16, j-=16) {
643    unsigned char temp;
644    for (k=0; k<16; ++k) {
645      temp=buf[i+k];
646      buf[i+k]=buf[j+k];
647      buf[j+k]=temp;
648    }
649  }
650}
651
652
653/***:-----------------------------------------------------------------------
654 ***: END OF WINDOWS FUNCTIONS
655 ***:-----------------------------------------------------------------------
656 */
657
658void set_tidtype(unsigned int tidtype)
659{
660    if (tidtype == TIDTYPE_SCB)
661    {
662        g_got_scb = 1;
663    }
664    else if (tidtype == TIDTYPE_FCB)
665    {
666        g_got_fcb = 1;
667    }
668    else
669    {
670        g_got_scb = 0;
671        g_got_fcb = 0;
672    }
673
674}
675
676void
677set_tcb_info(unsigned int tidtype, unsigned int cardtype)
678{
679    set_tidtype(tidtype);
680
681    g_tN = cardtype;
682    if (4 == g_tN) {
683        g_tcb_info = g_tcb_info4;
684        g_scb_info = g_scb_info4;
685        g_fcb_info = g_fcb_info4;
686    }
687    else if (5 == g_tN) {
688        g_tcb_info = g_tcb_info5;
689        g_scb_info = g_scb_info5;
690        g_fcb_info = g_fcb_info5;
691    }
692    else if (6 == g_tN) {
693        g_tcb_info = g_tcb_info6;
694        g_scb_info = g_scb_info6;
695        g_fcb_info = g_fcb_info6;
696    }
697}
698
699void
700set_print_style(unsigned int prntstyl)
701{
702  g_prntstyl=prntstyl;
703}
704