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 39 extern _TCBVAR g_tcb_info4[]; 40 extern _TCBVAR g_scb_info4[]; 41 extern _TCBVAR g_fcb_info4[]; 42 extern void t4_display_tcb_aux_0(_TCBVAR *tvp,int aux); 43 extern void t4_display_tcb_aux_1(_TCBVAR *tvp,int aux); 44 extern void t4_display_tcb_aux_2(_TCBVAR *tvp,int aux); 45 extern void t4_display_tcb_aux_3(_TCBVAR *tvp,int aux); 46 47 extern _TCBVAR g_tcb_info5[]; 48 extern _TCBVAR g_scb_info5[]; 49 extern _TCBVAR g_fcb_info5[]; 50 extern void t5_display_tcb_aux_0(_TCBVAR *tvp,int aux); 51 extern void t5_display_tcb_aux_1(_TCBVAR *tvp,int aux); 52 extern void t5_display_tcb_aux_2(_TCBVAR *tvp,int aux); 53 extern void t5_display_tcb_aux_3(_TCBVAR *tvp,int aux); 54 55 extern _TCBVAR g_tcb_info6[]; 56 extern _TCBVAR g_scb_info6[]; 57 extern _TCBVAR g_fcb_info6[]; 58 extern void t6_display_tcb_aux_0(_TCBVAR *tvp,int aux); 59 extern void t6_display_tcb_aux_1(_TCBVAR *tvp,int aux); 60 extern void t6_display_tcb_aux_2(_TCBVAR *tvp,int aux); 61 extern void t6_display_tcb_aux_3(_TCBVAR *tvp,int aux); 62 extern 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; 72 static int g_tN=0; 73 74 static int g_prntstyl=PRNTSTYL_COMP; 75 76 static int g_got_scb=0; 77 static int g_got_fcb=0; 78 79 80 /***:----------------------------------------------------------------------- 81 ***: error exit functions 82 ***:----------------------------------------------------------------------- 83 */ 84 85 /**: err_exit functions 86 *: ------------------ 87 */ 88 89 void tcb_prflush(void) 90 { 91 fflush(stdout); 92 fflush(stderr); 93 } 94 95 96 void 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 113 void 114 tcb_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 125 int 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 /*: ------------------------------------------------------------------------- 133 string functions 134 tcb_strmatch_nc: Similar to exact match, but case insensitive. 135 */ 136 137 138 int 139 tcb_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 156 int 157 tcb_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 176 static int g_PR_indent=1; 177 178 void 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 * 201 lu_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 214 unsigned 215 val(char *name) 216 { 217 _TCBVAR *tvp; 218 219 tvp=lu_tcbvar(name); 220 return tvp->val; 221 } 222 223 ui64 224 val64(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 240 static int 241 get_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 253 static ui64 254 get_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 273 void 274 decompress_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 322 void 323 get_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 341 char * 342 spr_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 366 char * 367 spr_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 381 char * 382 spr_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 404 char * 405 spr_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 422 void 423 display_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 455 unsigned 456 parse_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 505 void 506 parse_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 523 void 524 parse_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 535 void 536 display_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 556 void 557 display_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 577 void 578 parse_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 587 void 588 parse_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 605 void 606 parse_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 624 void 625 parse_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 637 void 638 swizzle_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 658 void 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 676 void 677 set_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 699 void 700 set_print_style(unsigned int prntstyl) 701 { 702 g_prntstyl=prntstyl; 703 } 704