/* 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; }
/* 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; }
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; }
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; }
/* 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; }
/* 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; }
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); }
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; }