⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snull.c

📁 本源码是将述嵌入式LINUX驱动程序例程
💻 C
📖 第 1 页 / 共 2 页
字号:
     * Ethhdr is 14 bytes, but the kernel arranges for iphdr
     * to be aligned (i.e., ethhdr is unaligned)
     */
    ih = (struct iphdr *)(buf+sizeof(struct ethhdr));
    saddr = &ih->saddr;
    daddr = &ih->daddr;

    ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */
    ((u8 *)daddr)[2] ^= 1;

    ih->check = 0;         /* and rebuild the checksum (ip needs it) */
    ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);

    if (dev == snull_devs)
        PDEBUGG("%08x:%05i --> %08x:%05i\n",
               ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source),
               ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest));
    else
        PDEBUGG("%08x:%05i <-- %08x:%05i\n",
               ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest),
               ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source));

    /*
     * Ok, now the packet is ready for transmission: first simulate a
     * receive interrupt on the twin device, then  a
     * transmission-done on the transmitting device
     */
    dest = snull_devs + (dev==snull_devs ? 1 : 0);
    priv = (struct snull_priv *) dest->priv;
    priv->status = SNULL_RX_INTR;
    priv->rx_packetlen = len;
    priv->rx_packetdata = buf;
    snull_interrupt(0, dest, NULL);

    priv = (struct snull_priv *) dev->priv;
    priv->status = SNULL_TX_INTR;
    priv->tx_packetlen = len;
    priv->tx_packetdata = buf;
    if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) {
        /* Simulate a dropped transmit interrupt */
        netif_stop_queue(dev);
        PDEBUG("Simulate lockup at %ld, txp %ld\n", jiffies,
                        (unsigned long) priv->stats.tx_packets);
    }
    else
        snull_interrupt(0, dev, NULL);
}

/*
 * Transmit a packet (called by the kernel)
 */
int snull_tx(struct sk_buff *skb, struct net_device *dev)
{
    int len;
    char *data;
    struct snull_priv *priv = (struct snull_priv *) dev->priv;

#ifndef LINUX_24
    if (dev->tbusy || skb == NULL) {
        PDEBUG("tint for %p, tbusy %ld, skb %p\n", dev, dev->tbusy, skb);
        snull_tx_timeout (dev);
        if (skb == NULL)
            return 0;
    }
#endif

    len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
    data = skb->data;
    dev->trans_start = jiffies; /* save the timestamp */

    /* Remember the skb, so we can free it at interrupt time */
    priv->skb = skb;

    /* actual deliver of data is device-specific, and not shown here */
    snull_hw_tx(data, len, dev);

    return 0; /* Our simple device can not fail */
}

/*
 * Deal with a transmit timeout.
 */
void snull_tx_timeout (struct net_device *dev)
{
    struct snull_priv *priv = (struct snull_priv *) dev->priv;

    PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies,
                    jiffies - dev->trans_start);
    priv->status = SNULL_TX_INTR;
    snull_interrupt(0, dev, NULL);
    priv->stats.tx_errors++;
    netif_wake_queue(dev);
    return;
}



/*
 * Ioctl commands 
 */
int snull_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
 
    PDEBUG("ioctl\n");
    return 0;
}

/*
 * Return statistics to the caller
 */
struct net_device_stats *snull_stats(struct net_device *dev)
{
    struct snull_priv *priv = (struct snull_priv *) dev->priv;
    return &priv->stats;
}

/*
 * This function is called to fill up an eth header, since arp is not
 * available on the interface
 */
#ifndef LINUX_20
int snull_rebuild_header(struct sk_buff *skb)
{
    struct ethhdr *eth = (struct ethhdr *) skb->data;
    struct net_device *dev = skb->dev;
    
    memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
    memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
    eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
    return 0;
}
#else /* LINUX_20 */
int snull_rebuild_header(void *buff, struct net_device *dev, unsigned long dst,
                    struct sk_buff *skb)
{
    struct ethhdr *eth = (struct ethhdr *)buff;

    memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
    memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
    eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
    return 0;
}
#endif /* LINUX_20 */


int snull_header(struct sk_buff *skb, struct net_device *dev,
                unsigned short type, void *daddr, void *saddr,
                unsigned int len)
{
    struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);

    eth->h_proto = htons(type);
    memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
    memcpy(eth->h_dest,   daddr ? daddr : dev->dev_addr, dev->addr_len);
    eth->h_dest[ETH_ALEN-1]   ^= 0x01;   /* dest is us xor 1 */
    return (dev->hard_header_len);
}





/*
 * The "change_mtu" method is usually not needed.
 * If you need it, it must be like this.
 */
int snull_change_mtu(struct net_device *dev, int new_mtu)
{
    unsigned long flags;
    spinlock_t *lock = &((struct snull_priv *) dev->priv)->lock;
    
    /* check ranges */
    if ((new_mtu < 68) || (new_mtu > 1500))
        return -EINVAL;
    /*
     * Do anything you need, and the accept the value
     */
    spin_lock_irqsave(lock, flags);
    dev->mtu = new_mtu;
    spin_unlock_irqrestore(lock, flags);
    return 0; /* success */
}

/*
 * The init function (sometimes called probe).
 * It is invoked by register_netdev()
 */
int snull_init(struct net_device *dev)
{
#if 0
    /*
     * Make the usual checks: check_region(), probe irq, ...  -ENODEV
     * should be returned if no device found.  No resource should be
     * grabbed: this is done on open(). 
     */
#endif

    /* 
     * Then, assign other fields in dev, using ether_setup() and some
     * hand assignments
     */
    ether_setup(dev); /* assign some of the fields */

    dev->open            = snull_open;
    dev->stop            = snull_release;
    dev->set_config      = snull_config;
    dev->hard_start_xmit = snull_tx;
    dev->do_ioctl        = snull_ioctl;
    dev->get_stats       = snull_stats;
    dev->change_mtu      = snull_change_mtu;  
    dev->rebuild_header  = snull_rebuild_header;
    dev->hard_header     = snull_header;
#ifdef HAVE_TX_TIMEOUT
    dev->tx_timeout     = snull_tx_timeout;
    dev->watchdog_timeo = timeout;
#endif
    /* keep the default flags, just add NOARP */
    dev->flags           |= IFF_NOARP;
#ifndef LINUX_20                        
    dev->hard_header_cache = NULL;      /* Disable caching */
#endif                                  
    SET_MODULE_OWNER(dev);

    /*
     * Then, allocate the priv field. This encloses the statistics
     * and a few private fields.
     */
    dev->priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL);
    if (dev->priv == NULL)
        return -ENOMEM;
    memset(dev->priv, 0, sizeof(struct snull_priv));
    spin_lock_init(& ((struct snull_priv *) dev->priv)->lock);
    return 0;
}

/*
 * The devices
 */

#ifdef LINUX_24
struct net_device snull_devs[2] = {
    { init: snull_init, },  /* init, nothing more */
    { init: snull_init, }
};
#else /* pre-2.4 */
char snull_names[16];

struct net_device snull_devs[2] = {
    {
        name: snull_names,
        init: snull_init,  /* init function */
    },
    {
        name: snull_names+8,
        init: snull_init,            /* init function */
    }
};
#endif /* LINUX_24 */



/*
 * Finally, the module stuff
 */

int snull_init_module(void)
{

    int result, i, device_present = 0;

    snull_eth = eth; /* copy the cfg datum in the non-static place */

    if (!snull_eth) { /* call them "sn0" and "sn1" */
        strcpy(snull_devs[0].name, "sn0");
        strcpy(snull_devs[1].name, "sn1");
    } else { /* use automatic assignment */
#ifdef LINUX_24                                                 
        strcpy(snull_devs[0].name, "eth%d");
        strcpy(snull_devs[1].name, "eth%d");
#else                                                           
        snull_devs[0].name[0] = snull_devs[1].name[0] = ' ';    
#endif                                                          
    }

    for (i=0; i<2;  i++)
        if ( (result = register_netdev(snull_devs + i)) )
            printk("snull: error %i registering device \"%s\"\n",
                   result, snull_devs[i].name);
        else device_present++;
#ifndef SNULL_DEBUG
    EXPORT_NO_SYMBOLS;
#endif

    return device_present ? 0 : -ENODEV;
}

void snull_cleanup(void)
{
    int i;
   
    for (i=0; i<2;  i++) {
        kfree(snull_devs[i].priv);
        unregister_netdev(snull_devs + i);
    }
    return;
}


module_init(snull_init_module);
module_exit(snull_cleanup);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -