Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!uunet!ncrlnk!ncr-sd!tw-rnd!jml From: jml@tw-rnd.SanDiego.NCR.COM (Michael Lodman) Newsgroups: comp.unix.i386 Subject: SL/IP for ISC Message-ID: <179@tw-rnd.SanDiego.NCR.COM> Date: 11 Dec 89 16:41:04 GMT Reply-To: jml@tw-rnd.SanDiego.NCR.COM (Michael Lodman) Organization: NCR Corporation - Distributed Systems Lab Lines: 1031 After numerous mail requests, I decided the easiest thing to do would be to just post this source for SL/IP. Disclaimer: I am nothing but a user of this code. cut here------------------------cut here------------------------cut here # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by John Ioannidis on Wed Oct 18 11:18:41 1989 # # This archive contains: # README Driver.c Master space.c # netd.cf node.d-slip sdevice.d-slip slattach.c # # Modification/access file times will be preserved. # Error checking via wc(1) will be performed. # Error checking via sum(1) will be performed. LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH if sum -r /dev/null 2>&1 then sumopt='-r' else sumopt='' fi echo x - README cat >README <<'@EOF' It is assumed that you more or less know how to install a driver in a System V machine and rebuild the kernel. The instructions here are for Interactive's 386/ix -- your milage may vary. * create /etc/conf/pack.d/slip/. Copy Driver.c and space.c there. Compile Driver.c (cc -c Driver.c) and leave space.c intact. * Put the following line in a /etc/conf/sdevice.d/slip ----------------------cut-here------------------------- slip Y 1 0 0 0 0 0 0 0 ----------------------cut-here------------------------- * Put the following two lines in /etc/conf/node.d/slip ----------------------cut-here------------------------- slip slip c 0 slip sliplisten c 1 ----------------------cut-here------------------------- * Put the folloing line in a file called Master in /tmp (or in /etc/conf/pack.d/slip) and run /etc/conf/bin/idinstall -a -m -k slip on it. ----------------------cut-here------------------------- slip - iSco slip 0 0 0 32 -1 ----------------------cut-here------------------------- This will install it in /etc/conf/cf.d/mdevice. Now run kconfig; this is by far the easiest way of reconfiguring a kernel. Just select '2' (configure a new kernel), followed by a few yes'es. If all goes well, it should build a new kernel, and when you reboot, create /dev/slip and /dev/sliplisten in /dev. Now you have to change /etc/netd.cf. Edit the one provided here. What we are doing is we are linking /dev/slip right under /dev/ip, the same way /dev/lo and /dev/arp are linked. Finally, compile slattach.c, connect your machine to another machine that groks slip, and fire up netd and slattach. Network services, pinging and gatewaying should all work. If you want to turn on debugging, run slattach with the environment variable DEBUGSLIP set to 1 (for debugging the STREAMS module), 2 (for debugging slattach) or 3 (for debugging both). Setting it to zero will disable both. Things I haven't done: * Change the MTU from 576 to something more reasonable (like 1500) * Set the POINTOPOINT flag in the if structure (I have yet to figure out how to do that in a clean way) * Implement the DLGSTAT ioctl so that netstat -i will work properly. * Clean up the code; it contains too many debugging hooks right now. * ... This is not the cleanest code I have ever written, but until last month I had never even used a System-V machine, let alone written a STREAMS device driver for it. The driver itself took me less than a week to write, in case it matters. I could have banged on the driver for another week and then released a cleaner version, but I think that a lot of people want SLIP for their machines and releasing it now will enable me to have it tested on a variety of platforms and have it debugged faster. In case you need to reach me, you can send me e-mail at ji@cs.columbia.edu (but you already know that). This is by far the easiest way to get in touch with me. If you feel like calling me, my phone number is (212) 854-5510, and I'm there from noon to the wee hours in the morning (but not continuously!) Finally, if you are, or know of, a good Un*x kernel hacker who wants to work for 12-18 months on a REALLY exciting project, drop me a line. /ji @EOF set `sum $sumopt Driver.c <<'@EOF' /* * SLIP driver for 386/ix * * Copyright (C) 1989 by John Ioannidis, ji@cs.columbia.edu * * Permission is granted to use, modify and copy this code * provided you don't make a profit out of it and that you * keep the copyright notice intact. */ #include "sys/types.h" #include "sys/param.h" #include "sys/sysmacros.h" #include "sys/stream.h" #include "sys/stropts.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/lihdr.h" #include "sys/socket.h" #include "netinet/in_systm.h" #include "netinet/in.h" #include "netinet/ip.h" #include "net/if.h" static struct module_info minfo = { 0, "slip", 0, INFPSZ, 512, 128 }; static int slipopen(), slipclose(), slipwput(), slipwsrv(), sliprsrv(); static struct qinit rinit = { NULL, sliprsrv, slipopen, slipclose, NULL, &minfo, NULL }; static struct qinit winit = { slipwput, slipwsrv, NULL, NULL, NULL, &minfo, NULL }; struct streamtab slipinfo = { &rinit, &winit, NULL, NULL }; struct slip { short boundp; short slipd; queue_t *oqptr; }; extern struct slip slip_slip[]; extern int slip_cnt; #define SETDEBUG (('J'<<8) | 1) static int slipdebug=0; static int slipopen(q, dev, flag, sflag) queue_t *q; { struct slip *slip; /* * If CLONEOPEN, return an error. We are only supposed * to be called from the networking code as minor 0 * and from the user-level loopback as minor 1. */ #ifdef DEBUGSLIP if (slipdebug) printf("slipopen(0x%x, %d, 0%o, 0%o)\n", q, dev, flag, sflag); #endif if (sflag == CLONEOPEN) return OPENFAIL; if (q->q_ptr) { #ifdef DEBUGSLIP if (slipdebug) printf("slipopen: attempted reopen slip/%d\n", dev); #endif return OPENFAIL; } switch (minor(dev)) { case 1: /* user side */ slip = &slip_slip[1]; q->q_ptr = (caddr_t) slip; WR(q)->q_ptr = (caddr_t) slip; slip_slip[0].oqptr = q; slip->slipd = 1; slip->boundp = 0; return 1; break; case 0: slip = &slip_slip[0]; q->q_ptr = (caddr_t) slip; WR(q)->q_ptr = (caddr_t) slip; slip_slip[1].oqptr = q; slip->slipd = 0; slip->boundp = 0; return 0; break; default: #ifdef DEBUGSLIP if (slipdebug) printf("slipopen: bad minor device slip/%d\n", dev); #endif return OPENFAIL; } /*NOTREACHED*/ } /* * the write-side put proc. This is where we handle all the * requests from the /dev/ip driver. Look up the document for * DLI for explanations. */ static int slipwput(q, mp) queue_t *q; mblk_t *mp; { struct ifnet *myif; mblk_t *mpc; extern struct ifnet *ifnet; int i; register struct slip *slip; slip = (struct slip*)q->q_ptr; /* recover our private d/s */ switch (mp->b_datap->db_type) { case M_PROTO: case M_PCPROTO: { register union DL_primitives *lir; lir = (union DL_primitives *)mp->b_rptr; switch (lir->prim_type) { case DL_BIND_REQ: #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: DL_BIND_REQ: sap=%x\n", slip->slipd, lir->bind_req.LLC_sap); #endif mp->b_datap->db_type = M_PCPROTO; lir->bind_ack.PRIM_type = DL_BIND_ACK; /* lir->bind_ack.LLC_sap = 0; */ lir->bind_ack.ADDR_length = 0; lir->bind_ack.ADDR_offset = 0; lir->bind_ack.GROWTH_field[0] = 0x1234; lir->bind_ack.GROWTH_field[1] = 0x5678; mp->b_wptr = mp->b_rptr + DL_BIND_ACK_SIZE; qreply(q, mp); break; case DL_UNBIND_REQ: #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: DL_UNBIND_REQ\n", slip->slipd); #endif mp->b_datap->db_type = M_PCPROTO; lir->ok_ack.PRIM_type = DL_OK_ACK; lir->ok_ack.CORRECT_prim = DL_UNBIND_REQ; mp->b_wptr = mp->b_rptr + DL_OK_ACK_SIZE; qreply(q, mp); break; case DL_INFO_REQ: #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: DL_INFO_REQ\n", slip->slipd); #endif mp->b_datap->db_type = M_PCPROTO; lir->info_ack.PRIM_type = DL_INFO_ACK; lir->info_ack.SDU_max = 1024; lir->info_ack.SDU_min = sizeof(struct ip); lir->info_ack.ADDR_length = 0; lir->info_ack.SUBNET_type = 0; lir->info_ack.SERV_class = 0; lir->info_ack.CURRENT_state = DL_IDLE; mp->b_wptr = mp->b_rptr + DL_INFO_ACK_SIZE; qreply(q, mp); break; case DL_UNITDATA_REQ: #ifdef DEBUGSLIP if (slipdebug) { printf("slipwput%d: DL_UNITDATA_REQ: len=%d off=%d sclass=%d filler=%d :", slip->slipd, lir->data_req.RA_length, lir->data_req.RA_offset, lir->data_req.SERV_class, lir->data_req.FILLER_field); for (i=lir->data_req.RA_offset; idata_req.RA_offset + lir->data_req.RA_length; i++) printf("%d:", ((char *)&(lir->data_req))[i]); printf("\n"); } #endif if (mp->b_cont) { #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: putting cont msg to the Q\n", slip->slipd); #endif putq(q, mp->b_cont); } else { printf("slipwput: DL_UNITDATA_REQ: error! no continuation message!\n"); freemsg(mp); } break; default: printf("slipwput%d: prim_type=0%o, putting in Q\n", slip->slipd, lir->prim_type); putq(q, mp); } } break; case M_IOCTL: { struct iocblk *iocp; int error; iocp = (struct iocblk *)mp->b_rptr; switch (iocp->ioc_cmd) { #ifdef DEBUGSLIP case SETDEBUG: if (iocp->ioc_count != sizeof(int)) goto iocnak; slipdebug = *(int *)mp->b_cont->b_rptr; mp->b_datap->db_type = M_IOCACK; iocp->ioc_count = 0; qreply(q, mp); break; #endif default: iocnak: error = EINVAL; #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: M_IOCTL: bad ioctl %x\n", slip->slipd, iocp->ioc_cmd); #endif mp->b_datap->db_type = M_IOCNAK; iocp->ioc_error = error; qreply(q, mp); } break; } case M_FLUSH: #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: M_FLUSH: flushing\n", slip->slipd); #endif if (*mp->b_rptr & FLUSHW) flushq(q, 0); if (*mp->b_rptr & FLUSHR) { flushq(RD(q), 0); *mp->b_rptr &= ~FLUSHW; qreply(q, mp); } else freemsg(mp); break; case M_DATA: { register union DL_primitives *lir; #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: M_DATA message\n", slip->slipd); #endif /* * the only way we can get here is by having the * user process pump us a datagram. Create a * contol part and send up a DL_UNITDATA_IND * message. */ mpc = allocb(DL_UNITDATA_IND_SIZE + 12, BPRI_MED); if (mpc == NULL) { printf("slipwput%d: M_DATA: can't allocb control msgs\n", slip->slipd); return; } mpc->b_datap->db_type = M_PCPROTO; lir = (union DL_primitives *)mpc->b_wptr; lir->data_ind.PRIM_type = DL_UNITDATA_IND; lir->data_ind.RA_length = lir->data_ind.LA_length = 6; lir->data_ind.RA_offset = DL_UNITDATA_IND_SIZE; lir->data_ind.LA_offset = DL_UNITDATA_IND_SIZE + 6; lir->data_ind.SERV_class = 0; mpc->b_wptr[DL_UNITDATA_IND_SIZE+0] = 0x7e; mpc->b_wptr[DL_UNITDATA_IND_SIZE+1] = 0x00; mpc->b_wptr[DL_UNITDATA_IND_SIZE+2] = 0x00; mpc->b_wptr[DL_UNITDATA_IND_SIZE+3] = 0x02; mpc->b_wptr[DL_UNITDATA_IND_SIZE+4] = 0x02; mpc->b_wptr[DL_UNITDATA_IND_SIZE+5] = 0x00; mpc->b_wptr[DL_UNITDATA_IND_SIZE+6] = 0x7e; mpc->b_wptr[DL_UNITDATA_IND_SIZE+7] = 0x00; mpc->b_wptr[DL_UNITDATA_IND_SIZE+8] = 0x00; mpc->b_wptr[DL_UNITDATA_IND_SIZE+9] = 0x01; mpc->b_wptr[DL_UNITDATA_IND_SIZE+10] = 0x02; mpc->b_wptr[DL_UNITDATA_IND_SIZE+11] = 0x00; mpc->b_wptr += DL_UNITDATA_IND_SIZE + 12; mpc->b_cont = mp; /* putq(q, mpc); */ putnext(slip->oqptr, mpc); break; } default: /* * if this stream isn't connected, send an M_ERROR upstream */ if (slip->oqptr == NULL) { putctl1(RD(q)->q_next, M_ERROR, ENXIO); freemsg(mp); break; } #ifdef DEBUGSLIP if (slipdebug) printf("slipwput%d: DEFAULT (data?) message\n", slip->slipd); #endif putq(q, mp); } } static int slipwsrv(q) register queue_t *q; { mblk_t *mp; register struct slip *slip; slip = (struct slip *)q->q_ptr; #ifdef DEBUGSLIP if (slipdebug) printf("slipwsrv%d: called!\n", slip->slipd); #endif while ((mp = getq(q)) != NULL) { /* * Check is we can put the message up the other * stream's read queue */ if (mp->b_datap->db_type <= QPCTL && !canput(slip->oqptr->q_next)) { #ifdef DEBUGSLIP if (slipdebug) printf("slipwsrv%d: blocked, putting back\n",slip->slipd); #endif putbq(q, mp); break; } #ifdef DEBUGSLIP if (slipdebug) printf("slipwsrv%d: pulled sth from the Q, sending...\n", slip->slipd); #endif putnext(slip->oqptr, mp); } } static int sliprsrv(q) queue_t *q; { /* * enter only when "back enabled" by flow control */ struct slip *slip; #ifdef DEBUGSLIP if (slipdebug) printf("sliprsrv%d: called!\n", slip->slipd); #endif slip = (struct slip *)q->q_ptr; if (slip->oqptr == NULL) return; /* manually enable write service procedure */ qenable(WR(slip->oqptr)); } static int slipclose(q) queue_t *q; { register struct slip *slip; slip = (struct slip *)q->q_ptr; slip->boundp = NULL; #ifdef DEBUGSLIP if (slipdebug) printf("slipclose%d: called!\n", slip->slipd); #endif } #ifdef notdef for (myif=ifnet; myif; myif = myif->if_next) { #ifdef DEBUGSLIP printf("slipwput: found %s\n", myif->if_name); #endif if (myif->if_name && !(strcmp(myif->if_name, "slip0"))) { myif->if_flags |= IFF_POINTOPOINT; break; } } #endif @EOF set `sum $sumopt Master <<'@EOF' slip - iSco slip 0 0 0 32 -1 @EOF set `sum $sumopt space.c <<'@EOF' /* * SLIP driver for 386/ix * * Copyright (C) 1989 by John Ioannidis, ji@cs.columbia.edu * * Permission is granted to use, modify and copy this code * provided you don't make a profit out of it and that you * keep the copyright notice intact. */ #include "sys/types.h" #include "sys/param.h" #include "sys/sysmacros.h" #include "sys/stream.h" #include "sys/stropts.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "config.h" struct slip { short openp; short slipd; queue_t *oqptr; }; struct slip slip_slip[SLIP_MAXSUB]; int slip_cnt = SLIP_MAXSUB; @EOF set `sum $sumopt netd.cf <<'@EOF' # @(#)netd.cf 1.4 - 88/11/15 # # This is a configuration file for host-based # TCP/IP using the wd ethernet interface # # open control streams for transport protocols tcp = "/dev/tcp" udp = "/dev/udp" # open an IP stream for each transport protocol ip_tcp = "/dev/ip" nsap 6 # bind stream to TCP protocol id ip_udp = "/dev/ip" nsap 17 # bind stream to UDP protocol id # open ARP for ethernet use arp = "/dev/arp" lsap 0x800 # open link level devices wd_arp = "/dev/wd" lsap 0x806 # stream for ARP messages wd_ip = "/dev/wd" lsap 0x800 # stream for IP messages loop = "/dev/lo" lsap 0x800 # stream for loopback driver loslip = "/dev/slip" lsap 0x800 # ji's sample driver # put it together link ip_tcp under tcp link ip_udp under udp # names must not assume a unit number so use as part of name link loop under ip_tcp name "lo0" link arp under ip_tcp name "wd0" link loslip under ip_tcp name "slip0" link wd_arp under arp type 0x101 link wd_ip under arp type 0x1 # initial configuration of interfaces ifconfig "wd0" toshiba1 up ifconfig "lo0" localhost up ifconfig "slip0" 126.0.0.1 126.0.0.2 up @EOF set `sum $sumopt node.d-slip <<'@EOF' slip slip c 0 slip sliplisten c 1 @EOF set `sum $sumopt sdevice.d-slip <<'@EOF' slip Y 1 0 0 0 0 0 0 0 @EOF set `sum $sumopt slattach.c <<'@EOF' #include #include #include #include #include #include #define isdot(_x) (((_x)&0x80)|!(isprint(_x))) #define SLIPEND (0300) #define SLIPESC (0333) #define SLIPESC_END (0334) #define SLIPESC_ESC (0335) #define SETDEBUG (('J'<<8) | 1) main(argc, argv) int argc; char **argv; { int fd, tfd, nr, debugfl; int flags, retval, i, inescape, debugon; unsigned char ibuf[2048], obuf[2048]; unsigned char *ib, *ob; char *ev; struct termio tio; struct strbuf ctlptr, dataptr; struct strioctl sctl; struct DL_unitdata_ind rply; tfd = open("/dev/tty00", 2); if (tfd < 0) perror("/dev/tty00"), exit(); tio.c_iflag = 0; tio.c_oflag = 0; tio.c_cflag = B9600 | CS8 | CREAD; tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (ioctl(tfd, TCSETA, &tio) < 0) perror("ioctl"), exit(); fd = open("/dev/sliplisten", 2); if (fd < 0) perror("/dev/sliplisten:"), exit(); if (ev = (char *)getenv("DEBUGSLIP")) { debugfl = atoi(ev); debugon = debugfl & 2; debugfl &= 1; sctl.ic_cmd = SETDEBUG; sctl.ic_timout = 0; sctl.ic_dp = (char *)&debugfl; sctl.ic_len = 4; if (ioctl(fd, I_STR, &sctl) < 0) perror("SETDEBUG"); } if (fork()) { printf("sliplisten: reader: starting up\n"); ob = obuf; for(;;) { nr = read(tfd, ibuf,2048); write(1, ".", 1); inescape = 0; if (nr <= 0) perror("reading from tty"), exit(); ib = ibuf; for (i=0; i 0) { if (debugon) xdump(dataptr.buf, dataptr.len, "sending to IP"); if (putmsg(fd, NULL, &dataptr, 0) < 0) perror("reader: putmsg"); } continue; } else { ob++; inescape = 0; } } else { if (*ob == SLIPESC_END) *ob++ = SLIPEND; else if (*ob == SLIPESC_ESC) *ob++ = SLIPESC; else ob++; } } } } else /* CHILD */ { printf("sliplisten: writer: starting up\n"); for(;;) { dataptr.maxlen = 2048; dataptr.len = 0; dataptr.buf = (char *)ibuf; flags = 0; if ((retval = getmsg(fd, NULL, &dataptr, &flags)) < 0) { perror("getmsg"); continue; } write(1, "+", 1); if (dataptr.len > 0) { ib = ibuf; ob = obuf; *ob++ = SLIPEND; for (i=0; i>4)&0xF]) #define LO(_x) (hd[(_x)&0xF]) xdump(base, length, title) caddr_t base; int length; char *title; { register char *bp, *hp, *cp; register int cnt; printf("%s\n", title); bp = base; hp = line; cp = line+50; for (cnt=80; cnt; line[--cnt]=' ') ; line[49] = line[66] = '*'; line[67] = '\0'; while(length-- > 0) { *hp++ = HI(*bp); *hp++ = LO(*bp); hp++; *cp++ = isdot(*bp)?'.':(*bp); bp++; if (++cnt == 16) { cnt = 0; hp = line; cp = line+50; puts(line); } } if (cnt) { while (cnt++ < 16) { *hp++=' '; *hp++=' '; *hp++=' '; *cp++=' '; } puts(line); } return 0; } @EOF set `sum $sumopt