** DYNAMIC SLIP DEVICES ** This diff is against Linux-1.2.8. (prev.version was for 1.2.4) The system comes up with 0 devices allocated, but when one is called for, it is allocated out from memory pool, and linked into the device structures. When the usage of the device finishes, it is removed from the device pool. To avoid running out of memory when something goes amok, drivers/net/slip.h defines SL_NRUNIT as 256, which SHOULD be enough for everybody -- there can't be more than SL_NRUNIT active SLIPs at any time. The MODULE -code is NOT tested. /Matti Aarnio diff -ur linux-1208virgin/arch/alpha/config.in linux-1208/arch/alpha/config.in --- linux-1208virgin/arch/alpha/config.in Fri Apr 28 11:17:56 1995 +++ linux-1208/arch/alpha/config.in Thu May 4 00:41:04 1995 @@ -87,7 +87,6 @@ bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' SL_COMPRESSED y - bool ' 16 channels instead of 4' SL_SLIP_LOTS n # bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n diff -ur linux-1208virgin/arch/i386/config.in linux-1208/arch/i386/config.in --- linux-1208virgin/arch/i386/config.in Fri Apr 28 11:17:56 1995 +++ linux-1208/arch/i386/config.in Thu May 4 00:41:04 1995 @@ -118,7 +118,6 @@ bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y - bool ' 16 channels instead of 4' SL_SLIP_LOTS n # bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n diff -ur linux-1208virgin/arch/mips/config.in linux-1208/arch/mips/config.in --- linux-1208virgin/arch/mips/config.in Fri Apr 28 11:17:56 1995 +++ linux-1208/arch/mips/config.in Thu May 4 00:41:04 1995 @@ -107,7 +107,6 @@ bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y - bool ' 16 channels instead of 4' SL_SLIP_LOTS n # bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n diff -ur linux-1208virgin/arch/sparc/config.in linux-1208/arch/sparc/config.in --- linux-1208virgin/arch/sparc/config.in Fri Apr 28 11:17:56 1995 +++ linux-1208/arch/sparc/config.in Thu May 4 00:41:04 1995 @@ -94,7 +94,6 @@ bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' SL_COMPRESSED y - bool ' 16 channels instead of 4' SL_SLIP_LOTS n # bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n diff -ur linux-1208virgin/drivers/net/Space.c linux-1208/drivers/net/Space.c --- linux-1208virgin/drivers/net/Space.c Sun Mar 26 10:49:58 1995 +++ linux-1208/drivers/net/Space.c Thu May 4 00:41:04 1995 @@ -215,76 +215,13 @@ #endif /* PLIP */ #if defined(SLIP) || defined(CONFIG_SLIP) - extern int slip_init(struct device *); - -#ifdef SL_SLIP_LOTS - - static struct device slip15_dev={"sl15",0,0,0,0,15,0,0,0,0,NEXT_DEV,slip_init}; - static struct device slip14_dev={"sl14",0,0,0,0,14,0,0,0,0,&slip15_dev,slip_init}; - static struct device slip13_dev={"sl13",0,0,0,0,13,0,0,0,0,&slip14_dev,slip_init}; - static struct device slip12_dev={"sl12",0,0,0,0,12,0,0,0,0,&slip13_dev,slip_init}; - static struct device slip11_dev={"sl11",0,0,0,0,11,0,0,0,0,&slip12_dev,slip_init}; - static struct device slip10_dev={"sl10",0,0,0,0,10,0,0,0,0,&slip11_dev,slip_init}; - static struct device slip9_dev={"sl9",0,0,0,0,9,0,0,0,0,&slip10_dev,slip_init}; - static struct device slip8_dev={"sl8",0,0,0,0,8,0,0,0,0,&slip9_dev,slip_init}; - static struct device slip7_dev={"sl7",0,0,0,0,7,0,0,0,0,&slip8_dev,slip_init}; - static struct device slip6_dev={"sl6",0,0,0,0,6,0,0,0,0,&slip7_dev,slip_init}; - static struct device slip5_dev={"sl5",0,0,0,0,5,0,0,0,0,&slip6_dev,slip_init}; - static struct device slip4_dev={"sl4",0,0,0,0,4,0,0,0,0,&slip5_dev,slip_init}; -# undef NEXT_DEV -# define NEXT_DEV (&slip4_dev) -#endif /* SL_SLIP_LOTS */ - - static struct device slip3_dev = { - "sl3", /* Internal SLIP driver, channel 3 */ - 0x0, /* recv memory end */ - 0x0, /* recv memory start */ - 0x0, /* memory end */ - 0x0, /* memory start */ - 0x3, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - NEXT_DEV, /* next device */ - slip_init /* slip_init should set up the rest */ - }; - static struct device slip2_dev = { - "sl2", /* Internal SLIP driver, channel 2 */ - 0x0, /* recv memory end */ - 0x0, /* recv memory start */ - 0x0, /* memory end */ - 0x0, /* memory start */ - 0x2, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - &slip3_dev, /* next device */ - slip_init /* slip_init should set up the rest */ - }; - static struct device slip1_dev = { - "sl1", /* Internal SLIP driver, channel 1 */ - 0x0, /* recv memory end */ - 0x0, /* recv memory start */ - 0x0, /* memory end */ - 0x0, /* memory start */ - 0x1, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - &slip2_dev, /* next device */ - slip_init /* slip_init should set up the rest */ - }; - static struct device slip0_dev = { - "sl0", /* Internal SLIP driver, channel 0 */ - 0x0, /* recv memory end */ - 0x0, /* recv memory start */ - 0x0, /* memory end */ - 0x0, /* memory start */ - 0x0, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - &slip1_dev, /* next device */ - slip_init /* slip_init should set up the rest */ - }; -# undef NEXT_DEV -# define NEXT_DEV (&slip0_dev) + /* To be exact, this node just hooks the initialization + routines to the device structures. */ +extern int slip_init_ctrl_dev(struct device *); +static struct device slip_bootstrap = { + "slip_proto", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, slip_init_ctrl_dev, }; +#undef NEXT_DEV +#define NEXT_DEV (&slip_bootstrap) #endif /* SLIP */ #if defined(CONFIG_PPP) diff -ur linux-1208virgin/drivers/net/slip.c linux-1208/drivers/net/slip.c --- linux-1208virgin/drivers/net/slip.c Sat Apr 29 12:41:33 1995 +++ linux-1208/drivers/net/slip.c Thu May 4 00:55:58 1995 @@ -36,11 +36,16 @@ * statistics. Include CSLIP code only * if it really needed. * Alan Cox : Free slhc buffers in the right place. + * Matti Aarnio : Dynamic SLIP devices, with ideas taken + * from Jim Freeman's + * dynamic PPP devices. We do NOT kfree() + * device entries, just reg./unreg. them + * as they are needed. We kfree() them + * at module cleanup. * * - * - * FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without - * CONFIG_INET defined. + * FIXME: This driver still makes some IP'ish assumptions. + * It should build cleanly KISS TNC only without CONFIG_INET defined. * I hope now it is fixed ;) */ @@ -84,9 +89,15 @@ #endif -static struct slip sl_ctrl[SL_NRUNIT]; +typedef struct slip_ctrl { + char if_name[8]; /* "sl0\000".."sl99999\000" */ + struct slip ctrl; /* SLIP things */ + struct device dev; /* the device */ +} slip_ctrl_t; + +static slip_ctrl_t *slip_ctrls[SL_NRUNIT]; /* Say, 256 POINTERS, or whatever + the maxima defining SL_NRUNIT is... */ static struct tty_ldisc sl_ldisc; -static int already = 0; static int slip_esc(unsigned char *p, unsigned char *d, int len); static void slip_unesc(struct slip *sl, unsigned char c); @@ -100,15 +111,62 @@ static inline struct slip * sl_alloc(void) { - struct slip *sl; + slip_ctrl_t *slp; int i; - for (i = 0; i < SL_NRUNIT; i++) { - sl = &sl_ctrl[i]; - if (!set_bit(SLF_INUSE, &sl->flags)) { - return sl; - } + for (i = 0; i < SL_NRUNIT; ++i) { + slp = slip_ctrls[i]; + /* Not allocated ? */ + if (slp == NULL) + break; + /* Not in use ? */ + if (!set_bit(SLF_INUSE, &slp->ctrl.flags)) + break; + } + /* SLP is set.. */ + + /* Sorry, too many, all slots in use */ + if (i >= SL_NRUNIT) return NULL; + + /* If no channels are available, allocate one */ + if (!slp && + (slip_ctrls[i] = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t), + GFP_KERNEL)) != NULL) { + slp = slip_ctrls[i]; + memset(slp, 0, sizeof(slip_ctrl_t)); + + /* Initialize channel control data */ + set_bit(SLF_INUSE,&slp->ctrl.flags); + slp->ctrl.tty = NULL; + sprintf(slp->if_name, "sl%d", i); + slp->dev.name = slp->if_name; + slp->dev.base_addr = i; + slp->dev.priv = (void*)&(slp->ctrl); + slp->dev.next = NULL; + slp->dev.init = slip_init; + /* printk(KERN_INFO "slip: kmalloc()ed SLIP control node for line %s\n", + slp->if_name); */ + } + if (slp != NULL) { + + /* register device so that it can be ifconfig'ed */ + /* slip_init() will be called as a side-effect */ + /* SIDE-EFFECT WARNING: slip_init() CLEARS slp->ctrl ! */ + + if (register_netdev(&(slp->dev)) == 0) { + /* (Re-)Set the INUSE bit. Very Important! */ + set_bit(SLF_INUSE,&slp->ctrl.flags); + slp->ctrl.dev = &(slp->dev); + slp->dev.priv = (void*)&(slp->ctrl); + /* printk(KERN_INFO "slip: linked in netdev %s for active use\n", + slp->if_name); */ + return (&(slp->ctrl)); + } else { + clear_bit(SLF_INUSE,&(slp->ctrl.flags)); + printk("sl_alloc() - register_netdev() failure.\n"); + } } + return NULL; } @@ -148,9 +206,9 @@ } } -/* MTU has been changed by the IP layer. Unfortunately we are not told about this, but - we spot it ourselves and fix things up. We could be in an upcall from the tty - driver, or in an ip packet queue. */ +/* MTU has been changed by the IP layer. Unfortunately we are not told + about this, but we spot it ourselves and fix things up. We could be + in an upcall from the tty driver, or in an ip packet queue. */ static void sl_changedmtu(struct slip *sl) { @@ -321,6 +379,8 @@ skb->len = count; skb->dev = sl->dev; memcpy(skb->data, sl->rbuff, count); + /* on Linux-1.3.x net sources: */ + /* skb->protocol=(sl->mode&SL_MODE_AX25)?htons(ETH_P_AX25):htons(ETH_P_IP); */ netif_rx(skb); sl->rx_packets++; } @@ -412,7 +472,7 @@ static int sl_xmit(struct sk_buff *skb, struct device *dev) { - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip*)(dev->priv); if (!dev->start) { printk("%s: xmit call when iface is down\n", dev->name); @@ -463,7 +523,7 @@ sl_type_trans (struct sk_buff *skb, struct device *dev) { #ifdef CONFIG_AX25 - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip*)(dev->priv); if (sl->mode & SL_MODE_AX25) { return htons(ETH_P_AX25); @@ -472,7 +532,6 @@ return htons(ETH_P_IP); } - /* Fill in the MAC-level header. Not used by SLIP. */ static int sl_header(unsigned char *buff, struct device *dev, unsigned short type, @@ -480,7 +539,7 @@ { #ifdef CONFIG_AX25 #ifdef CONFIG_INET - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip*)(dev->priv); if ((sl->mode & SL_MODE_AX25) && type != htons(ETH_P_AX25)) { return ax25_encapsulate(buff, dev, type, daddr, saddr, len, skb); @@ -498,7 +557,7 @@ { #ifdef CONFIG_AX25 #ifdef CONFIG_INET - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip*)(dev->priv); if (sl->mode & SL_MODE_AX25) { return ax25_rebuild_header(buff, dev, raddr, skb); @@ -513,7 +572,7 @@ static int sl_open(struct device *dev) { - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip*)(dev->priv); unsigned long len; if (sl->tty == NULL) { @@ -597,7 +656,7 @@ static int sl_close(struct device *dev) { - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip*)(dev->priv); if (sl->tty == NULL) { return -EBUSY; @@ -705,7 +764,7 @@ if ((err = sl_open(sl->dev))) { return err; } - + #ifdef MODULE MOD_INC_USE_COUNT; #endif @@ -732,10 +791,10 @@ } (void) dev_close(sl->dev); - tty->disc_data = 0; sl->tty = NULL; sl_free(sl); + unregister_netdev(sl->dev); #ifdef MODULE MOD_DEC_USE_COUNT; #endif @@ -746,7 +805,7 @@ sl_get_stats(struct device *dev) { static struct enet_statistics stats; - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip *)(dev->priv); #ifdef SL_INCLUDE_CSLIP struct slcompress *comp; #endif @@ -1048,17 +1107,73 @@ static int sl_open_dev(struct device *dev) { - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip *) (dev->priv); if(sl->tty==NULL) return -ENODEV; return 0; } +/* Initialize SLIP control device -- register SLIP line discipline */ +#ifdef MODULE +static +#endif +int +slip_init_ctrl_dev(struct device *notModule) +{ + int status; + + printk("SLIP: version %s (dynamic channels)" +#ifdef CONFIG_SLIP_MODE_SLIP6 + " (6 bit encapsulation enabled)" +#endif + "\n", + SLIP_VERSION ); +#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE) + printk("CSLIP: code copyright 1989 Regents of the University of California\n"); +#endif +#ifdef CONFIG_AX25 + printk("AX25: KISS encapsulation enabled\n"); +#endif + + /* Clear the pointer array, we allocate devices when we need them */ + memset(&slip_ctrls, 0, sizeof(slip_ctrls)); /* Pointers */ + + /* Fill in our line protocol discipline, and register it */ + memset(&sl_ldisc, 0, sizeof(sl_ldisc)); + sl_ldisc.magic = TTY_LDISC_MAGIC; + sl_ldisc.flags = 0; + sl_ldisc.open = slip_open; + sl_ldisc.close = slip_close; + sl_ldisc.read = NULL; + sl_ldisc.write = NULL; + sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, + unsigned int, unsigned long)) slip_ioctl; + sl_ldisc.select = NULL; + sl_ldisc.receive_buf = slip_receive_buf; + sl_ldisc.receive_room = slip_receive_room; + sl_ldisc.write_wakeup = slip_write_wakeup; + if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { + printk("SLIP: can't register line discipline (err = %d)\n", status); + } + + /* If not loadable module, a bootstrap Space.c slip_proto dev + * now needs to be unregistered. + */ +#ifndef MODULE + if (notModule) { + printk("SLIP: Unregistering bootstrap device " + "'slip_proto' - slip OK\n"); + unregister_netdev(notModule); + } +#endif + return status; +} + /* Initialize the SLIP driver. Called by DDI. */ int slip_init(struct device *dev) { - struct slip *sl = &sl_ctrl[dev->base_addr]; + struct slip *sl = (struct slip *)(dev->priv); int i; #ifdef CONFIG_AX25 static char ax25_bcast[7] = @@ -1067,39 +1182,8 @@ {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; #endif - if (already++ == 0) { - printk("SLIP: version %s (%d channels) %s\n", - SLIP_VERSION, SL_NRUNIT, -#ifdef CONFIG_SLIP_MODE_SLIP6 - "(6 bit encapsulation enabled)" -#else - "" -#endif - ); -#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE) - printk("CSLIP: code copyright 1989 Regents of the University of California\n"); -#endif -#ifdef CONFIG_AX25 - printk("AX25: KISS encapsulation enabled\n"); -#endif - /* Fill in our LDISC request block. */ - memset(&sl_ldisc, 0, sizeof(sl_ldisc)); - sl_ldisc.magic = TTY_LDISC_MAGIC; - sl_ldisc.flags = 0; - sl_ldisc.open = slip_open; - sl_ldisc.close = slip_close; - sl_ldisc.read = NULL; - sl_ldisc.write = NULL; - sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long)) slip_ioctl; - sl_ldisc.select = NULL; - sl_ldisc.receive_buf = slip_receive_buf; - sl_ldisc.receive_room = slip_receive_room; - sl_ldisc.write_wakeup = slip_write_wakeup; - if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { - printk("SLIP: can't register line discipline (err = %d)\n", i); - } - } + if (sl == NULL) + return -ENODEV; /* Set up the "SLIP Control Block". (And clear statistics) */ @@ -1113,7 +1197,7 @@ dev->open = sl_open_dev; dev->stop = sl_close; dev->hard_header = sl_header; - dev->type_trans = sl_type_trans; + dev->type_trans = sl_type_trans; dev->get_stats = sl_get_stats; #ifdef HAVE_SET_MAC_ADDR #ifdef CONFIG_AX25 @@ -1149,47 +1233,13 @@ #ifdef MODULE char kernel_version[] = UTS_RELEASE; -static struct device dev_slip[SL_NRUNIT] = { - { - "sl0", /* slip */ - 0, 0, 0, 0, /* memory */ - 0, 0, /* base, irq */ - 0, 0, 0, NULL, slip_init, - }, - { "sl1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, slip_init }, - { "sl2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, slip_init }, - { "sl3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, slip_init }, -#ifdef SL_SLIP_LOTS - { "sl4" , 0, 0, 0, 0, 4, 0, 0, 0, 0, NULL, slip_init }, - { "sl5" , 0, 0, 0, 0, 5, 0, 0, 0, 0, NULL, slip_init }, - { "sl6" , 0, 0, 0, 0, 6, 0, 0, 0, 0, NULL, slip_init }, - { "sl7" , 0, 0, 0, 0, 7, 0, 0, 0, 0, NULL, slip_init }, - { "sl8" , 0, 0, 0, 0, 8, 0, 0, 0, 0, NULL, slip_init }, - { "sl9" , 0, 0, 0, 0, 9, 0, 0, 0, 0, NULL, slip_init }, - { "sl10", 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, slip_init }, - { "sl11", 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, slip_init }, - { "sl12", 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, slip_init }, - { "sl13", 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, slip_init }, - { "sl14", 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, slip_init }, - { "sl15", 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, slip_init }, -#endif /* SL_SLIP_LOTS */ -}; - int init_module(void) { int err; int i; - for (i = 0; i < SL_NRUNIT; i++) { - if ((err = register_netdev(&dev_slip[i]))) { - if (err == -EEXIST) { - printk("SLIP: devices already present. Module not loaded.\n"); - } - return err; - } - } - return 0; + return slip_init_ctrl_dev(NULL); } void @@ -1202,11 +1252,13 @@ return; } for (i = 0; i < SL_NRUNIT; i++) { - unregister_netdev(&dev_slip[i]); + if (slip_ctrls[i] != NULL) { + unregister_netdev(&(slip_ctrls[i]->dev)); + kfree(slip_ctrls[i]); + } } if ((i = tty_register_ldisc(N_SLIP, NULL))) { printk("SLIP: can't unregister line discipline (err = %d)\n", i); } - already = 0; } #endif /* MODULE */ diff -ur linux-1208virgin/drivers/net/slip.h linux-1208/drivers/net/slip.h --- linux-1208virgin/drivers/net/slip.h Mon Jan 9 07:35:23 1995 +++ linux-1208/drivers/net/slip.h Thu May 4 00:41:04 1995 @@ -31,11 +31,8 @@ #endif /* SLIP configuration. */ -#ifndef SL_SLIP_LOTS -#define SL_NRUNIT 4 /* number of SLIP channels */ -#else -#define SL_NRUNIT 16 -#endif +#define SL_NRUNIT 256 /* MAX number of SLIP channels */ + #define SL_MTU 296 /* 296; I am used to 600- FvK */ /* SLIP protocol characters. */