*
* PACKET - implements raw packet sockets.
*
- * Version: $Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
unsigned int pg_vec_order;
unsigned int pg_vec_pages;
unsigned int pg_vec_len;
+ enum tpacket_versions tp_version;
+ unsigned int tp_hdrlen;
+ unsigned int tp_reserve;
#endif
};
#ifdef CONFIG_PACKET_MMAP
-static inline struct tpacket_hdr *packet_lookup_frame(struct packet_sock *po, unsigned int position)
+static void *packet_lookup_frame(struct packet_sock *po, unsigned int position,
+ int status)
{
unsigned int pg_vec_pos, frame_offset;
+ union {
+ struct tpacket_hdr *h1;
+ struct tpacket2_hdr *h2;
+ void *raw;
+ } h;
pg_vec_pos = position / po->frames_per_block;
frame_offset = position % po->frames_per_block;
- return (struct tpacket_hdr *)(po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size));
+ h.raw = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size);
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ if (status != h.h1->tp_status ? TP_STATUS_USER :
+ TP_STATUS_KERNEL)
+ return NULL;
+ break;
+ case TPACKET_V2:
+ if (status != h.h2->tp_status ? TP_STATUS_USER :
+ TP_STATUS_KERNEL)
+ return NULL;
+ break;
+ }
+ return h.raw;
+}
+
+static void __packet_set_status(struct packet_sock *po, void *frame, int status)
+{
+ union {
+ struct tpacket_hdr *h1;
+ struct tpacket2_hdr *h2;
+ void *raw;
+ } h;
+
+ h.raw = frame;
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ h.h1->tp_status = status;
+ break;
+ case TPACKET_V2:
+ h.h2->tp_status = status;
+ break;
+ }
}
#endif
static void packet_sock_destruct(struct sock *sk)
{
- BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
- BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(atomic_read(&sk->sk_rmem_alloc));
+ WARN_ON(atomic_read(&sk->sk_wmem_alloc));
if (!sock_flag(sk, SOCK_DEAD)) {
printk("Attempt to release alive packet socket: %p\n", sk);
if (skb->pkt_type == PACKET_LOOPBACK)
goto out;
- if (dev->nd_net != sk->sk_net)
+ if (dev_net(dev) != sock_net(sk))
goto out;
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
*/
saddr->spkt_device[13] = 0;
- dev = dev_get_by_name(sk->sk_net, saddr->spkt_device);
+ dev = dev_get_by_name(sock_net(sk), saddr->spkt_device);
err = -ENODEV;
if (dev == NULL)
goto out_unlock;
sk = pt->af_packet_priv;
po = pkt_sk(sk);
- if (dev->nd_net != sk->sk_net)
+ if (dev_net(dev) != sock_net(sk))
goto drop;
skb->dev = dev;
struct sock *sk;
struct packet_sock *po;
struct sockaddr_ll *sll;
- struct tpacket_hdr *h;
+ union {
+ struct tpacket_hdr *h1;
+ struct tpacket2_hdr *h2;
+ void *raw;
+ } h;
u8 * skb_head = skb->data;
int skb_len = skb->len;
unsigned int snaplen, res;
unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
- unsigned short macoff, netoff;
+ unsigned short macoff, netoff, hdrlen;
struct sk_buff *copy_skb = NULL;
struct timeval tv;
+ struct timespec ts;
if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;
sk = pt->af_packet_priv;
po = pkt_sk(sk);
- if (dev->nd_net != sk->sk_net)
+ if (dev_net(dev) != sock_net(sk))
goto drop;
if (dev->header_ops) {
snaplen = res;
if (sk->sk_type == SOCK_DGRAM) {
- macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16;
+ macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16 +
+ po->tp_reserve;
} else {
unsigned maclen = skb_network_offset(skb);
- netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen));
+ netoff = TPACKET_ALIGN(po->tp_hdrlen +
+ (maclen < 16 ? 16 : maclen)) +
+ po->tp_reserve;
macoff = netoff - maclen;
}
}
spin_lock(&sk->sk_receive_queue.lock);
- h = packet_lookup_frame(po, po->head);
-
- if (h->tp_status)
+ h.raw = packet_lookup_frame(po, po->head, TP_STATUS_KERNEL);
+ if (!h.raw)
goto ring_is_full;
po->head = po->head != po->frame_max ? po->head+1 : 0;
po->stats.tp_packets++;
status &= ~TP_STATUS_LOSING;
spin_unlock(&sk->sk_receive_queue.lock);
- skb_copy_bits(skb, 0, (u8*)h + macoff, snaplen);
+ skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
- h->tp_len = skb->len;
- h->tp_snaplen = snaplen;
- h->tp_mac = macoff;
- h->tp_net = netoff;
- if (skb->tstamp.tv64)
- tv = ktime_to_timeval(skb->tstamp);
- else
- do_gettimeofday(&tv);
- h->tp_sec = tv.tv_sec;
- h->tp_usec = tv.tv_usec;
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ h.h1->tp_len = skb->len;
+ h.h1->tp_snaplen = snaplen;
+ h.h1->tp_mac = macoff;
+ h.h1->tp_net = netoff;
+ if (skb->tstamp.tv64)
+ tv = ktime_to_timeval(skb->tstamp);
+ else
+ do_gettimeofday(&tv);
+ h.h1->tp_sec = tv.tv_sec;
+ h.h1->tp_usec = tv.tv_usec;
+ hdrlen = sizeof(*h.h1);
+ break;
+ case TPACKET_V2:
+ h.h2->tp_len = skb->len;
+ h.h2->tp_snaplen = snaplen;
+ h.h2->tp_mac = macoff;
+ h.h2->tp_net = netoff;
+ if (skb->tstamp.tv64)
+ ts = ktime_to_timespec(skb->tstamp);
+ else
+ getnstimeofday(&ts);
+ h.h2->tp_sec = ts.tv_sec;
+ h.h2->tp_nsec = ts.tv_nsec;
+ h.h2->tp_vlan_tci = skb->vlan_tci;
+ hdrlen = sizeof(*h.h2);
+ break;
+ default:
+ BUG();
+ }
- sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
+ sll = h.raw + TPACKET_ALIGN(hdrlen);
sll->sll_halen = dev_parse_header(skb, sll->sll_addr);
sll->sll_family = AF_PACKET;
sll->sll_hatype = dev->type;
else
sll->sll_ifindex = dev->ifindex;
- h->tp_status = status;
+ __packet_set_status(po, h.raw, status);
smp_mb();
{
struct page *p_start, *p_end;
- u8 *h_end = (u8 *)h + macoff + snaplen - 1;
+ u8 *h_end = h.raw + macoff + snaplen - 1;
- p_start = virt_to_page(h);
+ p_start = virt_to_page(h.raw);
p_end = virt_to_page(h_end);
while (p_start <= p_end) {
flush_dcache_page(p_start);
}
- dev = dev_get_by_index(sk->sk_net, ifindex);
+ dev = dev_get_by_index(sock_net(sk), ifindex);
err = -ENXIO;
if (dev == NULL)
goto out_unlock;
if (len > dev->mtu+reserve)
goto out_unlock;
- skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev),
+ skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
msg->msg_flags & MSG_DONTWAIT, &err);
if (skb==NULL)
goto out_unlock;
if (!sk)
return 0;
- net = sk->sk_net;
+ net = sock_net(sk);
po = pkt_sk(sk);
write_lock_bh(&net->packet.sklist_lock);
return -EINVAL;
strlcpy(name,uaddr->sa_data,sizeof(name));
- dev = dev_get_by_name(sk->sk_net, name);
+ dev = dev_get_by_name(sock_net(sk), name);
if (dev) {
err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
dev_put(dev);
if (sll->sll_ifindex) {
err = -ENODEV;
- dev = dev_get_by_index(sk->sk_net, sll->sll_ifindex);
+ dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);
if (dev == NULL)
goto out;
}
aux.tp_snaplen = skb->len;
aux.tp_mac = 0;
aux.tp_net = skb_network_offset(skb);
+ aux.tp_vlan_tci = skb->vlan_tci;
put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
}
return -EOPNOTSUPP;
uaddr->sa_family = AF_PACKET;
- dev = dev_get_by_index(sk->sk_net, pkt_sk(sk)->ifindex);
+ dev = dev_get_by_index(sock_net(sk), pkt_sk(sk)->ifindex);
if (dev) {
strlcpy(uaddr->sa_data, dev->name, 15);
dev_put(dev);
sll->sll_family = AF_PACKET;
sll->sll_ifindex = po->ifindex;
sll->sll_protocol = po->num;
- dev = dev_get_by_index(sk->sk_net, po->ifindex);
+ dev = dev_get_by_index(sock_net(sk), po->ifindex);
if (dev) {
sll->sll_hatype = dev->type;
sll->sll_halen = dev->addr_len;
return 0;
}
-static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int what)
+static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
+ int what)
{
switch (i->type) {
case PACKET_MR_MULTICAST:
dev_mc_delete(dev, i->addr, i->alen, 0);
break;
case PACKET_MR_PROMISC:
- dev_set_promiscuity(dev, what);
+ return dev_set_promiscuity(dev, what);
break;
case PACKET_MR_ALLMULTI:
- dev_set_allmulti(dev, what);
+ return dev_set_allmulti(dev, what);
break;
default:;
}
+ return 0;
}
static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
rtnl_lock();
err = -ENODEV;
- dev = __dev_get_by_index(sk->sk_net, mreq->mr_ifindex);
+ dev = __dev_get_by_index(sock_net(sk), mreq->mr_ifindex);
if (!dev)
goto done;
i->count = 1;
i->next = po->mclist;
po->mclist = i;
- packet_dev_mc(dev, i, +1);
+ err = packet_dev_mc(dev, i, 1);
+ if (err) {
+ po->mclist = i->next;
+ kfree(i);
+ }
done:
rtnl_unlock();
if (--ml->count == 0) {
struct net_device *dev;
*mlp = ml->next;
- dev = dev_get_by_index(sk->sk_net, ml->ifindex);
+ dev = dev_get_by_index(sock_net(sk), ml->ifindex);
if (dev) {
packet_dev_mc(dev, ml, -1);
dev_put(dev);
struct net_device *dev;
po->mclist = ml->next;
- if ((dev = dev_get_by_index(sk->sk_net, ml->ifindex)) != NULL) {
+ if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) {
packet_dev_mc(dev, ml, -1);
dev_put(dev);
}
pkt_sk(sk)->copy_thresh = val;
return 0;
}
+ case PACKET_VERSION:
+ {
+ int val;
+
+ if (optlen != sizeof(val))
+ return -EINVAL;
+ if (po->pg_vec)
+ return -EBUSY;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+ switch (val) {
+ case TPACKET_V1:
+ case TPACKET_V2:
+ po->tp_version = val;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ }
+ case PACKET_RESERVE:
+ {
+ unsigned int val;
+
+ if (optlen != sizeof(val))
+ return -EINVAL;
+ if (po->pg_vec)
+ return -EBUSY;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+ po->tp_reserve = val;
+ return 0;
+ }
#endif
case PACKET_AUXDATA:
{
data = &val;
break;
+#ifdef CONFIG_PACKET_MMAP
+ case PACKET_VERSION:
+ if (len > sizeof(int))
+ len = sizeof(int);
+ val = po->tp_version;
+ data = &val;
+ break;
+ case PACKET_HDRLEN:
+ if (len > sizeof(int))
+ len = sizeof(int);
+ if (copy_from_user(&val, optval, len))
+ return -EFAULT;
+ switch (val) {
+ case TPACKET_V1:
+ val = sizeof(struct tpacket_hdr);
+ break;
+ case TPACKET_V2:
+ val = sizeof(struct tpacket2_hdr);
+ break;
+ default:
+ return -EINVAL;
+ }
+ data = &val;
+ break;
+ case PACKET_RESERVE:
+ if (len > sizeof(unsigned int))
+ len = sizeof(unsigned int);
+ val = po->tp_reserve;
+ data = &val;
+ break;
+#endif
default:
return -ENOPROTOOPT;
}
struct sock *sk;
struct hlist_node *node;
struct net_device *dev = data;
- struct net *net = dev->nd_net;
+ struct net *net = dev_net(dev);
read_lock(&net->packet.sklist_lock);
sk_for_each(sk, node, &net->packet.sklist) {
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
case SIOCSIFFLAGS:
- if (sk->sk_net != &init_net)
+ if (!net_eq(sock_net(sk), &init_net))
return -ENOIOCTLCMD;
return inet_dgram_ops.ioctl(sock, cmd, arg);
#endif
spin_lock_bh(&sk->sk_receive_queue.lock);
if (po->pg_vec) {
unsigned last = po->head ? po->head-1 : po->frame_max;
- struct tpacket_hdr *h;
-
- h = packet_lookup_frame(po, last);
- if (h->tp_status)
+ if (packet_lookup_frame(po, last, TP_STATUS_USER))
mask |= POLLIN | POLLRDNORM;
}
spin_unlock_bh(&sk->sk_receive_queue.lock);
int err = 0;
if (req->tp_block_nr) {
- int i, l;
+ int i;
/* Sanity tests and some calculations */
if (unlikely(po->pg_vec))
return -EBUSY;
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ po->tp_hdrlen = TPACKET_HDRLEN;
+ break;
+ case TPACKET_V2:
+ po->tp_hdrlen = TPACKET2_HDRLEN;
+ break;
+ }
+
if (unlikely((int)req->tp_block_size <= 0))
return -EINVAL;
if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
return -EINVAL;
- if (unlikely(req->tp_frame_size < TPACKET_HDRLEN))
+ if (unlikely(req->tp_frame_size < po->tp_hdrlen +
+ po->tp_reserve))
return -EINVAL;
if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
return -EINVAL;
if (unlikely(!pg_vec))
goto out;
- l = 0;
for (i = 0; i < req->tp_block_nr; i++) {
- char *ptr = pg_vec[i];
- struct tpacket_hdr *header;
+ void *ptr = pg_vec[i];
int k;
for (k = 0; k < po->frames_per_block; k++) {
- header = (struct tpacket_hdr *) ptr;
- header->tp_status = TP_STATUS_KERNEL;
+ __packet_set_status(po, ptr, TP_STATUS_KERNEL);
ptr += req->tp_frame_size;
}
}