1: #ifndef lint 2: static char *rcsid = "$Header: gaptelnet.c,v 2.0 85/11/21 07:23:04 jqj Exp $"; 3: #endif 4: 5: /* 6: * XNS User telnet program. 7: */ 8: 9: /* $Log: gaptelnet.c,v $ 10: * Revision 2.0 85/11/21 07:23:04 jqj 11: * 4.3BSD standard release 12: * 13: * Revision 1.3 85/11/20 14:00:08 jqj 14: * added symbolic entries for Gap connection types 15: * 16: * Revision 1.2 85/05/22 09:46:37 jqj 17: * VAX 4.3beta baseline version 18: * 19: * Revision 1.2 85/05/22 09:46:37 jqj 20: * Beta-test GAP telnet 21: * 22: * based on tcp/telnet: 23: * static char *rcsid = "$Header: gaptelnet.c,v 2.0 85/11/21 07:23:04 jqj Exp $"; 24: * static char sccsid[] = "@(#)telnet.c 4.24 (Berkeley) 7/20/83"; 25: */ 26: 27: #include <sys/types.h> 28: #include <sys/socket.h> 29: #include <sys/ioctl.h> 30: 31: #include <netns/ns.h> 32: #include <netns/idp.h> 33: #include <netns/sp.h> /* for spphdr */ 34: #include <netns/spidp.h> 35: 36: #include <stdio.h> 37: #include <ctype.h> 38: #include <errno.h> 39: #include <signal.h> 40: 41: #include <xnscourier/Clearinghouse2.h> 42: #include "GAP3.h" 43: #include "gapcontrols.h" 44: #include <xnscourier/except.h> 45: #include <xnscourier/CH.h> 46: 47: #define strip(x) ((x)&0177) 48: 49: char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 50: char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 51: 52: 53: int connected; 54: CourierConnection *cconn; 55: int net; 56: FILE *logfile; 57: int debug = 0; 58: int crmod = 0; 59: char *prompt; 60: char escape = CTRL(]); 61: char on = 1; 62: 63: char line[200]; 64: int margc; 65: char *margv[20]; 66: 67: jmp_buf toplevel; 68: jmp_buf peerdied; 69: 70: extern int errno; 71: 72: int tn(), quit(), suspend(), bye(), help(); 73: int setescape(), status(), toggle(), setoptions(); 74: int setcrmod(), setdebug(), setlog(); 75: 76: #define HELPINDENT (sizeof ("connect")) 77: 78: struct cmd { 79: char *name; /* command name */ 80: char *help; /* help string */ 81: int (*handler)(); /* routine which executes command */ 82: }; 83: 84: char openhelp[] = "connect to a site"; 85: char closehelp[] = "close current connection"; 86: char quithelp[] = "exit telnet"; 87: char zhelp[] = "suspend telnet"; 88: char debughelp[] = "toggle debugging"; 89: char escapehelp[] = "set escape character"; 90: char statushelp[] = "print status information"; 91: char helphelp[] = "print help information"; 92: char crmodhelp[] = "toggle mapping of received carriage returns"; 93: char loghelp[] = "toggle logging of session"; 94: 95: struct cmd cmdtab[] = { 96: { "open", openhelp, tn }, 97: { "close", closehelp, bye }, 98: { "quit", quithelp, quit }, 99: { "z", zhelp, suspend }, 100: { "escape", escapehelp, setescape }, 101: { "status", statushelp, status }, 102: /* { "crmod", crmodhelp, setcrmod }, */ 103: { "debug", debughelp, setdebug }, 104: { "log", loghelp, setlog }, 105: { "?", helphelp, help }, 106: 0 107: }; 108: 109: struct sockaddr_ns sin; 110: 111: int intr(), deadpeer(); 112: char *control(); 113: struct cmd *getcmd(); 114: 115: struct tchars otc; 116: struct ltchars oltc; 117: struct sgttyb ottyb; 118: 119: char *hostname; 120: char hnamebuf[45]; 121: 122: 123: main(argc, argv) 124: int argc; 125: char *argv[]; 126: { 127: ioctl(0, TIOCGETP, (char *)&ottyb); 128: ioctl(0, TIOCGETC, (char *)&otc); 129: ioctl(0, TIOCGLTC, (char *)&oltc); 130: setbuf(stdin, 0); 131: setbuf(stdout, 0); 132: prompt = argv[0]; 133: if (argc > 1 && !strcmp(argv[1], "-d")) 134: debug = SO_DEBUG, argv++, argc--; 135: if (argc != 1) { 136: if (setjmp(toplevel) != 0) 137: exit(0); 138: tn(argc, argv); 139: } 140: setjmp(toplevel); 141: for (;;) 142: command(1); 143: } 144: 145: tn(argc, argv) 146: int argc; 147: char *argv[]; 148: { 149: register int c; 150: register struct ns_addr *host; 151: extern struct ns_addr *getXNSaddr(); 152: Clearinghouse2_ObjectName hostoname, hdefault; 153: LongCardinal servicetype; 154: 155: if (connected) { 156: printf("?Already connected to %s\n", hostname); 157: return; 158: } 159: if (argc < 2) { 160: strcpy(line, "Connect "); 161: printf("(to) "); 162: gets(&line[strlen(line)]); 163: makeargv(); 164: argc = margc; 165: argv = margv; 166: } 167: if (argc > 3) { 168: printf("usage: %s host-name [service-type]\n", argv[0]); 169: return; 170: } 171: if (argc == 2) servicetype = TTYService_sa; /* default to 1 */ 172: else if (strcmp(argv[2],"sa") == 0) servicetype = TTYService_sa; 173: else if (strncmp(argv[2],"re",2) == 0 || 174: strcmp(argv[2],"exec") == 0) servicetype = TTYService_exec; 175: else if (strcmp(argv[2],"its") == 0) servicetype = TTYService_its; 176: else servicetype = atoi(argv[2]); 177: CH_NameDefault(&hdefault); 178: hostoname = CH_StringToName(argv[1], &hdefault); 179: if ((host = CH_LookupAddrDN(hostoname,0,hnamebuf,sizeof(hnamebuf)))) { 180: sin.sns_family = AF_NS; 181: host->x_port = htons(IDPPORT_COURIER); 182: bcopy(host, (caddr_t)&sin.sns_addr, sizeof(host)); 183: /* hnamebuf is filled in by CH_LookupAddrDN */ 184: hostname = hnamebuf; 185: } else if ((host = getXNSaddr(argv[1]))) { 186: sin.sns_family = AF_NS; 187: bcopy(host, (caddr_t)&sin.sns_addr, sizeof(host)); 188: strcpy(hnamebuf, argv[1]); 189: hostname = hnamebuf; 190: } else { 191: printf("%s: unknown host\n", argv[1]); 192: return; 193: } 194: cconn = CourierOpen(host); 195: if(cconn == NULL) { 196: fprintf(stderr,"Courier connection failed\n"); 197: return; 198: } 199: net = *(int*)cconn; 200: signal(SIGINT, intr); 201: signal(SIGPIPE, deadpeer); 202: printf("Trying...\n"); 203: if (createsession(cconn,servicetype) < 0) 204: return; 205: connected++; 206: call(status, "status", 0); 207: sleep(1); 208: if (setjmp(peerdied) == 0) 209: telnet(net); 210: fprintf(stderr, "\nConnection closed by foreign host.\n"); 211: exit(1); 212: } 213: 214: /* 215: * create a session 216: */ 217: createsession(cconn, servicetype) 218: CourierConnection *cconn; 219: LongCardinal servicetype; 220: { 221: GAP3_SessionParameterObject pobj; 222: GAP3_TransportObject tobjs[2]; 223: GAP3_CommParamObject *cp; 224: struct { 225: Cardinal length; 226: GAP3_TransportObject *sequence; 227: } tobjlist; 228: Authentication1_Credentials creds; 229: Authentication1_Verifier verifier; 230: 231: pobj.designator = oldTtyHost; /* 11 */ 232: pobj.oldTtyHost_case.charLength = seven; 233: pobj.oldTtyHost_case.parity = none; 234: pobj.oldTtyHost_case.stopBits = oneStopBit; 235: pobj.oldTtyHost_case.frameTimeout = 20; 236: /* 237: tobjs[0].designator = rs232c; 238: cp = &tobjs[0].rs232c_case.commParams; 239: cp->accessDetail.designator = directConn; 240: cp->accessDetail.directConn_case.duplex = fullduplex; 241: cp->accessDetail.directConn_case.lineType = asynchronous; 242: cp->accessDetail.directConn_case.lineSpeed = bps300; 243: tobjs[0].rs232c_case.preemptOthers = preemptInactive; 244: tobjs[0].rs232c_case.preemptMe = preemptInactive; 245: tobjs[0].rs232c_case.phoneNumber = ""; 246: tobjs[0].rs232c_case.line.designator = reserveNeeded; 247: tobjs[0].rs232c_case.line.reserveNeeded_case.lineNumber = 1; 248: */ 249: tobjs[0].designator = service; 250: tobjs[0].service_case.id = servicetype; /* 1 == SA */ 251: 252: tobjs[1].designator = teletype; 253: tobjlist.length = 2; 254: tobjlist.sequence = tobjs; 255: MakeSimpleCredsAndVerifier(0, 0, &creds, &verifier); 256: DURING 257: (void) GAP3_Create(cconn, NULL, pobj, tobjlist, 0, creds, verifier); 258: HANDLER { 259: char *msg; 260: switch (Exception.Code) { 261: case GAP3_mediumConnectFailed: 262: msg = "medium connect failed"; 263: break; 264: case GAP3_illegalTransport: 265: msg = "illegal transport type"; 266: break; 267: case GAP3_tooManyGateStreams: 268: case GAP3_serviceTooBusy: 269: msg = "insufficient resources"; 270: break; 271: case GAP3_serviceNotFound: 272: msg = "service type not found"; 273: break; 274: case GAP3_userNotAuthenticated: 275: case GAP3_userNotAuthorized: 276: msg = "authentication problem"; 277: break; 278: case REJECT_ERROR: 279: switch (CourierErrArgs(rejectionDetails,designator)){ 280: case noSuchProgramNumber: 281: msg = "server does not support GAP"; 282: break; 283: case noSuchVersionNumber: 284: msg = "server does not support our GAP version"; 285: break; 286: default: 287: msg = "connection rejected"; 288: } 289: break; 290: case PROTOCOL_VIOLATION: 291: msg = "protocol violation by remote server"; 292: break; 293: default: 294: msg = "some random error"; 295: break; 296: } 297: fprintf(stderr,"Error creating connection, %s\n", 298: msg); 299: return(-1); 300: } END_HANDLER; 301: return(0); 302: } 303: 304: /* 305: * Print status about the connection. 306: */ 307: /*VARARGS*/ 308: status() 309: { 310: if (connected) 311: printf("Connected to %s.\n", hostname); 312: else 313: printf("No connection.\n"); 314: printf("Escape character is '%s'.\n", control(escape)); 315: fflush(stdout); 316: } 317: 318: makeargv() 319: { 320: register char *cp; 321: register char **argp = margv; 322: 323: margc = 0; 324: for (cp = line; *cp;) { 325: while (isspace(*cp)) 326: cp++; 327: if (*cp == '\0') 328: break; 329: *argp++ = cp; 330: margc += 1; 331: while (*cp != '\0' && !isspace(*cp)) 332: cp++; 333: if (*cp == '\0') 334: break; 335: *cp++ = '\0'; 336: } 337: *argp++ = 0; 338: } 339: 340: /*VARARGS*/ 341: suspend() 342: { 343: register int save; 344: 345: save = mode(0); 346: kill(0, SIGTSTP); 347: /* reget parameters in case they were changed */ 348: ioctl(0, TIOCGETP, (char *)&ottyb); 349: ioctl(0, TIOCGETC, (char *)&otc); 350: ioctl(0, TIOCGLTC, (char *)&oltc); 351: (void) mode(save); 352: } 353: 354: /*VARARGS*/ 355: bye() 356: { 357: register char *op; 358: 359: (void) mode(0); 360: if (connected) { 361: sendoobdata(GAPCTLcleanup); 362: setsockopt(net, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &on, 363: sizeof(on)); 364: sppclose(net); 365: printf("Connection closed.\n"); 366: connected = 0; 367: } 368: } 369: 370: /*VARARGS*/ 371: quit() 372: { 373: call(bye, "bye", 0); 374: exit(0); 375: } 376: 377: /* 378: * Toggle debugging 379: */ 380: setdebug(argc, argv) 381: { 382: debug = ~debug; 383: } 384: 385: /* 386: * Toggle logging 387: */ 388: setlog(argc, argv) 389: int argc; 390: char *argv[]; 391: { 392: if (argc > 2) 393: printf("Syntax: %s [filename]\n",argv[0]); 394: else if (logfile != (FILE*) 0) { 395: /* currently logging */ 396: fclose(logfile); 397: printf("Log file closed\n"); 398: logfile = (FILE*) 0; 399: if (argc == 2 && (logfile = fopen(argv[1],"a")) != (FILE*)0) 400: printf("Logging to %s\n",argv[1]); 401: } else { 402: /* not currently logging */ 403: if (argc == 1) 404: printf("Logging already disabled\n"); 405: else if (argc == 2 && 406: (logfile = fopen(argv[1],"a")) != (FILE*)0 ) 407: printf("Logging to %s\n",argv[1]); 408: } 409: } 410: 411: /* 412: * Help command. 413: */ 414: help(argc, argv) 415: int argc; 416: char *argv[]; 417: { 418: register struct cmd *c; 419: 420: if (argc == 1) { 421: printf("Commands may be abbreviated. Commands are:\n\n"); 422: for (c = cmdtab; c->name; c++) 423: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 424: return; 425: } 426: while (--argc > 0) { 427: register char *arg; 428: arg = *++argv; 429: c = getcmd(arg); 430: if (c == (struct cmd *)-1) 431: printf("?Ambiguous help command %s\n", arg); 432: else if (c == (struct cmd *)0) 433: printf("?Invalid help command %s\n", arg); 434: else 435: printf("%s\n", c->help); 436: } 437: } 438: 439: /* 440: * Call routine with argc, argv set from args (terminated by 0). 441: * VARARGS2 442: */ 443: call(routine, args) 444: int (*routine)(); 445: int args; 446: { 447: register int *argp; 448: register int argc; 449: 450: for (argc = 0, argp = &args; *argp++ != 0; argc++) 451: ; 452: (*routine)(argc, &args); 453: } 454: 455: struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 456: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 457: 458: mode(f) 459: register int f; 460: { 461: static int prevmode = 0; 462: struct tchars *tc; 463: struct ltchars *ltc; 464: struct sgttyb sb; 465: int onoff, old; 466: 467: if (prevmode == f) 468: return (f); 469: old = prevmode; 470: prevmode = f; 471: sb = ottyb; 472: switch (f) { 473: 474: case 0: 475: onoff = 0; 476: tc = &otc; 477: ltc = &oltc; 478: break; 479: 480: case 1: 481: case 2: 482: sb.sg_flags |= CBREAK; 483: if (f == 1) 484: sb.sg_flags &= ~(ECHO|CRMOD); 485: else 486: sb.sg_flags |= ECHO|CRMOD; 487: sb.sg_erase = sb.sg_kill = -1; 488: tc = ¬c; 489: ltc = &noltc; 490: onoff = 1; 491: break; 492: 493: default: 494: return; 495: } 496: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 497: ioctl(fileno(stdin), TIOCSETC, (char *)tc); 498: ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 499: ioctl(fileno(stdin), FIONBIO, &onoff); 500: ioctl(fileno(stdout), FIONBIO, &onoff); 501: return (old); 502: } 503: 504: struct {struct sphdr hdr; 505: char data[BUFSIZ]; 506: } sibuf; 507: char *sbp; 508: char tibuf[BUFSIZ], *tbp; 509: int scc, tcc; 510: 511: /* 512: * Select from tty and network... 513: */ 514: telnet(s) 515: int s; 516: { 517: register int c; 518: int tin = fileno(stdin), tout = fileno(stdout); 519: int on = 1; 520: int ibits, obits; 521: 522: (void) mode(1); 523: ioctl(s, FIONBIO, &on); 524: changeSPPopts(net, GAPCTLnone, 1); /* datastream "normal", eom */ 525: for (;;) { 526: ibits = obits = 0; 527: if (nfrontp - nbackp) 528: obits |= (1 << s); 529: else 530: ibits |= (1 << tin); 531: if (tfrontp - tbackp) 532: obits |= (1 << tout); 533: else 534: ibits |= (1 << s); 535: if (scc < 0 && tcc < 0) 536: break; 537: select(16, &ibits, &obits, 0, 0); 538: if (ibits == 0 && obits == 0) { 539: sleep(5); 540: continue; 541: } 542: 543: /* 544: * Something to read from the network... 545: */ 546: if (ibits & (1 << s)) { 547: scc = read(s, &sibuf, sizeof (sibuf)) 548: - sizeof(struct sphdr); 549: #ifdef DEBUG 550: if (debug) 551: printf("reading %d bytes from net\n", scc); 552: #endif 553: if (scc < 0 && errno == EWOULDBLOCK) 554: scc = 0; 555: else if (scc < 0) 556: break; /* protocol violation? */ 557: else if (sibuf.hdr.sp_cc & SP_OB) { 558: /* status or OOB control */ 559: switch ((u_char) *sibuf.data) { 560: case GAPCTLareYouThere: 561: sendoobdata(GAPCTLiAmHere); 562: break; 563: case GAPCTLmediumDown: 564: (void) mode(0); 565: longjmp(peerdied, -1); 566: /*NOTREACHED*/ 567: default: 568: /* ignore others */ 569: break; 570: } 571: scc = 0; 572: } 573: else if (sibuf.hdr.sp_dt == GAPCTLnone) { 574: /* normal case */ 575: sbp = sibuf.data; 576: } 577: else if(sibuf.hdr.sp_dt == GAPCTLcleanup){ 578: sendoobdata(GAPCTLcleanup); 579: /* should get an END next */ 580: scc = 0; 581: } 582: else if(sibuf.hdr.sp_dt == SPPSST_END) { 583: setsockopt(net, NSPROTO_SPP, 584: SO_HEADERS_ON_OUTPUT, 585: &on, sizeof(on)); 586: sppclosereply(net); 587: (void) mode(0); 588: longjmp(peerdied, -1); 589: /*NOTREACHED*/ 590: } 591: } 592: 593: /* 594: * Something to read from the tty... 595: */ 596: if (ibits & (1 << tin)) { 597: tcc = read(tin, tibuf, sizeof (tibuf)); 598: if (tcc < 0 && errno == EWOULDBLOCK) 599: tcc = 0; 600: else { 601: if (tcc <= 0) 602: break; 603: tbp = tibuf; 604: } 605: } 606: 607: while (tcc > 0) { 608: register int c; 609: 610: if ((&netobuf[BUFSIZ] - nfrontp) < 2) 611: break; 612: c = *tbp++ & 0377, tcc--; 613: if (strip(c) == escape) { 614: command(0); 615: tcc = 0; 616: break; 617: } 618: switch (c) { 619: case '\n': 620: /* *nfrontp++ = '\r'; */ 621: *nfrontp++ = '\n'; 622: break; 623: case '\r': 624: *nfrontp++ = '\r'; 625: /* *nfrontp++ = '\n'; */ 626: break; 627: default: 628: *nfrontp++ = c; 629: break; 630: } 631: } 632: if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 633: netflush(s); 634: while (scc > 0) { 635: register int c; 636: c = *sbp++&0377; scc--; 637: *tfrontp++ = c; 638: } 639: if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 640: ttyflush(tout); 641: } 642: (void) mode(0); 643: } 644: 645: command(top) 646: int top; 647: { 648: register struct cmd *c; 649: int oldmode, wasopen; 650: 651: oldmode = mode(0); 652: if (!top) 653: putchar('\n'); 654: else 655: signal(SIGINT, SIG_DFL); 656: for (;;) { 657: printf("%s> ", prompt); 658: if (gets(line) == 0) { 659: if (feof(stdin)) { 660: clearerr(stdin); 661: putchar('\n'); 662: } 663: break; 664: } 665: if (line[0] == 0) 666: break; 667: makeargv(); 668: c = getcmd(margv[0]); 669: if (c == (struct cmd *)-1) { 670: printf("?Ambiguous command\n"); 671: continue; 672: } 673: if (c == 0) { 674: printf("?Invalid command\n"); 675: continue; 676: } 677: (*c->handler)(margc, margv); 678: if (c->handler != help) 679: break; 680: } 681: if (!top) { 682: if (!connected) 683: longjmp(toplevel, 1); 684: (void) mode(oldmode); 685: } 686: } 687: 688: /* 689: * Set the escape character. 690: */ 691: setescape(argc, argv) 692: int argc; 693: char *argv[]; 694: { 695: register char *arg; 696: char buf[50]; 697: 698: if (argc > 2) 699: arg = argv[1]; 700: else { 701: printf("new escape character: "); 702: gets(buf); 703: arg = buf; 704: } 705: if (arg[0] != '\0') 706: escape = arg[0]; 707: printf("Escape character is '%s'.\n", control(escape)); 708: fflush(stdout); 709: } 710: 711: /* 712: * Construct a control character sequence 713: * for a special character. 714: */ 715: char * 716: control(c) 717: register int c; 718: { 719: static char buf[3]; 720: 721: if (c == 0177) 722: return ("^?"); 723: if (c >= 040) { 724: buf[0] = c; 725: buf[1] = 0; 726: } else { 727: buf[0] = '^'; 728: buf[1] = '@'+c; 729: buf[2] = 0; 730: } 731: return (buf); 732: } 733: 734: struct cmd * 735: getcmd(name) 736: register char *name; 737: { 738: register char *p, *q; 739: register struct cmd *c, *found; 740: register int nmatches, longest; 741: 742: longest = 0; 743: nmatches = 0; 744: found = 0; 745: for (c = cmdtab; p = c->name; c++) { 746: for (q = name; *q == *p++; q++) 747: if (*q == 0) /* exact match? */ 748: return (c); 749: if (!*q) { /* the name was a prefix */ 750: if (q - name > longest) { 751: longest = q - name; 752: nmatches = 1; 753: found = c; 754: } else if (q - name == longest) 755: nmatches++; 756: } 757: } 758: if (nmatches > 1) 759: return ((struct cmd *)-1); 760: return (found); 761: } 762: 763: deadpeer() 764: { 765: (void) mode(0); 766: longjmp(peerdied, -1); 767: } 768: 769: intr() 770: { 771: (void) mode(0); 772: longjmp(toplevel, -1); 773: } 774: 775: ttyflush(fd) 776: { 777: register int n; 778: 779: if ((n = tfrontp - tbackp) > 0) { 780: if (logfile != (FILE*)0) 781: fwrite(tbackp, 1, n, logfile); 782: n = write(fd, tbackp, n); 783: } 784: if (n < 0) 785: return; 786: tbackp += n; 787: if (tbackp == tfrontp) 788: tbackp = tfrontp = ttyobuf; 789: } 790: 791: netflush(fd) 792: { 793: int n; 794: 795: if ((n = nfrontp - nbackp) > 0) 796: n = write(fd, nbackp, n); 797: #ifdef DEBUG 798: if (debug) 799: printf("writing %d of %d bytes to net\n", n, nfrontp-nbackp); 800: #endif 801: if (n < 0) { 802: if (errno != ENOBUFS && errno != EWOULDBLOCK) { 803: (void) mode(0); 804: perror(hostname); 805: close(fd); 806: longjmp(peerdied, -1); 807: /*NOTREACHED*/ 808: } 809: n = 0; 810: } 811: nbackp += n; 812: if (nbackp == nfrontp) 813: nbackp = nfrontp = netobuf; 814: } 815: 816: /* 817: * Send out of band data to other end of network 818: */ 819: sendoobdata(value) 820: char value; 821: { 822: send(net, &value, 1, MSG_OOB); 823: } 824: 825: changeSPPopts(s, stream, eom) 826: int s; /* SPP socket */ 827: u_char stream; /* datastream type */ 828: char eom; /* Boolean EOM */ 829: { 830: struct sphdr sphdr; 831: int off = 0; 832: 833: sphdr.sp_dt = stream; 834: sphdr.sp_cc = (eom ? SP_EM : 0); 835: setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &off, sizeof(off)); 836: setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, &sphdr, sizeof(sphdr)); 837: }