diff options
author | Kumar Gala <galak@kernel.crashing.org> | 2007-02-12 23:57:21 -0600 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2007-02-12 23:57:21 -0600 |
commit | 54c66f6d781e03dc0b23956234963c4911e6d1c0 (patch) | |
tree | 40619a66ae6d8703a57bf681d087ffeabbffd346 /net/packet/af_packet.c | |
parent | 8ce0a7df6e6117d8814e976d4b7ce6a6b2c9cf93 (diff) | |
parent | 17e0e27020d028a790d97699aff85a43af5be472 (diff) |
Merge branch 'master' into 85xx
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 159 |
1 files changed, 106 insertions, 53 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6dc01bdeb76..15ff7b15e21 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -11,7 +11,7 @@ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox, <gw4pts@gw4pts.ampr.org> * - * Fixes: + * Fixes: * Alan Cox : verify_area() now used correctly * Alan Cox : new skbuff lists, look ma no backlogs! * Alan Cox : tidied skbuff lists. @@ -34,12 +34,12 @@ * Alexey Kuznetsov : Untied from IPv4 stack. * Cyrus Durgin : Fixed kerneld for kmod. * Michal Ostrowski : Module initialization cleanup. - * Ulises Alonso : Frame number limit removal and + * Ulises Alonso : Frame number limit removal and * packet_set_ring memory leak. * Eric Biederman : Allow for > 8 byte hardware addresses. * The convention is that longer addresses * will simply extend the hardware address - * byte arrays at the end of sockaddr_ll + * byte arrays at the end of sockaddr_ll * and packet_mreq. * * This program is free software; you can redistribute it and/or @@ -48,7 +48,7 @@ * 2 of the License, or (at your option) any later version. * */ - + #include <linux/types.h> #include <linux/sched.h> #include <linux/mm.h> @@ -60,6 +60,7 @@ #include <linux/netdevice.h> #include <linux/if_packet.h> #include <linux/wireless.h> +#include <linux/kernel.h> #include <linux/kmod.h> #include <net/ip.h> #include <net/protocol.h> @@ -123,7 +124,7 @@ Outgoing, dev->hard_header!=NULL Incoming, dev->hard_header==NULL mac.raw -> UNKNOWN position. It is very likely, that it points to ll header. - PPP makes it, that is wrong, because introduce assymetry + PPP makes it, that is wrong, because introduce assymetry between rx and tx paths. data -> data @@ -200,7 +201,8 @@ struct packet_sock { #endif struct packet_type prot_hook; spinlock_t bind_lock; - char running; /* prot_hook is attached*/ + unsigned int running:1, /* prot_hook is attached*/ + auxdata:1; int ifindex; /* bound device */ __be16 num; #ifdef CONFIG_PACKET_MULTICAST @@ -214,6 +216,16 @@ struct packet_sock { #endif }; +struct packet_skb_cb { + unsigned int origlen; + union { + struct sockaddr_pkt pkt; + struct sockaddr_ll ll; + } sa; +}; + +#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb)) + #ifdef CONFIG_PACKET_MMAP static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) @@ -225,7 +237,7 @@ static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int pos frame_offset = position % po->frames_per_block; frame = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size); - + return frame; } #endif @@ -268,7 +280,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct */ sk = pt->af_packet_priv; - + /* * Yank back the headers [hope the device set this * right or kerboom...] @@ -293,7 +305,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct /* drop conntrack reference */ nf_reset(skb); - spkt = (struct sockaddr_pkt*)skb->cb; + spkt = &PACKET_SKB_CB(skb)->sa.pkt; skb_push(skb, skb->data-skb->mac.raw); @@ -324,7 +336,7 @@ oom: * Output a raw packet to a device layer. This bypasses all the other * protocol layers and you must therefore supply it with a complete frame */ - + static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { @@ -334,9 +346,9 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, struct net_device *dev; __be16 proto=0; int err; - + /* - * Get and verify the address. + * Get and verify the address. */ if (saddr) @@ -350,7 +362,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, return(-ENOTCONN); /* SOCK_PACKET must be sent giving an address */ /* - * Find the device first to size check it + * Find the device first to size check it */ saddr->spkt_device[13] = 0; @@ -358,7 +370,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, err = -ENODEV; if (dev == NULL) goto out_unlock; - + err = -ENETDOWN; if (!(dev->flags & IFF_UP)) goto out_unlock; @@ -367,7 +379,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, * You may not queue a frame bigger than the mtu. This is the lowest level * raw protocol and you must do your own fragmentation at this level. */ - + err = -EMSGSIZE; if (len > dev->mtu + dev->hard_header_len) goto out_unlock; @@ -380,14 +392,14 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, * deal with the problem - do your own algorithmic backoffs. That's far * more flexible. */ - - if (skb == NULL) + + if (skb == NULL) goto out_unlock; /* - * Fill it in + * Fill it in */ - + /* FIXME: Save some space for broken drivers that write a * hard header at transmission time by themselves. PPP is the * notable one here. This should really be fixed at the driver level. @@ -512,7 +524,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet skb = nskb; } - sll = (struct sockaddr_ll*)skb->cb; + BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 > + sizeof(skb->cb)); + + sll = &PACKET_SKB_CB(skb)->sa.ll; sll->sll_family = AF_PACKET; sll->sll_hatype = dev->type; sll->sll_protocol = skb->protocol; @@ -523,6 +538,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet if (dev->hard_header_parse) sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + PACKET_SKB_CB(skb)->origlen = skb->len; + if (pskb_trim(skb, snaplen)) goto drop_n_acct; @@ -582,11 +599,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe 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_PARTIAL) - status |= TP_STATUS_CSUMNOTREADY; } } + if (skb->ip_summed == CHECKSUM_PARTIAL) + status |= TP_STATUS_CSUMNOTREADY; + snaplen = skb->len; res = run_filter(skb, sk, snaplen); @@ -623,7 +641,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe spin_lock(&sk->sk_receive_queue.lock); h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head); - + if (h->tp_status) goto ring_is_full; po->head = po->head != po->frame_max ? po->head+1 : 0; @@ -642,7 +660,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe h->tp_snaplen = snaplen; h->tp_mac = macoff; h->tp_net = netoff; - if (skb->tstamp.off_sec == 0) { + if (skb->tstamp.off_sec == 0) { __net_timestamp(skb); sock_enable_timestamp(sk); } @@ -682,7 +700,7 @@ drop_n_restore: skb->len = skb_len; } drop: - kfree_skb(skb); + kfree_skb(skb); return 0; ring_is_full: @@ -710,9 +728,9 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, int ifindex, err, reserve = 0; /* - * Get and verify the address. + * Get and verify the address. */ - + if (saddr == NULL) { struct packet_sock *po = pkt_sk(sk); @@ -921,11 +939,11 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add char name[15]; struct net_device *dev; int err = -ENODEV; - + /* * Check legality */ - + if (addr_len != sizeof(struct sockaddr)) return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); @@ -950,7 +968,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len /* * Check legality */ - + if (addr_len < sizeof(struct sockaddr_ll)) return -EINVAL; if (sll->sll_family != AF_PACKET) @@ -977,7 +995,7 @@ static struct proto packet_proto = { }; /* - * Create a packet of type SOCK_PACKET. + * Create a packet of type SOCK_PACKET. */ static int packet_create(struct socket *sock, int protocol) @@ -1079,7 +1097,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err); /* - * An error occurred so return it. Because skb_recv_datagram() + * An error occurred so return it. Because skb_recv_datagram() * handles the blocking we don't see and worry about blocking * retries. */ @@ -1092,7 +1110,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, * it in now. */ - sll = (struct sockaddr_ll*)skb->cb; + sll = &PACKET_SKB_CB(skb)->sa.ll; if (sock->type == SOCK_PACKET) msg->msg_namelen = sizeof(struct sockaddr_pkt); else @@ -1117,7 +1135,22 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, sock_recv_timestamp(msg, sk, skb); if (msg->msg_name) - memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, + msg->msg_namelen); + + if (pkt_sk(sk)->auxdata) { + struct tpacket_auxdata aux; + + aux.tp_status = TP_STATUS_USER; + if (skb->ip_summed == CHECKSUM_PARTIAL) + aux.tp_status |= TP_STATUS_CSUMNOTREADY; + aux.tp_len = PACKET_SKB_CB(skb)->origlen; + aux.tp_snaplen = skb->len; + aux.tp_mac = 0; + aux.tp_net = skb->nh.raw - skb->data; + + put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); + } /* * Free or return the buffer as appropriate. Again this @@ -1317,6 +1350,7 @@ static int packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); int ret; if (level != SOL_PACKET) @@ -1324,7 +1358,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv switch(optname) { #ifdef CONFIG_PACKET_MULTICAST - case PACKET_ADD_MEMBERSHIP: + case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { struct packet_mreq_max mreq; @@ -1369,6 +1403,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return 0; } #endif + case PACKET_AUXDATA: + { + int val; + + if (optlen < sizeof(val)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + + po->auxdata = !!val; + return 0; + } default: return -ENOPROTOOPT; } @@ -1378,8 +1424,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { int len; + int val; struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); + void *data; + struct tpacket_stats st; if (level != SOL_PACKET) return -ENOPROTOOPT; @@ -1389,12 +1438,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, if (len < 0) return -EINVAL; - + switch(optname) { case PACKET_STATISTICS: - { - struct tpacket_stats st; - if (len > sizeof(struct tpacket_stats)) len = sizeof(struct tpacket_stats); spin_lock_bh(&sk->sk_receive_queue.lock); @@ -1403,16 +1449,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, spin_unlock_bh(&sk->sk_receive_queue.lock); st.tp_packets += st.tp_drops; - if (copy_to_user(optval, &st, len)) - return -EFAULT; + data = &st; + break; + case PACKET_AUXDATA: + if (len > sizeof(int)) + len = sizeof(int); + val = po->auxdata; + + data = &val; break; - } default: return -ENOPROTOOPT; } if (put_user(len, optlen)) return -EFAULT; + if (copy_to_user(optval, data, len)) + return -EFAULT; return 0; } @@ -1494,7 +1547,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, } case SIOCGSTAMP: return sock_get_timestamp(sk, (struct timeval __user *)arg); - + #ifdef CONFIG_INET case SIOCADDRT: case SIOCDELRT: @@ -1555,7 +1608,7 @@ static void packet_mm_open(struct vm_area_struct *vma) struct file *file = vma->vm_file; struct socket * sock = file->private_data; struct sock *sk = sock->sk; - + if (sk) atomic_inc(&pkt_sk(sk)->mapped); } @@ -1565,7 +1618,7 @@ static void packet_mm_close(struct vm_area_struct *vma) struct file *file = vma->vm_file; struct socket * sock = file->private_data; struct sock *sk = sock->sk; - + if (sk) atomic_dec(&pkt_sk(sk)->mapped); } @@ -1629,7 +1682,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing int was_running, order = 0; __be16 num; int err = 0; - + if (req->tp_block_nr) { int i, l; @@ -1691,7 +1744,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing __sock_put(sk); } spin_unlock(&po->bind_lock); - + synchronize_net(); err = -EBUSY; @@ -1808,7 +1861,7 @@ static const struct proto_ops packet_ops = { .connect = sock_no_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, - .getname = packet_getname, + .getname = packet_getname, .poll = packet_poll, .ioctl = packet_ioctl, .listen = sock_no_listen, @@ -1853,17 +1906,17 @@ static void *packet_seq_start(struct seq_file *seq, loff_t *pos) static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; - return (v == SEQ_START_TOKEN) - ? sk_head(&packet_sklist) + return (v == SEQ_START_TOKEN) + ? sk_head(&packet_sklist) : sk_next((struct sock*)v) ; } static void packet_seq_stop(struct seq_file *seq, void *v) { - read_unlock(&packet_sklist_lock); + read_unlock(&packet_sklist_lock); } -static int packet_seq_show(struct seq_file *seq, void *v) +static int packet_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_puts(seq, "sk RefCnt Type Proto Iface R Rmem User Inode\n"); @@ -1899,7 +1952,7 @@ static int packet_seq_open(struct inode *inode, struct file *file) return seq_open(file, &packet_seq_ops); } -static struct file_operations packet_seq_fops = { +static const struct file_operations packet_seq_fops = { .owner = THIS_MODULE, .open = packet_seq_open, .read = seq_read, |