📄 hamachi.c
字号:
skb_reserve(skb, 2); /* 16 byte align the IP header */ /* Call copy + cksum if available. */#if 1 || USE_IP_COPYSUM eth_copy_and_sum(skb, bus_to_virt(desc->addr), pkt_len, 0); skb_put(skb, pkt_len);#else memcpy(skb_put(skb, pkt_len), bus_to_virt(desc->addr),pkt_len);#endif } else { char *temp = skb_put(skb = hmp->rx_skbuff[entry], pkt_len); hmp->rx_skbuff[entry] = NULL;#ifndef final_version /* Remove after testing. */ if (bus_to_virt(desc->addr) != temp) printk(KERN_ERR "%s: Internal fault: The skbuff addresses " "do not match in hamachi_rx: %p vs. %p / %p.\n", dev->name, bus_to_virt(desc->addr), skb->head, temp);#else (void) temp;#endif }#ifdef TX_CHECKSUM /* account for extra TX hard_header bytes */ skb->protocol = hamachi_eth_type_trans(skb, dev);#else skb->protocol = eth_type_trans(skb, dev);#endif#ifdef RX_CHECKSUM /* TCP or UDP on ipv4, DIX encoding */ if (pfck>>24 == 0x91 || pfck>>24 == 0x51) { struct iphdr *ih = (struct iphdr *) skb->data; /* Check that IP packet is at least 46 bytes, otherwise, * there may be pad bytes included in the hardware checksum. * This wouldn't happen if everyone padded with 0. */ if (ntohs(ih->tot_len) >= 46){ /* don't worry about frags */ if (!(ih->frag_off & __constant_htons(IP_MF|IP_OFFSET))) { u32 inv = *(u32 *) &buf_addr[data_size - 16]; u32 *p = (u32 *) &buf_addr[data_size - 20]; register u32 crc, p_r, p_r1; if (inv & 4) { inv &= ~4; --p; } p_r = *p; p_r1 = *(p-1); switch (inv) { case 0: crc = (p_r & 0xffff) + (p_r >> 16); break; case 1: crc = (p_r >> 16) + (p_r & 0xffff) + (p_r1 >> 16 & 0xff00); break; case 2: crc = p_r + (p_r1 >> 16); break; case 3: crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); break; default: /*NOTREACHED*/ crc = 0; } if (crc & 0xffff0000) { crc &= 0xffff; ++crc; } /* tcp/udp will add in pseudo */ skb->csum = ntohs(pfck & 0xffff); if (skb->csum > crc) skb->csum -= crc; else skb->csum += (~crc & 0xffff); /* * could do the pseudo myself and return * CHECKSUM_UNNECESSARY */ skb->ip_summed = CHECKSUM_HW; } } }#endif /* RX_CHECKSUM */ netif_rx(skb); dev->last_rx = jiffies; hmp->stats.rx_packets++; } entry = (++hmp->cur_rx) % RX_RING_SIZE; hmp->rx_head_desc = &hmp->rx_ring[entry]; } /* Refill the Rx ring buffers. */ for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { struct sk_buff *skb; entry = hmp->dirty_rx % RX_RING_SIZE; if (hmp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(hmp->rx_buf_sz); hmp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ hmp->rx_ring[entry].addr = virt_to_desc(skb->tail); } hmp->rx_ring[entry].status_n_length = cpu_to_le32(hmp->rx_buf_sz); if (entry >= RX_RING_SIZE-1) hmp->rx_ring[entry].status_n_length |= cpu_to_le32(DescOwn | DescEndPacket | DescEndRing | DescIntr); else hmp->rx_ring[entry].status_n_length |= cpu_to_le32(DescOwn | DescEndPacket | DescIntr); } /* Restart Rx engine if stopped. */ /* If we don't need to check status, don't. -KDU */ if (readw(dev->base_addr + RxStatus) & 0x0002) writew(0x0001, dev->base_addr + RxCmd); return 0;}/* This is more properly named "uncommon interrupt events", as it covers more than just errors. */static void hamachi_error(struct net_device *dev, int intr_status){ long ioaddr = dev->base_addr; struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; if (intr_status & (LinkChange|NegotiationChange)) { if (hamachi_debug > 1) printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl" " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n", dev->name, readw(ioaddr + 0x0E0), readw(ioaddr + 0x0E2), readw(ioaddr + ANLinkPartnerAbility), readl(ioaddr + IntrStatus)); if (readw(ioaddr + ANStatus) & 0x20) writeb(0x01, ioaddr + LEDCtrl); else writeb(0x03, ioaddr + LEDCtrl); } if (intr_status & StatsMax) { hamachi_get_stats(dev); /* Read the overflow bits to clear. */ readl(ioaddr + 0x370); readl(ioaddr + 0x3F0); } if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) && hamachi_debug) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) hmp->stats.tx_fifo_errors++; if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) hmp->stats.rx_fifo_errors++;}static int hamachi_close(struct net_device *dev){ long ioaddr = dev->base_addr; struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; int i; netif_stop_queue(dev); if (hamachi_debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", dev->name, readw(ioaddr + TxStatus), readw(ioaddr + RxStatus), readl(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx, hmp->dirty_rx); } /* Disable interrupts by clearing the interrupt mask. */ writel(0x0000, ioaddr + InterruptEnable); /* Stop the chip's Tx and Rx processes. */ writel(2, ioaddr + RxCmd); writew(2, ioaddr + TxCmd);#ifdef __i386__ if (hamachi_debug > 2) { printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)virt_to_bus(hmp->tx_ring)); for (i = 0; i < TX_RING_SIZE; i++) printk(" %c #%d desc. %8.8x %8.8x.\n", readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", (int)virt_to_bus(hmp->rx_ring)); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n", readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); if (hamachi_debug > 6) { if (*(u8*)bus_to_virt(hmp->rx_ring[i].addr) != 0x69) { int j; for (j = 0; j < 0x50; j++) printk(" %4.4x",((u16*)le32desc_to_virt(hmp->rx_ring[i].addr))[j]); printk("\n"); } } } }#endif /* __i386__ debugging only */ free_irq(dev->irq, dev); del_timer_sync(&hmp->timer); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { hmp->rx_ring[i].status_n_length = 0; hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (hmp->rx_skbuff[i]) { dev_kfree_skb(hmp->rx_skbuff[i]); } hmp->rx_skbuff[i] = 0; } for (i = 0; i < TX_RING_SIZE; i++) { if (hmp->tx_skbuff[i]) dev_kfree_skb(hmp->tx_skbuff[i]); hmp->tx_skbuff[i] = 0; } writeb(0x00, ioaddr + LEDCtrl); return 0;}static struct net_device_stats *hamachi_get_stats(struct net_device *dev){ long ioaddr = dev->base_addr; struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are non-critical. */ /* Ok, what goes here? This appears to be stuck at 21 packets according to ifconfig. It does get incremented in hamachi_tx(), so I think I'll comment it out here and see if better things happen. */ /* hmp->stats.tx_packets = readl(ioaddr + 0x000); */ hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */ hmp->stats.tx_bytes = readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */ hmp->stats.multicast = readl(ioaddr + 0x320); /* Multicast Rx */ hmp->stats.rx_length_errors = readl(ioaddr + 0x368); /* Over+Undersized */ hmp->stats.rx_over_errors = readl(ioaddr + 0x35C); /* Jabber */ hmp->stats.rx_crc_errors = readl(ioaddr + 0x360); /* Jabber */ hmp->stats.rx_frame_errors = readl(ioaddr + 0x364); /* Symbol Errs */ hmp->stats.rx_missed_errors = readl(ioaddr + 0x36C); /* Dropped */ return &hmp->stats;}static void set_rx_mode(struct net_device *dev){ long ioaddr = dev->base_addr; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); writew(0x000F, ioaddr + AddrMode); } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ writew(0x000B, ioaddr + AddrMode); } else if (dev->mc_count > 0) { /* Must use the CAM filter. */ struct dev_mc_list *mclist; int i; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8); writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]), ioaddr + 0x104 + i*8); } /* Clear remaining entries. */ for (; i < 64; i++) writel(0, ioaddr + 0x104 + i*8); writew(0x0003, ioaddr + AddrMode); } else { /* Normal, unicast/broadcast-only mode. */ writew(0x0001, ioaddr + AddrMode); }}#ifdef HAVE_PRIVATE_IOCTLstatic int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ /* TODO: Check the sequencing of this. Might need to stop and * restart Rx and Tx engines. -KDU */ if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */ u32 *d = (u32 *)&rq->ifr_data; /* Should add this check here or an ordinary user can do nasty * things. -KDU * * TODO: Shut down the Rx and Tx engines while doing this. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; writel(d[0], dev->base_addr + TxIntrCtrl); writel(d[1], dev->base_addr + RxIntrCtrl); printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name, (u32) readl(dev->base_addr + TxIntrCtrl), (u32) readl(dev->base_addr + RxIntrCtrl)); return 0; } default: return -EOPNOTSUPP; }}#endif /* HAVE_PRIVATE_IOCTL */static void __exit hamachi_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { unregister_netdev(dev); iounmap((char *)dev->base_addr); kfree(dev); pci_set_drvdata(pdev, NULL); }}static struct pci_device_id hamachi_pci_tbl[] __initdata = { { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }};MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl);static struct pci_driver hamachi_driver = { name: "hamachi", id_table: hamachi_pci_tbl, probe: hamachi_init_one, remove: hamachi_remove_one,};static int __init hamachi_init (void){ if (pci_register_driver(&hamachi_driver) > 0) return 0; pci_unregister_driver(&hamachi_driver); return -ENODEV;}static void __exit hamachi_exit (void){ pci_unregister_driver(&hamachi_driver);}module_init(hamachi_init);module_exit(hamachi_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -