Example #1
0
/* drop from and add into a multicast group
 */
int
renew_multicast( int msockfd, const struct ip_mreq* mreq )
{
    int rc = 0;

    rc = set_multicast( msockfd, mreq, IP_DROP_MEMBERSHIP );
    if( 0 != rc ) return rc;

    rc = set_multicast( msockfd, mreq, IP_ADD_MEMBERSHIP );
    return rc;
}
Example #2
0
/* unsubscribe from multicast and close the reader socket
 */
void
close_mcast_listener( int msockfd, const struct ip_mreq* mreq )
{
    assert( mreq );

    if( msockfd <= 0 ) return;

    (void) set_multicast( msockfd, mreq, IP_DROP_MEMBERSHIP );
    (void) close( msockfd );

    TRACE( (void)tmfprintf( g_flog, "Mcast listener socket=[%d] closed\n",
                msockfd) );
    return;
}
Example #3
0
static int
rio_open (struct net_device *dev)
{
	struct netdev_private *np = netdev_priv(dev);
	void __iomem *ioaddr = np->ioaddr;
	const int irq = np->pdev->irq;
	int i;
	u16 macctrl;

	i = request_irq(irq, rio_interrupt, IRQF_SHARED, dev->name, dev);
	if (i)
		return i;

	/* Reset all logic functions */
	dw16(ASICCtrl + 2,
	     GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset);
	mdelay(10);

	/* DebugCtrl bit 4, 5, 9 must set */
	dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230);

	/* Jumbo frame */
	if (np->jumbo != 0)
		dw16(MaxFrameSize, MAX_JUMBO+14);

	alloc_list (dev);

	/* Get station address */
	for (i = 0; i < 6; i++)
		dw8(StationAddr0 + i, dev->dev_addr[i]);

	set_multicast (dev);
	if (np->coalesce) {
		dw32(RxDMAIntCtrl, np->rx_coalesce | np->rx_timeout << 16);
	}
	/* Set RIO to poll every N*320nsec. */
	dw8(RxDMAPollPeriod, 0x20);
	dw8(TxDMAPollPeriod, 0xff);
	dw8(RxDMABurstThresh, 0x30);
	dw8(RxDMAUrgentThresh, 0x30);
	dw32(RmonStatMask, 0x0007ffff);
	/* clear statistics */
	clear_stats (dev);

	/* VLAN supported */
	if (np->vlan) {
		/* priority field in RxDMAIntCtrl  */
		dw32(RxDMAIntCtrl, dr32(RxDMAIntCtrl) | 0x7 << 10);
		/* VLANId */
		dw16(VLANId, np->vlan);
		/* Length/Type should be 0x8100 */
		dw32(VLANTag, 0x8100 << 16 | np->vlan);
		/* Enable AutoVLANuntagging, but disable AutoVLANtagging.
		   VLAN information tagged by TFC' VID, CFI fields. */
		dw32(MACCtrl, dr32(MACCtrl) | AutoVLANuntagging);
	}

	setup_timer(&np->timer, rio_timer, (unsigned long)dev);
	np->timer.expires = jiffies + 1*HZ;
	add_timer (&np->timer);

	/* Start Tx/Rx */
	dw32(MACCtrl, dr32(MACCtrl) | StatsEnable | RxEnable | TxEnable);

	macctrl = 0;
	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
	dw16(MACCtrl, macctrl);

	netif_start_queue (dev);

	dl2k_enable_int(np);
	return 0;
}
Example #4
0
static int
rio_open (struct net_device *dev)
{
	struct netdev_private *np = netdev_priv(dev);
	long ioaddr = dev->base_addr;
	int i;
	u16 macctrl;

	i = request_irq (dev->irq, &rio_interrupt, IRQF_SHARED, dev->name, dev);
	if (i)
		return i;

	/* Reset all logic functions */
	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
		ioaddr + ASICCtrl + 2);
	mdelay(10);

	/* DebugCtrl bit 4, 5, 9 must set */
	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);

	/* Jumbo frame */
	if (np->jumbo != 0)
		writew (MAX_JUMBO+14, ioaddr + MaxFrameSize);

	alloc_list (dev);

	/* Get station address */
	for (i = 0; i < 6; i++)
		writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);

	set_multicast (dev);
	if (np->coalesce) {
		writel (np->rx_coalesce | np->rx_timeout << 16,
			ioaddr + RxDMAIntCtrl);
	}
	/* Set RIO to poll every N*320nsec. */
	writeb (0x20, ioaddr + RxDMAPollPeriod);
	writeb (0xff, ioaddr + TxDMAPollPeriod);
	writeb (0x30, ioaddr + RxDMABurstThresh);
	writeb (0x30, ioaddr + RxDMAUrgentThresh);
	writel (0x0007ffff, ioaddr + RmonStatMask);
	/* clear statistics */
	clear_stats (dev);

	/* VLAN supported */
	if (np->vlan) {
		/* priority field in RxDMAIntCtrl  */
		writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
			ioaddr + RxDMAIntCtrl);
		/* VLANId */
		writew (np->vlan, ioaddr + VLANId);
		/* Length/Type should be 0x8100 */
		writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
		/* Enable AutoVLANuntagging, but disable AutoVLANtagging.
		   VLAN information tagged by TFC' VID, CFI fields. */
		writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
			ioaddr + MACCtrl);
	}

	init_timer (&np->timer);
	np->timer.expires = jiffies + 1*HZ;
	np->timer.data = (unsigned long) dev;
	np->timer.function = &rio_timer;
	add_timer (&np->timer);

	/* Start Tx/Rx */
	writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
			ioaddr + MACCtrl);

	macctrl = 0;
	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
	writew(macctrl,	ioaddr + MACCtrl);

	netif_start_queue (dev);

	/* Enable default interrupts */
	EnableInt ();
	return 0;
}
Example #5
0
/* set up the socket to receive multicast data
 *
 */
int
setup_mcast_listener( struct sockaddr_in*   sa,
                      const struct ip_mreq* mreq,
                      int*                  mcastfd,
                      int                   sockbuflen )
{
    int sockfd, rc;
    int ON = 1;
    int buflen = sockbuflen;
    size_t rcvbuf_len = 0;

    assert( sa && mreq && mcastfd && (sockbuflen >= 0) );

    TRACE( (void)tmfprintf( g_flog, "Setting up multicast listener\n") );
    rc = ERR_INTERNAL;
    do {
        sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
        if( -1 == sockfd ) {
            mperror(g_flog, errno, "%s: socket", __func__);
            break;
        }

        if (buflen != 0) {
            rc = get_rcvbuf( sockfd, &rcvbuf_len );
            if (0 != rc) break;

            if ((size_t)buflen > rcvbuf_len) {
                rc = set_rcvbuf( sockfd, buflen );
                if (0 != rc) break;
            }
        }
        else {
            TRACE( (void)tmfprintf( g_flog, "Must not adjust buffer size "
                                            "for mcast socket [%d]\n", sockfd ) );
        }

        rc = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
                         &ON, sizeof(ON) );
        if( 0 != rc ) {
            mperror(g_flog, errno, "%s: setsockopt SO_REUSEADDR",
                    __func__);
            break;
        }

#ifdef SO_REUSEPORT
        /*  On some systems (such as FreeBSD) SO_REUSEADDR
            just isn't enough to subscribe to N same channels for different clients.
        */
        rc = setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT,
                         &ON, sizeof(ON) );
        if( 0 != rc ) {
            mperror(g_flog, errno, "%s: setsockopt SO_REUSEPORT",
                    __func__);
            break;
        }
#endif /* SO_REUSEPORT */

        rc = bind( sockfd, (struct sockaddr*)sa, sizeof(*sa) );
        if( 0 != rc ) {
            mperror(g_flog, errno, "%s: bind", __func__);
            break;
        }

        rc = set_multicast( sockfd, mreq, IP_ADD_MEMBERSHIP );
        if( 0 != rc )
            break;
    } while(0);

    if( 0 == rc ) {
        *mcastfd = sockfd;
        TRACE( (void)tmfprintf( g_flog, "Mcast listener socket=[%d] set up\n",
                                sockfd) );
    }
    else {
        (void)close(sockfd);
    }

    return rc;
}
Example #6
0
/* main function */
int main(int argc, char *argv[])
{
	int			opt, retval = 0;
	struct sockaddr_in	si, wsd_mcast;
	uuid_t			uuid;
	char 			uuid_str[37];
	struct sigaction	act;
	static const int 	enable = 1;
	int			out_len;
	int			conn, clients, i, activity;
	struct pollfd		fds[MAX_CLIENTS+3];
	char			iface[32] = "";
	struct 			in_addr iface_addr;

	gethostname(cd_name, sizeof(cd_name));
	iface_addr.s_addr = INADDR_ANY;

	/* process command line options */
	while ((opt = getopt(argc, argv, "dhFIn:w:i:")) != -1) {
		switch (opt) {

		case 'd':
			loglevel = LOG_DEBUG;
			asdaemon = 0;
			usesyslog = 0;
			break;

		case 'F':
			asdaemon = 0;
			break;

		case 'I':
			usesyslog = 0;
			break;

		case 'i':
			strncpy(iface, optarg, sizeof(iface));
			break;

		case 'n':
			strncpy(cd_name, optarg, sizeof(cd_name));
			break;

		case 'w':
			strncpy(cd_workgroup, optarg, sizeof(cd_workgroup));
			break;

		case 'h':
			printf("usage: wsdd [-d (debug)] [-I (interactive) [-F (foreground)]\n"
			       "            [-h] [-n hostname] [-w workgroup] [-i ip]\n");
			return(0);
		}
	}

	if (*iface)
		if (inet_aton(iface, &iface_addr) == 0) {
			wsdd_log(LOG_ERR, "Invalid interface address %s", iface);
			return 1;
		}

	/* Set signal handler for graceful shutdown */
	memset(&act, 0, sizeof(act));
 	act.sa_sigaction = &sigterm_handler;
	act.sa_flags = SA_SIGINFO;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	
	if (asdaemon)
		daemonize();

	if (usesyslog)
		openlog("wsdd", LOG_PID, LOG_DAEMON);

	/* Generate UUIDs */
	instance_id = time(NULL);
	uuid_generate_time(uuid);
	uuid_unparse(uuid, uuid_str);
	sprintf(endpoint, "urn:uuid:%s", uuid_str);
	uuid_generate_time(uuid);
	uuid_unparse(uuid, uuid_str);
	sprintf(sequence, "urn:uuid:%s", uuid_str);

	memset((char *) &wsd_mcast, 0, sizeof(wsd_mcast));
	wsd_mcast.sin_family = AF_INET;
	wsd_mcast.sin_port = htons(WSD_PORT);
	if (inet_aton(WSD_MCAST_ADDR, &wsd_mcast.sin_addr) == 0) {
		wsdd_log(LOG_ERR, "inet_aton() failed for wsd multicast address");
		return 1;
	}

	/* Prepare LLMNR socket */
	fds[LLMNR_UDP_SOCK].fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fds[LLMNR_UDP_SOCK].fd == -1) {
		wsdd_log(LOG_ERR, "Failed to create socket, %s", strerror(errno));
		return 1;
	}
	setsockopt(fds[LLMNR_UDP_SOCK].fd, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));

	memset((char *) &si, 0, sizeof(si));
	si.sin_family = AF_INET;
	si.sin_port = htons(LLMNR_PORT);
	si.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(fds[LLMNR_UDP_SOCK].fd, (const struct sockaddr*)&si, sizeof(si)) == -1) {
		wsdd_log(LOG_ERR, "Failed to listen to UDP port %d for LLMNR", ntohs(si.sin_port));
		retval = 1;
		goto llmnr_udp_close;
	}	

	if (set_multicast(fds[LLMNR_UDP_SOCK].fd, LLMNR_MCAST_ADDR, &iface_addr, IP_ADD_MEMBERSHIP)) {
		wsdd_log(LOG_ERR, "Failed to add multicast for LLMNR: %s", strerror(errno));
		retval = 1;
		goto llmnr_drop_multicast;
	}

	fds[WSD_UDP_SOCK].fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fds[WSD_UDP_SOCK].fd == -1) {
		wsdd_log(LOG_ERR, "Failed to create socket for wsdd");
		retval = 1;
		goto llmnr_drop_multicast;
	}
	setsockopt(fds[WSD_UDP_SOCK].fd, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));

	memset((char *) &si, 0, sizeof(si));
	si.sin_family = AF_INET;
	si.sin_port = htons(WSD_PORT);
	si.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(fds[WSD_UDP_SOCK].fd, (const struct sockaddr*)&si, sizeof(si)) == -1) {
		wsdd_log(LOG_ERR, "Failed to listen to UDP port %d for WSDD", ntohs(si.sin_port));
		retval = 1;
		goto wsd_udp_close;
	}

	if (set_multicast(fds[WSD_UDP_SOCK].fd, WSD_MCAST_ADDR, &iface_addr, IP_ADD_MEMBERSHIP)) {
		wsdd_log(LOG_ERR, "Failed to add multicast for WSDD: %s", strerror(errno));
		retval = 1;
		goto wsd_drop_multicast;
	}

	fds[WSD_HTTP_SOCK].fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fds[WSD_HTTP_SOCK].fd == -1) {
		wsdd_log(LOG_ERR, "Failed to create http socket");
		retval = 1;
		goto wsd_drop_multicast;
	}	
	setsockopt(fds[WSD_HTTP_SOCK].fd, SOL_SOCKET, SO_REUSEADDR, &enable , sizeof(enable));

	memset((char *) &si, 0, sizeof(si));
	si.sin_family = AF_INET;
	si.sin_port = htons(WSD_HTTP_PORT);
	si.sin_addr = iface_addr;
	if (bind(fds[WSD_HTTP_SOCK].fd, (const struct sockaddr*)&si, sizeof(si)) < 0) {
		wsdd_log(LOG_ERR, "Failed to listen to HTTP port %d", WSD_HTTP_PORT);
		retval = 1;
		goto wsd_http_close;
	}	

	if (listen(fds[WSD_HTTP_SOCK].fd, 5) < 0) {
		wsdd_log(LOG_ERR, "Failed to listen to HTTP port %d", WSD_HTTP_PORT);
		retval = 1;
		goto wsd_http_close;
	}

	/* Send hello message */
	out_len = sizeof(out);
	action_hello(out, &out_len, wsd_device, 0);
	if (udp_send_all(fds[WSD_UDP_SOCK].fd, &iface_addr, (const struct sockaddr*)&wsd_mcast, sizeof(wsd_mcast), out_len) == -1) {
		wsdd_log(LOG_ERR, "Failed to send hello with %d", errno);
		retval = 1;
		goto wsd_http_close;
	}

	clients = 0;
	fds[WSD_HTTP_SOCK].events = POLLIN;
	fds[WSD_UDP_SOCK].events = POLLIN;
	fds[LLMNR_UDP_SOCK].events = POLLIN;
	
	while(!terminate) {
		activity = poll(fds , 3 + clients, -1);
		if (activity == -1) {
			if (errno != EINTR)
				wsdd_log(LOG_ERR, "Select failed");
			continue;
		}
		
		if (fds[WSD_HTTP_SOCK].revents & POLLIN) {
			conn = accept(fds[WSD_HTTP_SOCK].fd, NULL, NULL);
			if (conn < 0)
				continue;
			if (clients < MAX_CLIENTS) {
				fds[3+clients].fd = conn;
				fds[3+clients].events = POLLIN;
				fds[3+clients].revents = 0;
				clients++;
			} else
				close(conn);
			--activity;
			if (!activity)
				continue;
		}

		if (fds[WSD_UDP_SOCK].revents & POLLIN) {
			wsd_udp_request(fds[WSD_UDP_SOCK].fd);
			--activity;
			if (!activity)
				continue;
		}

		if (fds[LLMNR_UDP_SOCK].revents & POLLIN) {
			llmnr_udp_request(fds[LLMNR_UDP_SOCK].fd);
			--activity;
			if (!activity)
				continue;
		}

		i = 0;
		while (i<clients && activity) {
			if (fds[3+i].revents & POLLIN) {
				conn = fds[3+i].fd;
				wsdd_http_request(conn);
				shutdown(conn, SHUT_RDWR);
				close(conn);
				--clients;
				--activity;
				fds[3+i] = fds[3+clients];
			} else
				i++;
		}
	}

	/* Send bye message */
	out_len = sizeof(out);
	action_bye(out, &out_len, wsd_device, 0);
	if (udp_send_all(fds[WSD_UDP_SOCK].fd, &iface_addr, (const struct sockaddr*)&wsd_mcast, sizeof(wsd_mcast), out_len) == -1) {
		wsdd_log(LOG_ERR, "Failed to send bye with %d", errno);
		retval = 1;
	}

wsd_http_close:	
	shutdown(fds[WSD_HTTP_SOCK].fd, SHUT_RDWR);
	close(fds[WSD_HTTP_SOCK].fd);

wsd_drop_multicast:
	set_multicast(fds[WSD_UDP_SOCK].fd, WSD_MCAST_ADDR, &iface_addr, IP_DROP_MEMBERSHIP);

wsd_udp_close:
	shutdown(fds[WSD_UDP_SOCK].fd, SHUT_RDWR);
	close(fds[WSD_UDP_SOCK].fd);
	
llmnr_drop_multicast:
	set_multicast(fds[LLMNR_UDP_SOCK].fd, LLMNR_MCAST_ADDR, &iface_addr, IP_DROP_MEMBERSHIP);

llmnr_udp_close:
	shutdown(fds[LLMNR_UDP_SOCK].fd, SHUT_RDWR);
	close(fds[LLMNR_UDP_SOCK].fd);

	if (asdaemon)
		closelog();

	return retval;
}
Example #7
0
File: dl2k.c Project: Lyude/linux
static void rio_hw_init(struct net_device *dev)
{
	struct netdev_private *np = netdev_priv(dev);
	void __iomem *ioaddr = np->ioaddr;
	int i;
	u16 macctrl;

	/* Reset all logic functions */
	dw16(ASICCtrl + 2,
	     GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset);
	mdelay(10);

	rio_set_led_mode(dev);

	/* DebugCtrl bit 4, 5, 9 must set */
	dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230);

	if (np->chip_id == CHIP_IP1000A &&
	    (np->pdev->revision == 0x40 || np->pdev->revision == 0x41)) {
		/* PHY magic taken from ipg driver, undocumented registers */
		mii_write(dev, np->phy_addr, 31, 0x0001);
		mii_write(dev, np->phy_addr, 27, 0x01e0);
		mii_write(dev, np->phy_addr, 31, 0x0002);
		mii_write(dev, np->phy_addr, 27, 0xeb8e);
		mii_write(dev, np->phy_addr, 31, 0x0000);
		mii_write(dev, np->phy_addr, 30, 0x005e);
		/* advertise 1000BASE-T half & full duplex, prefer MASTER */
		mii_write(dev, np->phy_addr, MII_CTRL1000, 0x0700);
	}

	if (np->phy_media)
		mii_set_media_pcs(dev);
	else
		mii_set_media(dev);

	/* Jumbo frame */
	if (np->jumbo != 0)
		dw16(MaxFrameSize, MAX_JUMBO+14);

	/* Set RFDListPtr */
	dw32(RFDListPtr0, np->rx_ring_dma);
	dw32(RFDListPtr1, 0);

	/* Set station address */
	/* 16 or 32-bit access is required by TC9020 datasheet but 8-bit works
	 * too. However, it doesn't work on IP1000A so we use 16-bit access.
	 */
	for (i = 0; i < 3; i++)
		dw16(StationAddr0 + 2 * i,
		     cpu_to_le16(((u16 *)dev->dev_addr)[i]));

	set_multicast (dev);
	if (np->coalesce) {
		dw32(RxDMAIntCtrl, np->rx_coalesce | np->rx_timeout << 16);
	}
	/* Set RIO to poll every N*320nsec. */
	dw8(RxDMAPollPeriod, 0x20);
	dw8(TxDMAPollPeriod, 0xff);
	dw8(RxDMABurstThresh, 0x30);
	dw8(RxDMAUrgentThresh, 0x30);
	dw32(RmonStatMask, 0x0007ffff);
	/* clear statistics */
	clear_stats (dev);

	/* VLAN supported */
	if (np->vlan) {
		/* priority field in RxDMAIntCtrl  */
		dw32(RxDMAIntCtrl, dr32(RxDMAIntCtrl) | 0x7 << 10);
		/* VLANId */
		dw16(VLANId, np->vlan);
		/* Length/Type should be 0x8100 */
		dw32(VLANTag, 0x8100 << 16 | np->vlan);
		/* Enable AutoVLANuntagging, but disable AutoVLANtagging.
		   VLAN information tagged by TFC' VID, CFI fields. */
		dw32(MACCtrl, dr32(MACCtrl) | AutoVLANuntagging);
	}

	/* Start Tx/Rx */
	dw32(MACCtrl, dr32(MACCtrl) | StatsEnable | RxEnable | TxEnable);

	macctrl = 0;
	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
	dw16(MACCtrl, macctrl);
}
Example #8
0
static int
rio_open (struct net_device *dev)
{
	struct netdev_private *np = netdev_priv(dev);
	long ioaddr = dev->base_addr;
	int i;
	u16 macctrl;

	i = request_irq (dev->irq, rio_interrupt, IRQF_SHARED, dev->name, dev);
	if (i)
		return i;

	/*                           */
	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
		ioaddr + ASICCtrl + 2);
	mdelay(10);

	/*                                */
	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);

	/*             */
	if (np->jumbo != 0)
		writew (MAX_JUMBO+14, ioaddr + MaxFrameSize);

	alloc_list (dev);

	/*                     */
	for (i = 0; i < 6; i++)
		writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);

	set_multicast (dev);
	if (np->coalesce) {
		writel (np->rx_coalesce | np->rx_timeout << 16,
			ioaddr + RxDMAIntCtrl);
	}
	/*                                  */
	writeb (0x20, ioaddr + RxDMAPollPeriod);
	writeb (0xff, ioaddr + TxDMAPollPeriod);
	writeb (0x30, ioaddr + RxDMABurstThresh);
	writeb (0x30, ioaddr + RxDMAUrgentThresh);
	writel (0x0007ffff, ioaddr + RmonStatMask);
	/*                  */
	clear_stats (dev);

	/*                */
	if (np->vlan) {
		/*                                 */
		writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
			ioaddr + RxDMAIntCtrl);
		/*        */
		writew (np->vlan, ioaddr + VLANId);
		/*                              */
		writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
		/*                                                       
                                                      */
		writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
			ioaddr + MACCtrl);
	}

	init_timer (&np->timer);
	np->timer.expires = jiffies + 1*HZ;
	np->timer.data = (unsigned long) dev;
	np->timer.function = rio_timer;
	add_timer (&np->timer);

	/*             */
	writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
			ioaddr + MACCtrl);

	macctrl = 0;
	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
	writew(macctrl,	ioaddr + MACCtrl);

	netif_start_queue (dev);

	/*                           */
	EnableInt ();
	return 0;
}