mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-11 10:30:09 +00:00
backported the changes from the Mac-On-Linux project:
- now compiles under Linux 2.4 kernels - Ethernet hardware address is virtualized on the Mac side - automatically filters IP packets based on the IP address of the Mac side
This commit is contained in:
parent
ff01052ee4
commit
53973d4b84
@ -29,9 +29,22 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/wait.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/arp.h>
|
||||
#include <net/ip.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/* Compatibility glue */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
#define LINUX_24
|
||||
#else
|
||||
#define net_device device
|
||||
typedef struct wait_queue *wait_queue_head_t;
|
||||
#define init_waitqueue_head(x) *(x)=NULL
|
||||
#endif
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#define bug printk
|
||||
@ -42,19 +55,24 @@
|
||||
#endif
|
||||
|
||||
|
||||
// Constants
|
||||
#define SHEEP_NET_MINOR 198 // Driver minor number
|
||||
#define MAX_QUEUE 32 // Maximum number of packets in queue
|
||||
#define PROT_MAGIC 1520 // Our "magic" protocol type
|
||||
/* Constants */
|
||||
#define SHEEP_NET_MINOR 198 /* Driver minor number */
|
||||
#define MAX_QUEUE 32 /* Maximum number of packets in queue */
|
||||
#define PROT_MAGIC 1520 /* Our "magic" protocol type */
|
||||
|
||||
// Prototypes
|
||||
#define ETH_ADDR_MULTICAST 0x1
|
||||
|
||||
#define SIOC_MOL_GET_IPFILTER SIOCDEVPRIVATE
|
||||
#define SIOC_MOL_SET_IPFILTER (SIOCDEVPRIVATE + 1)
|
||||
|
||||
/* Prototypes */
|
||||
static int sheep_net_open(struct inode *inode, struct file *f);
|
||||
static int sheep_net_release(struct inode *inode, struct file *f);
|
||||
static ssize_t sheep_net_read(struct file *f, char *buf, size_t count, loff_t *off);
|
||||
static ssize_t sheep_net_write(struct file *f, const char *buf, size_t count, loff_t *off);
|
||||
static unsigned int sheep_net_poll(struct file *f, struct poll_table_struct *wait);
|
||||
static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int code, unsigned long arg);
|
||||
static int sheep_net_receiver(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
|
||||
static int sheep_net_receiver(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt);
|
||||
|
||||
|
||||
/*
|
||||
@ -62,11 +80,14 @@ static int sheep_net_receiver(struct sk_buff *skb, struct device *dev, struct pa
|
||||
*/
|
||||
|
||||
struct SheepVars {
|
||||
struct device *ether; // The Ethernet device we're attached to
|
||||
struct sock *skt; // Socket for communication with Ethernet card
|
||||
struct sk_buff_head queue; // Receiver packet queue
|
||||
struct packet_type pt; // Receiver packet type
|
||||
struct wait_queue *wait; // Wait queue for blocking read operations
|
||||
struct net_device *ether; /* The Ethernet device we're attached to */
|
||||
struct sock *skt; /* Socket for communication with Ethernet card */
|
||||
struct sk_buff_head queue; /* Receiver packet queue */
|
||||
struct packet_type pt; /* Receiver packet type */
|
||||
wait_queue_head_t wait; /* Wait queue for blocking read operations */
|
||||
u32 ipfilter; /* Only receive IP packets destined for this address (host byte order) */
|
||||
char eth_addr[6]; /* Hardware address of the Ethernet card */
|
||||
char fake_addr[6]; /* Local faked hardware address (what SheepShaver sees) */
|
||||
};
|
||||
|
||||
|
||||
@ -76,21 +97,12 @@ struct SheepVars {
|
||||
*/
|
||||
|
||||
static struct file_operations sheep_net_fops = {
|
||||
NULL, // llseek
|
||||
sheep_net_read,
|
||||
sheep_net_write,
|
||||
NULL, // readdir
|
||||
sheep_net_poll,
|
||||
sheep_net_ioctl,
|
||||
NULL, // mmap
|
||||
sheep_net_open,
|
||||
NULL, // flush
|
||||
sheep_net_release,
|
||||
NULL, // fsync
|
||||
NULL, // fasync
|
||||
NULL, // check_media_change
|
||||
NULL, // revalidate
|
||||
NULL // lock
|
||||
read: sheep_net_read,
|
||||
write: sheep_net_write,
|
||||
poll: sheep_net_poll,
|
||||
ioctl: sheep_net_ioctl,
|
||||
open: sheep_net_open,
|
||||
release: sheep_net_release,
|
||||
};
|
||||
|
||||
|
||||
@ -99,8 +111,8 @@ static struct file_operations sheep_net_fops = {
|
||||
*/
|
||||
|
||||
static struct miscdevice sheep_net_device = {
|
||||
SHEEP_NET_MINOR, // minor number
|
||||
"sheep_net", // name
|
||||
SHEEP_NET_MINOR, /* minor number */
|
||||
"sheep_net", /* name */
|
||||
&sheep_net_fops,
|
||||
NULL,
|
||||
NULL
|
||||
@ -115,7 +127,7 @@ int init_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// Register driver
|
||||
/* Register driver */
|
||||
ret = misc_register(&sheep_net_device);
|
||||
D(bug("Sheep net driver installed\n"));
|
||||
return ret;
|
||||
@ -130,7 +142,7 @@ int cleanup_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// Unregister driver
|
||||
/* Unregister driver */
|
||||
ret = misc_deregister(&sheep_net_device);
|
||||
D(bug("Sheep net driver removed\n"));
|
||||
return ret;
|
||||
@ -146,18 +158,25 @@ static int sheep_net_open(struct inode *inode, struct file *f)
|
||||
struct SheepVars *v;
|
||||
D(bug("sheep_net: open\n"));
|
||||
|
||||
// Must be opened with read permissions
|
||||
/* Must be opened with read permissions */
|
||||
if ((f->f_flags & O_ACCMODE) == O_WRONLY)
|
||||
return -EPERM;
|
||||
|
||||
// Allocate private variables
|
||||
/* Allocate private variables */
|
||||
v = (struct SheepVars *)f->private_data = kmalloc(sizeof(struct SheepVars), GFP_USER);
|
||||
if (v == NULL)
|
||||
return -ENOMEM;
|
||||
memset(v, 0, sizeof(struct SheepVars));
|
||||
skb_queue_head_init(&v->queue);
|
||||
init_waitqueue_head(&v->wait);
|
||||
v->fake_addr[0] = 0xfe;
|
||||
v->fake_addr[1] = 0xfd;
|
||||
v->fake_addr[2] = 0xde;
|
||||
v->fake_addr[3] = 0xad;
|
||||
v->fake_addr[4] = 0xbe;
|
||||
v->fake_addr[5] = 0xef;
|
||||
|
||||
// Yes, we're open
|
||||
/* Yes, we're open */
|
||||
MOD_INC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
@ -173,27 +192,96 @@ static int sheep_net_release(struct inode *inode, struct file *f)
|
||||
struct sk_buff *skb;
|
||||
D(bug("sheep_net: close\n"));
|
||||
|
||||
// Detach from Ethernet card
|
||||
/* Detach from Ethernet card */
|
||||
if (v->ether) {
|
||||
dev_remove_pack(&v->pt);
|
||||
sk_free(v->skt);
|
||||
v->skt = NULL;
|
||||
#ifdef LINUX_24
|
||||
dev_put( v->ether );
|
||||
#endif
|
||||
v->ether = NULL;
|
||||
}
|
||||
|
||||
// Empty packet queue
|
||||
/* Empty packet queue */
|
||||
while ((skb = skb_dequeue(&v->queue)) != NULL)
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
// Free private variables
|
||||
/* Free private variables */
|
||||
kfree(v);
|
||||
|
||||
// Sorry, we're closed
|
||||
/* Sorry, we're closed */
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check whether an Ethernet address is the local (attached) one or
|
||||
* the fake one
|
||||
*/
|
||||
|
||||
static inline int is_local_addr(struct SheepVars *v, void *a)
|
||||
{
|
||||
return memcmp(a, v->eth_addr, 6) == 0;
|
||||
}
|
||||
|
||||
static inline int is_fake_addr(struct SheepVars *v, void *a)
|
||||
{
|
||||
return memcmp(a, v->fake_addr, 6) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Outgoing packet. Replace the fake enet addr with the real local one.
|
||||
*/
|
||||
|
||||
static inline void do_demasq(struct SheepVars *v, u8 *p)
|
||||
{
|
||||
memcpy(p, v->eth_addr, 6);
|
||||
}
|
||||
|
||||
static void demasquerade(struct SheepVars *v, struct sk_buff *skb)
|
||||
{
|
||||
u8 *p = skb->mac.raw;
|
||||
int proto = (p[12] << 8) | p[13];
|
||||
|
||||
do_demasq(v, p + 6); /* source address */
|
||||
|
||||
/* Need to fix ARP packets */
|
||||
if (proto == ETH_P_ARP) {
|
||||
if (is_fake_addr(v, p + 14 + 8)) /* sender HW-addr */
|
||||
do_demasq(v, p + 14 + 8);
|
||||
}
|
||||
|
||||
/* ...and AARPs (snap code: 0x00,0x00,0x00,0x80,0xF3) */
|
||||
if (p[17] == 0 && p[18] == 0 && p[19] == 0 && p[20] == 0x80 && p[21] == 0xf3) {
|
||||
/* XXX: we should perhaps look for the 802 frame too */
|
||||
if (is_fake_addr(v, p + 30))
|
||||
do_demasq(v, p + 30); /* sender HW-addr */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Incoming packet. Replace the local enet addr with the fake one.
|
||||
*/
|
||||
|
||||
static inline void do_masq(struct SheepVars *v, u8 *p)
|
||||
{
|
||||
memcpy(p, v->fake_addr, 6);
|
||||
}
|
||||
|
||||
static void masquerade(struct SheepVars *v, struct sk_buff *skb)
|
||||
{
|
||||
u8 *p = skb->mac.raw;
|
||||
if (!(p[0] & ETH_ADDR_MULTICAST))
|
||||
do_masq(v, p); /* destination address */
|
||||
|
||||
/* XXX: reverse ARP might need to be fixed */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Driver read() function
|
||||
*/
|
||||
@ -202,33 +290,27 @@ static ssize_t sheep_net_read(struct file *f, char *buf, size_t count, loff_t *o
|
||||
{
|
||||
struct SheepVars *v = (struct SheepVars *)f->private_data;
|
||||
struct sk_buff *skb;
|
||||
sigset_t sigs;
|
||||
int i;
|
||||
|
||||
D(bug("sheep_net: read\n"));
|
||||
|
||||
for (;;) {
|
||||
|
||||
// Get next packet from queue
|
||||
start_bh_atomic();
|
||||
/* Get next packet from queue */
|
||||
skb = skb_dequeue(&v->queue);
|
||||
end_bh_atomic();
|
||||
if (skb != NULL || (f->f_flags & O_NONBLOCK))
|
||||
break;
|
||||
|
||||
// No packet in queue and in blocking mode, so block
|
||||
/* No packet in queue and in blocking mode, so block */
|
||||
interruptible_sleep_on(&v->wait);
|
||||
|
||||
// Signal received? Then bail out
|
||||
signandsets(&sigs, ¤t->signal, ¤t->blocked);
|
||||
for (i=0; i<_NSIG_WORDS; i++) {
|
||||
if (sigs.sig[i])
|
||||
return -EINTR;
|
||||
}
|
||||
/* Signal received? Then bail out */
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
}
|
||||
if (skb == NULL)
|
||||
return -EAGAIN;
|
||||
|
||||
// Pass packet to caller
|
||||
/* Pass packet to caller */
|
||||
if (count > skb->len)
|
||||
count = skb->len;
|
||||
if (copy_to_user(buf, skb->data, count))
|
||||
@ -249,37 +331,65 @@ static ssize_t sheep_net_write(struct file *f, const char *buf, size_t count, lo
|
||||
char *p;
|
||||
D(bug("sheep_net: write\n"));
|
||||
|
||||
// Check packet size
|
||||
/* Check packet size */
|
||||
if (count < sizeof(struct ethhdr))
|
||||
return -EINVAL;
|
||||
if (count > 1514)
|
||||
count = 1514;
|
||||
|
||||
// Interface active?
|
||||
/* Interface active? */
|
||||
if (v->ether == NULL)
|
||||
return count;
|
||||
|
||||
// Allocate buffer for packet
|
||||
/* Allocate buffer for packet */
|
||||
skb = dev_alloc_skb(count);
|
||||
if (skb == NULL)
|
||||
return -ENOBUFS;
|
||||
|
||||
// Stuff packet in buffer
|
||||
/* Stuff packet in buffer */
|
||||
p = skb_put(skb, count);
|
||||
if (copy_from_user(p, buf, count)) {
|
||||
kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
// Transmit packet
|
||||
dev_lock_list();
|
||||
/* Transmit packet */
|
||||
atomic_add(skb->truesize, &v->skt->wmem_alloc);
|
||||
skb->sk = v->skt;
|
||||
skb->dev = v->ether;
|
||||
skb->priority = 0;
|
||||
skb->protocol = PROT_MAGIC; // "Magic" protocol value to recognize our packets in sheep_net_receiver()
|
||||
skb->nh.raw = skb->h.raw = skb->data + v->ether->hard_header_len;
|
||||
dev_unlock_list();
|
||||
skb->mac.raw = skb->data;
|
||||
|
||||
/* Base the IP-filtering on the IP address in any outgoing ARP packets */
|
||||
if (skb->mac.ethernet->h_proto == htons(ETH_P_ARP)) {
|
||||
u8 *p = &skb->data[14+14]; /* source IP address */
|
||||
u32 ip = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
if (ip != v->ipfilter) {
|
||||
v->ipfilter = ip;
|
||||
printk("sheep_net: ipfilter set to %d.%d.%d.%d\n", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is this packet addressed solely to the local host? */
|
||||
if (is_local_addr(v, skb->data) && !(skb->data[0] & ETH_ADDR_MULTICAST)) {
|
||||
skb->protocol = eth_type_trans(skb, v->ether);
|
||||
netif_rx(skb);
|
||||
return count;
|
||||
}
|
||||
if (skb->data[0] & ETH_ADDR_MULTICAST) {
|
||||
/* We can't clone the skb since we will manipulate the data below */
|
||||
struct sk_buff *lskb = skb_copy(skb, GFP_ATOMIC);
|
||||
if (lskb) {
|
||||
lskb->protocol = eth_type_trans(lskb, v->ether);
|
||||
netif_rx(lskb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Outgoing packet (will be on the net) */
|
||||
demasquerade(v, skb);
|
||||
|
||||
skb->protocol = PROT_MAGIC; /* Magic value (we can recognize the packet in sheep_net_receiver) */
|
||||
dev_queue_xmit(skb);
|
||||
return count;
|
||||
}
|
||||
@ -294,22 +404,16 @@ static unsigned int sheep_net_poll(struct file *f, struct poll_table_struct *wai
|
||||
struct SheepVars *v = (struct SheepVars *)f->private_data;
|
||||
D(bug("sheep_net: poll\n"));
|
||||
|
||||
// Packets in queue? Then return
|
||||
start_bh_atomic();
|
||||
if (!skb_queue_empty(&v->queue)) {
|
||||
end_bh_atomic();
|
||||
/* Packets in queue? Then return */
|
||||
if (!skb_queue_empty(&v->queue))
|
||||
return POLLIN | POLLRDNORM;
|
||||
}
|
||||
|
||||
// Otherwise wait for packet
|
||||
/* Otherwise wait for packet */
|
||||
poll_wait(f, &v->wait, wait);
|
||||
if (!skb_queue_empty(&v->queue)) {
|
||||
end_bh_atomic();
|
||||
if (!skb_queue_empty(&v->queue))
|
||||
return POLLIN | POLLRDNORM;
|
||||
} else {
|
||||
end_bh_atomic();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -324,65 +428,88 @@ static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int cod
|
||||
|
||||
switch (code) {
|
||||
|
||||
// Attach to Ethernet card
|
||||
// arg: pointer to name of Ethernet device (char[8])
|
||||
/* Attach to Ethernet card
|
||||
arg: pointer to name of Ethernet device (char[8]) */
|
||||
case SIOCSIFLINK: {
|
||||
char name[8];
|
||||
int err;
|
||||
|
||||
// Already attached?
|
||||
/* Already attached? */
|
||||
if (v->ether)
|
||||
return -EBUSY;
|
||||
|
||||
// Get Ethernet card name
|
||||
/* Get Ethernet card name */
|
||||
if (copy_from_user(name, (void *)arg, 8))
|
||||
return -EFAULT;
|
||||
name[7] = 0;
|
||||
|
||||
// Find card
|
||||
/* Find card */
|
||||
#ifdef LINUX_24
|
||||
v->ether = dev_get_by_name(name);
|
||||
#else
|
||||
dev_lock_list();
|
||||
v->ether = dev_get(name);
|
||||
#endif
|
||||
if (v->ether == NULL) {
|
||||
dev_unlock_list();
|
||||
return -ENODEV;
|
||||
err = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Is it Ethernet?
|
||||
/* Is it Ethernet? */
|
||||
if (v->ether->type != ARPHRD_ETHER) {
|
||||
v->ether = NULL;
|
||||
dev_unlock_list();
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Allocate socket
|
||||
/* Remember the card's hardware address */
|
||||
memcpy(v->eth_addr, v->ether->dev_addr, 6);
|
||||
|
||||
/* Allocate socket */
|
||||
v->skt = sk_alloc(0, GFP_USER, 1);
|
||||
if (v->skt == NULL) {
|
||||
v->ether = NULL;
|
||||
dev_unlock_list();
|
||||
return -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
v->skt->dead = 1;
|
||||
|
||||
// Attach packet handler
|
||||
/* Attach packet handler */
|
||||
v->pt.type = htons(ETH_P_ALL);
|
||||
v->pt.dev = v->ether;
|
||||
v->pt.func = sheep_net_receiver;
|
||||
v->pt.data = v;
|
||||
dev_add_pack(&v->pt);
|
||||
#ifndef LINUX_24
|
||||
dev_unlock_list();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
error:
|
||||
#ifdef LINUX_24
|
||||
if (v->ether)
|
||||
dev_put(v->ether);
|
||||
#else
|
||||
dev_unlock_list();
|
||||
#endif
|
||||
v->ether = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
// Get hardware address of Ethernet card
|
||||
// arg: pointer to buffer (6 bytes) to store address
|
||||
/* Get hardware address of the sheep_net module
|
||||
arg: pointer to buffer (6 bytes) to store address */
|
||||
case SIOCGIFADDR:
|
||||
if (v->ether == NULL)
|
||||
return -ENODEV;
|
||||
if (copy_to_user((void *)arg, v->ether->dev_addr, 6))
|
||||
if (copy_to_user((void *)arg, v->fake_addr, 6))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
// Add multicast address
|
||||
// arg: pointer to address (6 bytes)
|
||||
/* Set the hardware address of the sheep_net module
|
||||
arg: pointer to new address (6 bytes) */
|
||||
case SIOCSIFADDR:
|
||||
if (copy_from_user(v->fake_addr, (void*)arg, 6))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
/* Add multicast address
|
||||
arg: pointer to address (6 bytes) */
|
||||
case SIOCADDMULTI: {
|
||||
char addr[6];
|
||||
if (v->ether == NULL)
|
||||
@ -392,8 +519,8 @@ static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int cod
|
||||
return dev_mc_add(v->ether, addr, 6, 0);
|
||||
}
|
||||
|
||||
// Remove multicast address
|
||||
// arg: pointer to address (6 bytes)
|
||||
/* Remove multicast address
|
||||
arg: pointer to address (6 bytes) */
|
||||
case SIOCDELMULTI: {
|
||||
char addr[6];
|
||||
if (v->ether == NULL)
|
||||
@ -403,18 +530,34 @@ static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int cod
|
||||
return dev_mc_delete(v->ether, addr, 6, 0);
|
||||
}
|
||||
|
||||
// Return size of first packet in queue
|
||||
/* Return size of first packet in queue */
|
||||
case FIONREAD: {
|
||||
int count = 0;
|
||||
struct sk_buff *skb;
|
||||
start_bh_atomic();
|
||||
#ifdef LINUX_24
|
||||
long flags;
|
||||
spin_lock_irqsave(&v->queue.lock, flags);
|
||||
#else
|
||||
cli();
|
||||
#endif
|
||||
skb = skb_peek(&v->queue);
|
||||
if (skb)
|
||||
count = skb->len;
|
||||
end_bh_atomic();
|
||||
#ifdef LINUX_24
|
||||
spin_unlock_irqrestore(&v->queue.lock, flags);
|
||||
#else
|
||||
sti();
|
||||
#endif
|
||||
return put_user(count, (int *)arg);
|
||||
}
|
||||
|
||||
case SIOC_MOL_GET_IPFILTER:
|
||||
return put_user(v->ipfilter, (int *)arg);
|
||||
|
||||
case SIOC_MOL_SET_IPFILTER:
|
||||
v->ipfilter = arg;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
@ -425,32 +568,55 @@ static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int cod
|
||||
* Packet receiver function
|
||||
*/
|
||||
|
||||
static int sheep_net_receiver(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
|
||||
static int sheep_net_receiver(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
|
||||
{
|
||||
struct SheepVars *v = (struct SheepVars *)pt->data;
|
||||
struct sk_buff *skb2;
|
||||
int fake;
|
||||
int multicast;
|
||||
D(bug("sheep_net: packet received\n"));
|
||||
|
||||
// Packet sent by us? Then discard
|
||||
if (skb->protocol == PROT_MAGIC) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
multicast = (skb->mac.ethernet->h_dest[0] & ETH_ADDR_MULTICAST);
|
||||
fake = is_fake_addr(v, &skb->mac.ethernet->h_dest);
|
||||
|
||||
/* Packet sent by us? Then discard */
|
||||
if (is_fake_addr(v, &skb->mac.ethernet->h_source) || skb->protocol == PROT_MAGIC)
|
||||
goto drop;
|
||||
|
||||
/* If the packet is not meant for this host, discard it */
|
||||
if (!is_local_addr(v, &skb->mac.ethernet->h_dest) && !multicast && !fake)
|
||||
goto drop;
|
||||
|
||||
/* Discard packets if queue gets too full */
|
||||
if (skb_queue_len(&v->queue) > MAX_QUEUE)
|
||||
goto drop;
|
||||
|
||||
/* Apply any filters here (if fake is true, then we *know* we want this packet) */
|
||||
if (!fake) {
|
||||
if ((skb->protocol == htons(ETH_P_IP))
|
||||
&& (!v->ipfilter || (ntohl(skb->h.ipiph->daddr) != v->ipfilter && !multicast)))
|
||||
goto drop;
|
||||
}
|
||||
|
||||
// Discard packets if queue gets too full
|
||||
if (skb_queue_len(&v->queue) > MAX_QUEUE) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
/* Masquerade (we are typically a clone - best to make a real copy) */
|
||||
skb2 = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!skb2)
|
||||
goto drop;
|
||||
kfree_skb(skb);
|
||||
skb = skb2;
|
||||
masquerade(v, skb);
|
||||
|
||||
// We also want the Ethernet header
|
||||
/* We also want the Ethernet header */
|
||||
skb_push(skb, skb->data - skb->mac.raw);
|
||||
|
||||
// Enqueue packet
|
||||
start_bh_atomic();
|
||||
/* Enqueue packet */
|
||||
skb_queue_tail(&v->queue, skb);
|
||||
end_bh_atomic();
|
||||
|
||||
// Unblock blocked read
|
||||
/* Unblock blocked read */
|
||||
wake_up(&v->wait);
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user