*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/capability.h>
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <linux/in.h>
spinlock_t bind_lock;
char running; /* prot_hook is attached*/
int ifindex; /* bound device */
- unsigned short num;
+ __be16 num;
#ifdef CONFIG_PACKET_MULTICAST
struct packet_mclist *mclist;
#endif
}
-static struct proto_ops packet_ops;
+static const struct proto_ops packet_ops;
#ifdef CONFIG_SOCK_PACKET
-static struct proto_ops packet_ops_spkt;
+static const struct proto_ops packet_ops_spkt;
static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
struct sk_buff *skb;
struct net_device *dev;
- unsigned short proto=0;
+ __be16 proto=0;
int err;
/*
*/
err = -EMSGSIZE;
- if(len>dev->mtu+dev->hard_header_len)
+ if (len > dev->mtu + dev->hard_header_len)
goto out_unlock;
err = -ENOBUFS;
}
#endif
-static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned res)
+static inline int run_filter(struct sk_buff *skb, struct sock *sk,
+ unsigned *snaplen)
{
struct sk_filter *filter;
+ int err = 0;
- bh_lock_sock(sk);
- filter = sk->sk_filter;
- /*
- * Our caller already checked that filter != NULL but we need to
- * verify that under bh_lock_sock() to be safe
- */
- if (likely(filter != NULL))
- res = sk_run_filter(skb, filter->insns, filter->len);
- bh_unlock_sock(sk);
+ rcu_read_lock_bh();
+ filter = rcu_dereference(sk->sk_filter);
+ if (filter != NULL) {
+ err = sk_run_filter(skb, filter->insns, filter->len);
+ if (!err)
+ err = -EPERM;
+ else if (*snaplen > err)
+ *snaplen = err;
+ }
+ rcu_read_unlock_bh();
- return res;
+ return err;
}
/*
snaplen = skb->len;
- if (sk->sk_filter) {
- unsigned res = run_filter(skb, sk, snaplen);
- if (res == 0)
- goto drop_n_restore;
- if (snaplen > res)
- snaplen = res;
- }
+ if (run_filter(skb, sk, &snaplen) < 0)
+ goto drop_n_restore;
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf)
else if (skb->pkt_type == PACKET_OUTGOING) {
/* Special case: outgoing packets have ll header at head */
skb_pull(skb, skb->nh.raw - skb->data);
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
status |= TP_STATUS_CSUMNOTREADY;
}
}
snaplen = skb->len;
- if (sk->sk_filter) {
- unsigned res = run_filter(skb, sk, snaplen);
- if (res == 0)
- goto drop_n_restore;
- if (snaplen > res)
- snaplen = res;
- }
+ if (run_filter(skb, sk, &snaplen) < 0)
+ goto drop_n_restore;
if (sk->sk_type == SOCK_DGRAM) {
macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16;
if ((int)snaplen < 0)
snaplen = 0;
}
- if (snaplen > skb->len-skb->data_len)
- snaplen = skb->len-skb->data_len;
spin_lock(&sk->sk_receive_queue.lock);
h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head);
status &= ~TP_STATUS_LOSING;
spin_unlock(&sk->sk_receive_queue.lock);
- memcpy((u8*)h + macoff, skb->data, snaplen);
+ skb_copy_bits(skb, 0, (u8*)h + macoff, snaplen);
h->tp_len = skb->len;
h->tp_snaplen = snaplen;
__net_timestamp(skb);
sock_enable_timestamp(sk);
}
- h->tp_sec = skb_tv_base.tv_sec + skb->tstamp.off_sec;
- h->tp_usec = skb_tv_base.tv_usec + skb->tstamp.off_usec;
+ h->tp_sec = skb->tstamp.off_sec;
+ h->tp_usec = skb->tstamp.off_usec;
sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
sll->sll_halen = 0;
struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
struct sk_buff *skb;
struct net_device *dev;
- unsigned short proto;
+ __be16 proto;
unsigned char *addr;
int ifindex, err, reserve = 0;
if (dev->hard_header) {
int res;
err = -EINVAL;
- if (saddr) {
- if (saddr->sll_halen != dev->addr_len)
- goto out_free;
- if (saddr->sll_hatype != dev->type)
- goto out_free;
- }
res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
if (sock->type != SOCK_DGRAM) {
skb->tail = skb->data;
* Attach a packet hook.
*/
-static int packet_do_bind(struct sock *sk, struct net_device *dev, int protocol)
+static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol)
{
struct packet_sock *po = pkt_sk(sk);
/*
* Check legality
*/
- if(addr_len!=sizeof(struct sockaddr))
+ if (addr_len != sizeof(struct sockaddr))
return -EINVAL;
strlcpy(name,uaddr->sa_data,sizeof(name));
{
struct sock *sk;
struct packet_sock *po;
+ __be16 proto = (__force __be16)protocol; /* weird, but documented */
int err;
if (!capable(CAP_NET_RAW))
po = pkt_sk(sk);
sk->sk_family = PF_PACKET;
- po->num = protocol;
+ po->num = proto;
sk->sk_destruct = packet_sock_destruct;
atomic_inc(&packet_socks_nr);
#endif
po->prot_hook.af_packet_priv = sk;
- if (protocol) {
- po->prot_hook.type = protocol;
+ if (proto) {
+ po->prot_hook.type = proto;
dev_add_pack(&po->prot_hook);
sock_hold(sk);
po->running = 1;
* retries.
*/
- if(skb==NULL)
+ if (skb == NULL)
goto out;
/*
goto done;
err = -ENOBUFS;
- i = (struct packet_mclist *)kmalloc(sizeof(*i), GFP_KERNEL);
+ i = kmalloc(sizeof(*i), GFP_KERNEL);
if (i == NULL)
goto done;
if (level != SOL_PACKET)
return -ENOPROTOOPT;
- if (get_user(len,optlen))
- return -EFAULT;
+ if (get_user(len, optlen))
+ return -EFAULT;
if (len < 0)
return -EINVAL;
return -ENOPROTOOPT;
}
- if (put_user(len, optlen))
- return -EFAULT;
- return 0;
+ if (put_user(len, optlen))
+ return -EFAULT;
+ return 0;
}
#endif
default:
- return dev_ioctl(cmd, (void __user *)arg);
+ return -ENOIOCTLCMD;
}
return 0;
}
return virt_to_page(one_pg_vec + (PAGE_SIZE << order) - 1);
}
-static void free_pg_vec(char **pg_vec, unsigned order, unsigned len)
+static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len)
{
int i;
- for (i=0; i<len; i++) {
- if (pg_vec[i]) {
- struct page *page, *pend;
-
- pend = pg_vec_endpage(pg_vec[i], order);
- for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
- ClearPageReserved(page);
- free_pages((unsigned long)pg_vec[i], order);
- }
+ for (i = 0; i < len; i++) {
+ if (likely(pg_vec[i]))
+ free_pages((unsigned long) pg_vec[i], order);
}
kfree(pg_vec);
}
+static inline char *alloc_one_pg_vec_page(unsigned long order)
+{
+ return (char *) __get_free_pages(GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
+ order);
+}
+
+static char **alloc_pg_vec(struct tpacket_req *req, int order)
+{
+ unsigned int block_nr = req->tp_block_nr;
+ char **pg_vec;
+ int i;
+
+ pg_vec = kzalloc(block_nr * sizeof(char *), GFP_KERNEL);
+ if (unlikely(!pg_vec))
+ goto out;
+
+ for (i = 0; i < block_nr; i++) {
+ pg_vec[i] = alloc_one_pg_vec_page(order);
+ if (unlikely(!pg_vec[i]))
+ goto out_free_pgvec;
+ }
+
+out:
+ return pg_vec;
+
+out_free_pgvec:
+ free_pg_vec(pg_vec, order, block_nr);
+ pg_vec = NULL;
+ goto out;
+}
static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing)
{
char **pg_vec = NULL;
struct packet_sock *po = pkt_sk(sk);
- int was_running, num, order = 0;
+ int was_running, order = 0;
+ __be16 num;
int err = 0;
if (req->tp_block_nr) {
/* Sanity tests and some calculations */
- if (po->pg_vec)
+ if (unlikely(po->pg_vec))
return -EBUSY;
- if ((int)req->tp_block_size <= 0)
+ if (unlikely((int)req->tp_block_size <= 0))
return -EINVAL;
- if (req->tp_block_size&(PAGE_SIZE-1))
+ if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
return -EINVAL;
- if (req->tp_frame_size < TPACKET_HDRLEN)
+ if (unlikely(req->tp_frame_size < TPACKET_HDRLEN))
return -EINVAL;
- if (req->tp_frame_size&(TPACKET_ALIGNMENT-1))
+ if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
return -EINVAL;
po->frames_per_block = req->tp_block_size/req->tp_frame_size;
- if (po->frames_per_block <= 0)
+ if (unlikely(po->frames_per_block <= 0))
return -EINVAL;
- if (po->frames_per_block*req->tp_block_nr != req->tp_frame_nr)
+ if (unlikely((po->frames_per_block * req->tp_block_nr) !=
+ req->tp_frame_nr))
return -EINVAL;
- /* OK! */
-
- /* Allocate page vector */
- while ((PAGE_SIZE<<order) < req->tp_block_size)
- order++;
err = -ENOMEM;
-
- pg_vec = kmalloc(req->tp_block_nr*sizeof(char *), GFP_KERNEL);
- if (pg_vec == NULL)
+ order = get_order(req->tp_block_size);
+ pg_vec = alloc_pg_vec(req, order);
+ if (unlikely(!pg_vec))
goto out;
- memset(pg_vec, 0, req->tp_block_nr*sizeof(char **));
-
- for (i=0; i<req->tp_block_nr; i++) {
- struct page *page, *pend;
- pg_vec[i] = (char *)__get_free_pages(GFP_KERNEL, order);
- if (!pg_vec[i])
- goto out_free_pgvec;
-
- pend = pg_vec_endpage(pg_vec[i], order);
- for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
- SetPageReserved(page);
- }
- /* Page vector is allocated */
l = 0;
- for (i=0; i<req->tp_block_nr; i++) {
+ for (i = 0; i < req->tp_block_nr; i++) {
char *ptr = pg_vec[i];
struct tpacket_hdr *header;
int k;
- for (k=0; k<po->frames_per_block; k++) {
-
- header = (struct tpacket_hdr*)ptr;
+ for (k = 0; k < po->frames_per_block; k++) {
+ header = (struct tpacket_hdr *) ptr;
header->tp_status = TP_STATUS_KERNEL;
ptr += req->tp_frame_size;
}
}
/* Done */
} else {
- if (req->tp_frame_nr)
+ if (unlikely(req->tp_frame_nr))
return -EINVAL;
}
spin_lock_bh(&sk->sk_receive_queue.lock);
pg_vec = XC(po->pg_vec, pg_vec);
- po->frame_max = req->tp_frame_nr-1;
+ po->frame_max = (req->tp_frame_nr - 1);
po->head = 0;
po->frame_size = req->tp_frame_size;
spin_unlock_bh(&sk->sk_receive_queue.lock);
release_sock(sk);
-out_free_pgvec:
if (pg_vec)
free_pg_vec(pg_vec, order, req->tp_block_nr);
out:
if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE)
goto out;
- atomic_inc(&po->mapped);
start = vma->vm_start;
- err = -EAGAIN;
- for (i=0; i<po->pg_vec_len; i++) {
- if (remap_pfn_range(vma, start,
- __pa(po->pg_vec[i]) >> PAGE_SHIFT,
- po->pg_vec_pages*PAGE_SIZE,
- vma->vm_page_prot))
- goto out;
- start += po->pg_vec_pages*PAGE_SIZE;
+ for (i = 0; i < po->pg_vec_len; i++) {
+ struct page *page = virt_to_page(po->pg_vec[i]);
+ int pg_num;
+
+ for (pg_num = 0; pg_num < po->pg_vec_pages; pg_num++, page++) {
+ err = vm_insert_page(vma, start, page);
+ if (unlikely(err))
+ goto out;
+ start += PAGE_SIZE;
+ }
}
+ atomic_inc(&po->mapped);
vma->vm_ops = &packet_mmap_ops;
err = 0;
#ifdef CONFIG_SOCK_PACKET
-static struct proto_ops packet_ops_spkt = {
+static const struct proto_ops packet_ops_spkt = {
.family = PF_PACKET,
.owner = THIS_MODULE,
.release = packet_release,
};
#endif
-static struct proto_ops packet_ops = {
+static const struct proto_ops packet_ops = {
.family = PF_PACKET,
.owner = THIS_MODULE,
.release = packet_release,