1 /*
2  *
3  * arch/xtensa/platforms/iss/network.c
4  *
5  * Platform specific initialization.
6  *
7  * Authors: Chris Zankel <chris@zankel.net>
8  * Based on work form the UML team.
9  *
10  * Copyright 2005 Tensilica Inc.
11  *
12  * This program is free software; you can redistribute  it and/or modify it
13  * under  the terms of  the GNU General  Public License as published by the
14  * Free Software Foundation;  either version 2 of the  License, or (at your
15  * option) any later version.
16  *
17  */
18 
19 #include <linux/list.h>
20 #include <linux/irq.h>
21 #include <linux/spinlock.h>
22 #include <linux/slab.h>
23 #include <linux/timer.h>
24 #include <linux/if_ether.h>
25 #include <linux/inetdevice.h>
26 #include <linux/init.h>
27 #include <linux/if_tun.h>
28 #include <linux/etherdevice.h>
29 #include <linux/interrupt.h>
30 #include <linux/ioctl.h>
31 #include <linux/bootmem.h>
32 #include <linux/ethtool.h>
33 #include <linux/rtnetlink.h>
34 #include <linux/platform_device.h>
35 
36 #include <platform/simcall.h>
37 
38 #define DRIVER_NAME "iss-netdev"
39 #define ETH_MAX_PACKET 1500
40 #define ETH_HEADER_OTHER 14
41 #define ISS_NET_TIMER_VALUE (2 * HZ)
42 
43 
44 static DEFINE_SPINLOCK(opened_lock);
45 static LIST_HEAD(opened);
46 
47 static DEFINE_SPINLOCK(devices_lock);
48 static LIST_HEAD(devices);
49 
50 /* ------------------------------------------------------------------------- */
51 
52 /* We currently only support the TUNTAP transport protocol. */
53 
54 #define TRANSPORT_TUNTAP_NAME "tuntap"
55 #define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET
56 
57 struct tuntap_info {
58 	char dev_name[IFNAMSIZ];
59 	int fixed_config;
60 	unsigned char gw[ETH_ALEN];
61 	int fd;
62 };
63 
64 /* ------------------------------------------------------------------------- */
65 
66 
67 /* This structure contains out private information for the driver. */
68 
69 struct iss_net_private {
70 
71 	struct list_head device_list;
72 	struct list_head opened_list;
73 
74 	spinlock_t lock;
75 	struct net_device *dev;
76 	struct platform_device pdev;
77 	struct timer_list tl;
78 	struct net_device_stats stats;
79 
80 	struct timer_list timer;
81 	unsigned int timer_val;
82 
83 	int index;
84 	int mtu;
85 
86 	unsigned char mac[ETH_ALEN];
87 	int have_mac;
88 
89 	struct {
90 		union {
91 			struct tuntap_info tuntap;
92 		} info;
93 
94 		int (*open)(struct iss_net_private *lp);
95 		void (*close)(struct iss_net_private *lp);
96 		int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
97 		int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
98 		unsigned short (*protocol)(struct sk_buff *skb);
99 		int (*poll)(struct iss_net_private *lp);
100 	} tp;
101 
102 };
103 
104 /* ================================ HELPERS ================================ */
105 
106 
107 static char *split_if_spec(char *str, ...)
108 {
109 	char **arg, *end;
110 	va_list ap;
111 
112 	va_start(ap, str);
113 	while ((arg = va_arg(ap, char**)) != NULL) {
114 		if (*str == '\0')
115 			return NULL;
116 		end = strchr(str, ',');
117 		if (end != str)
118 			*arg = str;
119 		if (end == NULL)
120 			return NULL;
121 		*end ++ = '\0';
122 		str = end;
123 	}
124 	va_end(ap);
125 	return str;
126 }
127 
128 
129 #if 0
130 /* Adjust SKB. */
131 
132 struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
133 {
134 	if ((skb != NULL) && (skb_tailroom(skb) < extra)) {
135 		struct sk_buff *skb2;
136 
137 		skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
138 		dev_kfree_skb(skb);
139 		skb = skb2;
140 	}
141 	if (skb != NULL)
142 		skb_put(skb, extra);
143 
144 	return skb;
145 }
146 #endif
147 
148 /* Return the IP address as a string for a given device. */
149 
150 static void dev_ip_addr(void *d, char *buf, char *bin_buf)
151 {
152 	struct net_device *dev = d;
153 	struct in_device *ip = dev->ip_ptr;
154 	struct in_ifaddr *in;
155 	__be32 addr;
156 
157 	if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
158 		printk(KERN_WARNING "Device not assigned an IP address!\n");
159 		return;
160 	}
161 
162 	addr = in->ifa_address;
163 	sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
164 		(addr >> 16) & 0xff, addr >> 24);
165 
166 	if (bin_buf) {
167 		bin_buf[0] = addr & 0xff;
168 		bin_buf[1] = (addr >> 8) & 0xff;
169 		bin_buf[2] = (addr >> 16) & 0xff;
170 		bin_buf[3] = addr >> 24;
171 	}
172 }
173 
174 /* Set Ethernet address of the specified device. */
175 
176 static void inline set_ether_mac(void *d, unsigned char *addr)
177 {
178 	struct net_device *dev = d;
179 	memcpy(dev->dev_addr, addr, ETH_ALEN);
180 }
181 
182 
183 /* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
184 
185 static int tuntap_open(struct iss_net_private *lp)
186 {
187 	struct ifreq ifr;
188 	char *dev_name = lp->tp.info.tuntap.dev_name;
189 	int err = -EINVAL;
190 	int fd;
191 
192 	/* We currently only support a fixed configuration. */
193 
194 	if (!lp->tp.info.tuntap.fixed_config)
195 		return -EINVAL;
196 
197 	if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) {	/* O_RDWR */
198 		printk("Failed to open /dev/net/tun, returned %d "
199 		       "(errno = %d)\n", fd, errno);
200 		return fd;
201 	}
202 
203 	memset(&ifr, 0, sizeof ifr);
204 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
205 	strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name);
206 
207 	if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
208 		printk("Failed to set interface, returned %d "
209 		       "(errno = %d)\n", err, errno);
210 		simc_close(fd);
211 		return err;
212 	}
213 
214 	lp->tp.info.tuntap.fd = fd;
215 	return err;
216 }
217 
218 static void tuntap_close(struct iss_net_private *lp)
219 {
220 #if 0
221 	if (lp->tp.info.tuntap.fixed_config)
222 		iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name);
223 #endif
224 	simc_close(lp->tp.info.tuntap.fd);
225 	lp->tp.info.tuntap.fd = -1;
226 }
227 
228 static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb)
229 {
230 #if 0
231 	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
232 	if (*skb == NULL)
233 		return -ENOMEM;
234 #endif
235 
236 	return simc_read(lp->tp.info.tuntap.fd,
237 			(*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
238 }
239 
240 static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb)
241 {
242 	return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
243 }
244 
245 unsigned short tuntap_protocol(struct sk_buff *skb)
246 {
247 	return eth_type_trans(skb, skb->dev);
248 }
249 
250 static int tuntap_poll(struct iss_net_private *lp)
251 {
252 	return simc_poll(lp->tp.info.tuntap.fd);
253 }
254 
255 /*
256  * Currently only a device name is supported.
257  * ethX=tuntap[,[mac address][,[device name]]]
258  */
259 
260 static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
261 {
262 	const int len = strlen(TRANSPORT_TUNTAP_NAME);
263 	char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
264 
265 	/* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
266 
267 	if (strncmp(init, TRANSPORT_TUNTAP_NAME, len))
268 		return 0;
269 
270 	if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') {
271 		if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) {
272 			printk("Extra garbage on specification : '%s'\n", rem);
273 			return 0;
274 		}
275 	} else if (*init != '\0') {
276 		printk("Invalid argument: %s. Skipping device!\n", init);
277 		return 0;
278 	}
279 
280 	if (dev_name) {
281 		strncpy(lp->tp.info.tuntap.dev_name, dev_name,
282 			 sizeof lp->tp.info.tuntap.dev_name);
283 		lp->tp.info.tuntap.fixed_config = 1;
284 	} else
285 		strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME);
286 
287 
288 #if 0
289 	if (setup_etheraddr(mac_str, lp->mac))
290 		lp->have_mac = 1;
291 #endif
292 	lp->mtu = TRANSPORT_TUNTAP_MTU;
293 
294 	//lp->info.tuntap.gate_addr = gate_addr;
295 
296 	lp->tp.info.tuntap.fd = -1;
297 
298 	lp->tp.open = tuntap_open;
299 	lp->tp.close = tuntap_close;
300 	lp->tp.read = tuntap_read;
301 	lp->tp.write = tuntap_write;
302 	lp->tp.protocol = tuntap_protocol;
303 	lp->tp.poll = tuntap_poll;
304 
305 	printk("TUN/TAP backend - ");
306 #if 0
307 	if (lp->host.gate_addr != NULL)
308 		printk("IP = %s", lp->host.gate_addr);
309 #endif
310 	printk("\n");
311 
312 	return 1;
313 }
314 
315 /* ================================ ISS NET ================================ */
316 
317 static int iss_net_rx(struct net_device *dev)
318 {
319 	struct iss_net_private *lp = netdev_priv(dev);
320 	int pkt_len;
321 	struct sk_buff *skb;
322 
323 	/* Check if there is any new data. */
324 
325 	if (lp->tp.poll(lp) == 0)
326 		return 0;
327 
328 	/* Try to allocate memory, if it fails, try again next round. */
329 
330 	if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) {
331 		lp->stats.rx_dropped++;
332 		return 0;
333 	}
334 
335 	skb_reserve(skb, 2);
336 
337 	/* Setup skb */
338 
339 	skb->dev = dev;
340 	skb_reset_mac_header(skb);
341 	pkt_len = lp->tp.read(lp, &skb);
342 	skb_put(skb, pkt_len);
343 
344 	if (pkt_len > 0) {
345 		skb_trim(skb, pkt_len);
346 		skb->protocol = lp->tp.protocol(skb);
347 
348 		lp->stats.rx_bytes += skb->len;
349 		lp->stats.rx_packets++;
350 	//	netif_rx(skb);
351 		netif_rx_ni(skb);
352 		return pkt_len;
353 	}
354 	kfree_skb(skb);
355 	return pkt_len;
356 }
357 
358 static int iss_net_poll(void)
359 {
360 	struct list_head *ele;
361 	int err, ret = 0;
362 
363 	spin_lock(&opened_lock);
364 
365 	list_for_each(ele, &opened) {
366 		struct iss_net_private *lp;
367 
368 		lp = list_entry(ele, struct iss_net_private, opened_list);
369 
370 		if (!netif_running(lp->dev))
371 			break;
372 
373 		spin_lock(&lp->lock);
374 
375 		while ((err = iss_net_rx(lp->dev)) > 0)
376 			ret++;
377 
378 		spin_unlock(&lp->lock);
379 
380 		if (err < 0) {
381 			printk(KERN_ERR "Device '%s' read returned %d, "
382 			       "shutting it down\n", lp->dev->name, err);
383 			dev_close(lp->dev);
384 		} else {
385 			// FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ);
386 		}
387 	}
388 
389 	spin_unlock(&opened_lock);
390 	return ret;
391 }
392 
393 
394 static void iss_net_timer(unsigned long priv)
395 {
396 	struct iss_net_private* lp = (struct iss_net_private*) priv;
397 
398 	spin_lock(&lp->lock);
399 
400 	iss_net_poll();
401 
402 	mod_timer(&lp->timer, jiffies + lp->timer_val);
403 
404 	spin_unlock(&lp->lock);
405 }
406 
407 
408 static int iss_net_open(struct net_device *dev)
409 {
410 	struct iss_net_private *lp = netdev_priv(dev);
411 	char addr[sizeof "255.255.255.255\0"];
412 	int err;
413 
414 	spin_lock(&lp->lock);
415 
416 	if ((err = lp->tp.open(lp)) < 0)
417 		goto out;
418 
419 	if (!lp->have_mac) {
420 		dev_ip_addr(dev, addr, &lp->mac[2]);
421 		set_ether_mac(dev, lp->mac);
422 	}
423 
424 	netif_start_queue(dev);
425 
426 	/* clear buffer - it can happen that the host side of the interface
427 	 * is full when we get here. In this case, new data is never queued,
428 	 * SIGIOs never arrive, and the net never works.
429 	 */
430 	while ((err = iss_net_rx(dev)) > 0)
431 		;
432 
433 	spin_lock(&opened_lock);
434 	list_add(&lp->opened_list, &opened);
435 	spin_unlock(&opened_lock);
436 
437 	init_timer(&lp->timer);
438 	lp->timer_val = ISS_NET_TIMER_VALUE;
439 	lp->timer.data = (unsigned long) lp;
440 	lp->timer.function = iss_net_timer;
441 	mod_timer(&lp->timer, jiffies + lp->timer_val);
442 
443 out:
444 	spin_unlock(&lp->lock);
445 	return err;
446 }
447 
448 static int iss_net_close(struct net_device *dev)
449 {
450 	struct iss_net_private *lp = netdev_priv(dev);
451 printk("iss_net_close!\n");
452 	netif_stop_queue(dev);
453 	spin_lock(&lp->lock);
454 
455 	spin_lock(&opened_lock);
456 	list_del(&opened);
457 	spin_unlock(&opened_lock);
458 
459 	del_timer_sync(&lp->timer);
460 
461 	lp->tp.close(lp);
462 
463 	spin_unlock(&lp->lock);
464 	return 0;
465 }
466 
467 static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
468 {
469 	struct iss_net_private *lp = netdev_priv(dev);
470 	unsigned long flags;
471 	int len;
472 
473 	netif_stop_queue(dev);
474 	spin_lock_irqsave(&lp->lock, flags);
475 
476 	len = lp->tp.write(lp, &skb);
477 
478 	if (len == skb->len) {
479 		lp->stats.tx_packets++;
480 		lp->stats.tx_bytes += skb->len;
481 		dev->trans_start = jiffies;
482 		netif_start_queue(dev);
483 
484 		/* this is normally done in the interrupt when tx finishes */
485 		netif_wake_queue(dev);
486 
487 	} else if (len == 0) {
488 		netif_start_queue(dev);
489 		lp->stats.tx_dropped++;
490 
491 	} else {
492 		netif_start_queue(dev);
493 		printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len);
494 	}
495 
496 	spin_unlock_irqrestore(&lp->lock, flags);
497 
498 	dev_kfree_skb(skb);
499 	return NETDEV_TX_OK;
500 }
501 
502 
503 static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
504 {
505 	struct iss_net_private *lp = netdev_priv(dev);
506 	return &lp->stats;
507 }
508 
509 static void iss_net_set_multicast_list(struct net_device *dev)
510 {
511 #if 0
512 	if (dev->flags & IFF_PROMISC)
513 		return;
514 	else if (!netdev_mc_empty(dev))
515 		dev->flags |= IFF_ALLMULTI;
516 	else
517 		dev->flags &= ~IFF_ALLMULTI;
518 #endif
519 }
520 
521 static void iss_net_tx_timeout(struct net_device *dev)
522 {
523 #if 0
524 	dev->trans_start = jiffies;
525 	netif_wake_queue(dev);
526 #endif
527 }
528 
529 static int iss_net_set_mac(struct net_device *dev, void *addr)
530 {
531 #if 0
532 	struct iss_net_private *lp = netdev_priv(dev);
533 	struct sockaddr *hwaddr = addr;
534 
535 	spin_lock(&lp->lock);
536 	memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
537 	spin_unlock(&lp->lock);
538 #endif
539 
540 	return 0;
541 }
542 
543 static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
544 {
545 #if 0
546 	struct iss_net_private *lp = netdev_priv(dev);
547 	int err = 0;
548 
549 	spin_lock(&lp->lock);
550 
551 	// FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user);
552 
553 	if (new_mtu < 0)
554 		err = new_mtu;
555 	else
556 		dev->mtu = new_mtu;
557 
558 	spin_unlock(&lp->lock);
559 	return err;
560 #endif
561 	return -EINVAL;
562 }
563 
564 void iss_net_user_timer_expire(unsigned long _conn)
565 {
566 }
567 
568 
569 static struct platform_driver iss_net_driver = {
570 	.driver = {
571 		.name  = DRIVER_NAME,
572 	},
573 };
574 
575 static int driver_registered;
576 
577 static const struct net_device_ops iss_netdev_ops = {
578 	.ndo_open		= iss_net_open,
579 	.ndo_stop		= iss_net_close,
580 	.ndo_get_stats		= iss_net_get_stats,
581 	.ndo_start_xmit		= iss_net_start_xmit,
582 	.ndo_validate_addr	= eth_validate_addr,
583 	.ndo_change_mtu		= iss_net_change_mtu,
584 	.ndo_set_mac_address	= iss_net_set_mac,
585 	//.ndo_do_ioctl		= iss_net_ioctl,
586 	.ndo_tx_timeout		= iss_net_tx_timeout,
587 	.ndo_set_rx_mode	= iss_net_set_multicast_list,
588 };
589 
590 static int iss_net_configure(int index, char *init)
591 {
592 	struct net_device *dev;
593 	struct iss_net_private *lp;
594 	int err;
595 
596 	if ((dev = alloc_etherdev(sizeof *lp)) == NULL) {
597 		printk(KERN_ERR "eth_configure: failed to allocate device\n");
598 		return 1;
599 	}
600 
601 	/* Initialize private element. */
602 
603 	lp = netdev_priv(dev);
604 	*lp = ((struct iss_net_private) {
605 		.device_list		= LIST_HEAD_INIT(lp->device_list),
606 		.opened_list		= LIST_HEAD_INIT(lp->opened_list),
607 		.lock			= __SPIN_LOCK_UNLOCKED(lp.lock),
608 		.dev			= dev,
609 		.index			= index,
610 		//.fd                   = -1,
611 		.mac			= { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
612 		.have_mac		= 0,
613 		});
614 
615 	/*
616 	 * Try all transport protocols.
617 	 * Note: more protocols can be added by adding '&& !X_init(lp, eth)'.
618 	 */
619 
620 	if (!tuntap_probe(lp, index, init)) {
621 		printk("Invalid arguments. Skipping device!\n");
622 		goto errout;
623 	}
624 
625 	printk(KERN_INFO "Netdevice %d ", index);
626 	if (lp->have_mac)
627 		printk("(%pM) ", lp->mac);
628 	printk(": ");
629 
630 	/* sysfs register */
631 
632 	if (!driver_registered) {
633 		platform_driver_register(&iss_net_driver);
634 		driver_registered = 1;
635 	}
636 
637 	spin_lock(&devices_lock);
638 	list_add(&lp->device_list, &devices);
639 	spin_unlock(&devices_lock);
640 
641 	lp->pdev.id = index;
642 	lp->pdev.name = DRIVER_NAME;
643 	platform_device_register(&lp->pdev);
644 	SET_NETDEV_DEV(dev,&lp->pdev.dev);
645 
646 	/*
647 	 * If this name ends up conflicting with an existing registered
648 	 * netdevice, that is OK, register_netdev{,ice}() will notice this
649 	 * and fail.
650 	 */
651 	snprintf(dev->name, sizeof dev->name, "eth%d", index);
652 
653 	dev->netdev_ops = &iss_netdev_ops;
654 	dev->mtu = lp->mtu;
655 	dev->watchdog_timeo = (HZ >> 1);
656 	dev->irq = -1;
657 
658 	rtnl_lock();
659 	err = register_netdevice(dev);
660 	rtnl_unlock();
661 
662 	if (err) {
663 		printk("Error registering net device!\n");
664 		/* XXX: should we call ->remove() here? */
665 		free_netdev(dev);
666 		return 1;
667 	}
668 
669 	init_timer(&lp->tl);
670 	lp->tl.function = iss_net_user_timer_expire;
671 
672 #if 0
673 	if (lp->have_mac)
674 		set_ether_mac(dev, lp->mac);
675 #endif
676 	return 0;
677 
678 errout:
679 	// FIXME: unregister; free, etc..
680 	return -EIO;
681 
682 }
683 
684 /* ------------------------------------------------------------------------- */
685 
686 /* Filled in during early boot */
687 
688 struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
689 
690 struct iss_net_init {
691 	struct list_head list;
692 	char *init;		/* init string */
693 	int index;
694 };
695 
696 /*
697  * Parse the command line and look for 'ethX=...' fields, and register all
698  * those fields. They will be later initialized in iss_net_init.
699  */
700 
701 #define ERR KERN_ERR "iss_net_setup: "
702 
703 static int __init iss_net_setup(char *str)
704 {
705 	struct iss_net_private *device = NULL;
706 	struct iss_net_init *new;
707 	struct list_head *ele;
708 	char *end;
709 	int n;
710 
711 	n = simple_strtoul(str, &end, 0);
712 	if (end == str) {
713 		printk(ERR "Failed to parse '%s'\n", str);
714 		return 1;
715 	}
716 	if (n < 0) {
717 		printk(ERR "Device %d is negative\n", n);
718 		return 1;
719 	}
720 	if (*(str = end) != '=') {
721 		printk(ERR "Expected '=' after device number\n");
722 		return 1;
723 	}
724 
725 	spin_lock(&devices_lock);
726 
727 	list_for_each(ele, &devices) {
728 		device = list_entry(ele, struct iss_net_private, device_list);
729 		if (device->index == n)
730 			break;
731 	}
732 
733 	spin_unlock(&devices_lock);
734 
735 	if (device && device->index == n) {
736 		printk(ERR "Device %d already configured\n", n);
737 		return 1;
738 	}
739 
740 	if ((new = alloc_bootmem(sizeof new)) == NULL) {
741 		printk("Alloc_bootmem failed\n");
742 		return 1;
743 	}
744 
745 	INIT_LIST_HEAD(&new->list);
746 	new->index = n;
747 	new->init = str + 1;
748 
749 	list_add_tail(&new->list, &eth_cmd_line);
750 	return 1;
751 }
752 
753 #undef ERR
754 
755 __setup("eth=", iss_net_setup);
756 
757 /*
758  * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
759  */
760 
761 static int iss_net_init(void)
762 {
763 	struct list_head *ele, *next;
764 
765 	/* Walk through all Ethernet devices specified in the command line. */
766 
767 	list_for_each_safe(ele, next, &eth_cmd_line) {
768 		struct iss_net_init *eth;
769 		eth = list_entry(ele, struct iss_net_init, list);
770 		iss_net_configure(eth->index, eth->init);
771 	}
772 
773 	return 1;
774 }
775 
776 module_init(iss_net_init);
777 
778