/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
* James Leu (jleu@mindspring.net).
* Copyright (C) 2001 by various other people who didn't put their name here.
* Licensed under the GPL.
*/
#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/netdevice.h"
#include "linux/rtnetlink.h"
#include "linux/skbuff.h"
#include "linux/socket.h"
#include "linux/spinlock.h"
#include "linux/module.h"
#include "linux/init.h"
#include "linux/etherdevice.h"
#include "linux/list.h"
#include "linux/inetdevice.h"
#include "linux/ctype.h"
#include "linux/bootmem.h"
#include "linux/ethtool.h"
#include "asm/uaccess.h"
#include "user_util.h"
#include "kern_util.h"
#include "net_kern.h"
#include "net_user.h"
#include "mconsole_kern.h"
#include "init.h"
#include "irq_user.h"
#include "irq_kern.h"
#define DRIVER_NAME "uml-netdev"
static DEFINE_SPINLOCK(opened_lock);
LIST_HEAD(opened);
static int uml_net_rx(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
int pkt_len;
struct sk_buff *skb;
/* If we can't allocate memory, try again next round. */
skb = dev_alloc_skb(dev->mtu);
if (skb == NULL) {
lp->stats.rx_dropped++;
return 0;
}
skb->dev = dev;
skb_put(skb, dev->mtu);
skb->mac.raw = skb->data;
pkt_len = (*lp->read)(lp->fd, &skb, lp);
if (pkt_len > 0) {
skb_trim(skb, pkt_len);
skb->protocol = (*lp->protocol)(skb);
netif_rx(skb);
lp->stats.rx_bytes += skb->len;
lp->stats.rx_packets++;
return pkt_len;
}
kfree_skb(skb);
return pkt_len;
}
irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct uml_net_private *lp = dev->priv;
int err;
if(!netif_running(dev))
return(IRQ_NONE);
spin_lock(&lp->lock);
while((err = uml_net_rx(dev)) > 0) ;
if(err < 0) {
printk(KERN_ERR
"Device '%s' read returned %d, shutting it down\n",
dev->name, err);
dev_close(dev);
goto out;
}
reactivate_fd(lp->fd, UM_ETH_IRQ);
out:
spin_unlock(&lp->lock);
return(IRQ_HANDLED);
}
static int uml_net_open(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
char addr[sizeof("255.255.255.255\0")];
int err;
spin_lock(&lp->lock);
if(lp->fd >= 0){
err = -ENXIO;
goto out;
}
if(!lp->have_mac){
dev_ip_addr(dev, addr, &lp->mac[2]);
set_ether_mac(dev, lp->mac);
}
lp->fd = (*lp->open)(&lp->user);
if(lp->fd < 0){
err = lp->fd;
goto out;
}
err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
if(err != 0){
printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
err = -ENETUNREACH;
}
lp->tl.data = (unsigned long) &lp->user;
netif_start_queue(dev);
/* clear buffer - it can happen that the host side of the interface
* is full when we get here. In this case, new data is never queued,
* SIGIOs never arrive, and the net never works.
*/
while((err = uml_net_rx(dev)) > 0) ;
out:
spin_unlock(&lp->lock);
return(err);
}
static int uml_net_close(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
netif_stop_queue(dev);
spin_lock(&lp->lock);
free_irq_by_irq_and_dev(dev->irq, dev);
free_irq(dev->irq, dev);
if(lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
spin_unlock(&lp->lock);
return 0;
}
static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
unsigned long flags;
int len;
netif_stop_queue(dev);
spin_lock_irqsave(&lp->lock, flags);
<