diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2011-05-08 23:11:02 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2011-05-08 23:11:02 +0200 |
commit | cded208c7ea6d107dcbfdb2e2d4622daf41c2886 (patch) | |
tree | a04a03736b0a928c2954382f924aadb105ee39cc /libdde_linux26/contrib/net | |
parent | fc82e00ca1e174cb961dea6ad37622e9b26cd899 (diff) |
remove .svn directories
Diffstat (limited to 'libdde_linux26/contrib/net')
30 files changed, 0 insertions, 18460 deletions
diff --git a/libdde_linux26/contrib/net/.svn/all-wcprops b/libdde_linux26/contrib/net/.svn/all-wcprops deleted file mode 100644 index 5af71256..00000000 --- a/libdde_linux26/contrib/net/.svn/all-wcprops +++ /dev/null @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 62 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net -END -socket.c -K 25 -svn:wc:ra_dav:version-url -V 71 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/socket.c -END diff --git a/libdde_linux26/contrib/net/.svn/entries b/libdde_linux26/contrib/net/.svn/entries deleted file mode 100644 index 042f5985..00000000 --- a/libdde_linux26/contrib/net/.svn/entries +++ /dev/null @@ -1,74 +0,0 @@ -9 - -dir -465 -http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/contrib/net -http://svn.tudos.org/repos/tudos - - - -2009-05-20T14:32:55.606606Z -455 -l4check - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -a704ac0b-3a55-4d43-a2a9-7be6f07c34fb - -netlink -dir - -sched -dir - -core -dir - -socket.c -file - - - - -2009-11-15T17:16:35.000000Z -03baa764b9a13ce360545b14ee578b06 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -58332 - -ethernet -dir - diff --git a/libdde_linux26/contrib/net/.svn/format b/libdde_linux26/contrib/net/.svn/format deleted file mode 100644 index ec635144..00000000 --- a/libdde_linux26/contrib/net/.svn/format +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/libdde_linux26/contrib/net/.svn/text-base/socket.c.svn-base b/libdde_linux26/contrib/net/.svn/text-base/socket.c.svn-base deleted file mode 100644 index 35dd7371..00000000 --- a/libdde_linux26/contrib/net/.svn/text-base/socket.c.svn-base +++ /dev/null @@ -1,2406 +0,0 @@ -/* - * NET An implementation of the SOCKET network access protocol. - * - * Version: @(#)socket.c 1.1.93 18/02/95 - * - * Authors: Orest Zborowski, <obz@Kodak.COM> - * Ross Biro - * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> - * - * Fixes: - * Anonymous : NOTSOCK/BADF cleanup. Error fix in - * shutdown() - * Alan Cox : verify_area() fixes - * Alan Cox : Removed DDI - * Jonathan Kamens : SOCK_DGRAM reconnect bug - * Alan Cox : Moved a load of checks to the very - * top level. - * Alan Cox : Move address structures to/from user - * mode above the protocol layers. - * Rob Janssen : Allow 0 length sends. - * Alan Cox : Asynchronous I/O support (cribbed from the - * tty drivers). - * Niibe Yutaka : Asynchronous I/O for writes (4.4BSD style) - * Jeff Uphoff : Made max number of sockets command-line - * configurable. - * Matti Aarnio : Made the number of sockets dynamic, - * to be allocated when needed, and mr. - * Uphoff's max is used as max to be - * allowed to allocate. - * Linus : Argh. removed all the socket allocation - * altogether: it's in the inode now. - * Alan Cox : Made sock_alloc()/sock_release() public - * for NetROM and future kernel nfsd type - * stuff. - * Alan Cox : sendmsg/recvmsg basics. - * Tom Dyas : Export net symbols. - * Marcin Dalecki : Fixed problems with CONFIG_NET="n". - * Alan Cox : Added thread locking to sys_* calls - * for sockets. May have errors at the - * moment. - * Kevin Buhr : Fixed the dumb errors in the above. - * Andi Kleen : Some small cleanups, optimizations, - * and fixed a copy_from_user() bug. - * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) - * Tigran Aivazian : Made listen(2) backlog sanity checks - * protocol-independent - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * This module is effectively the top level interface to the BSD socket - * paradigm. - * - * Based upon Swansea University Computer Society NET3.039 - */ - -#include <linux/mm.h> -#include <linux/socket.h> -#include <linux/file.h> -#include <linux/net.h> -#include <linux/interrupt.h> -#include <linux/thread_info.h> -#include <linux/rcupdate.h> -#include <linux/netdevice.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/mutex.h> -#include <linux/wanrouter.h> -#include <linux/if_bridge.h> -#include <linux/if_frad.h> -#include <linux/if_vlan.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/cache.h> -#include <linux/module.h> -#include <linux/highmem.h> -#include <linux/mount.h> -#include <linux/security.h> -#include <linux/syscalls.h> -#include <linux/compat.h> -#include <linux/kmod.h> -#include <linux/audit.h> -#include <linux/wireless.h> -#include <linux/nsproxy.h> - -#include <asm/uaccess.h> -#include <asm/unistd.h> - -#include <net/compat.h> -#include <net/wext.h> - -#include <net/sock.h> -#include <linux/netfilter.h> - -static int sock_no_open(struct inode *irrelevant, struct file *dontcare); -static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); -static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos); -static int sock_mmap(struct file *file, struct vm_area_struct *vma); - -static int sock_close(struct inode *inode, struct file *file); -static unsigned int sock_poll(struct file *file, - struct poll_table_struct *wait); -static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -static long compat_sock_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); -#endif -static int sock_fasync(int fd, struct file *filp, int on); -static ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more); -static ssize_t sock_splice_read(struct file *file, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags); - -/* - * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear - * in the operation structures but are done directly via the socketcall() multiplexor. - */ - -static const struct file_operations socket_file_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .aio_read = sock_aio_read, - .aio_write = sock_aio_write, - .poll = sock_poll, - .unlocked_ioctl = sock_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_sock_ioctl, -#endif - .mmap = sock_mmap, - .open = sock_no_open, /* special open code to disallow open via /proc */ - .release = sock_close, - .fasync = sock_fasync, - .sendpage = sock_sendpage, - .splice_write = generic_splice_sendpage, - .splice_read = sock_splice_read, -}; - -/* - * The protocol list. Each protocol is registered in here. - */ - -static DEFINE_SPINLOCK(net_family_lock); -static const struct net_proto_family *net_families[NPROTO] __read_mostly; - -/* - * Statistics counters of the socket lists - */ - -static DEFINE_PER_CPU(int, sockets_in_use) = 0; - -/* - * Support routines. - * Move socket addresses back and forth across the kernel/user - * divide and look after the messy bits. - */ - -#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - - 16 for IP, 16 for IPX, - 24 for IPv6, - about 80 for AX.25 - must be at least one bigger than - the AF_UNIX size (see net/unix/af_unix.c - :unix_mkname()). - */ - -/** - * move_addr_to_kernel - copy a socket address into kernel space - * @uaddr: Address in user space - * @kaddr: Address in kernel space - * @ulen: Length in user space - * - * The address is copied into kernel space. If the provided address is - * too long an error code of -EINVAL is returned. If the copy gives - * invalid addresses -EFAULT is returned. On a success 0 is returned. - */ - -int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr) -{ - if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) - return -EINVAL; - if (ulen == 0) - return 0; - if (copy_from_user(kaddr, uaddr, ulen)) - return -EFAULT; - return audit_sockaddr(ulen, kaddr); -} - -/** - * move_addr_to_user - copy an address to user space - * @kaddr: kernel space address - * @klen: length of address in kernel - * @uaddr: user space address - * @ulen: pointer to user length field - * - * The value pointed to by ulen on entry is the buffer length available. - * This is overwritten with the buffer space used. -EINVAL is returned - * if an overlong buffer is specified or a negative buffer size. -EFAULT - * is returned if either the buffer or the length field are not - * accessible. - * After copying the data up to the limit the user specifies, the true - * length of the data is written over the length limit the user - * specified. Zero is returned for a success. - */ - -int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr, - int __user *ulen) -{ - int err; - int len; - - err = get_user(len, ulen); - if (err) - return err; - if (len > klen) - len = klen; - if (len < 0 || len > sizeof(struct sockaddr_storage)) - return -EINVAL; - if (len) { - if (audit_sockaddr(klen, kaddr)) - return -ENOMEM; - if (copy_to_user(uaddr, kaddr, len)) - return -EFAULT; - } - /* - * "fromlen shall refer to the value before truncation.." - * 1003.1g - */ - return __put_user(klen, ulen); -} - -#define SOCKFS_MAGIC 0x534F434B - -static struct kmem_cache *sock_inode_cachep __read_mostly; - -static struct inode *sock_alloc_inode(struct super_block *sb) -{ - struct socket_alloc *ei; - - ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); - if (!ei) - return NULL; - init_waitqueue_head(&ei->socket.wait); - - ei->socket.fasync_list = NULL; - ei->socket.state = SS_UNCONNECTED; - ei->socket.flags = 0; - ei->socket.ops = NULL; - ei->socket.sk = NULL; - ei->socket.file = NULL; - - return &ei->vfs_inode; -} - -static void sock_destroy_inode(struct inode *inode) -{ - kmem_cache_free(sock_inode_cachep, - container_of(inode, struct socket_alloc, vfs_inode)); -} - -static void init_once(void *foo) -{ - struct socket_alloc *ei = (struct socket_alloc *)foo; - - inode_init_once(&ei->vfs_inode); -} - -static int init_inodecache(void) -{ - sock_inode_cachep = kmem_cache_create("sock_inode_cache", - sizeof(struct socket_alloc), - 0, - (SLAB_HWCACHE_ALIGN | - SLAB_RECLAIM_ACCOUNT | - SLAB_MEM_SPREAD), - init_once); - if (sock_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -static struct super_operations sockfs_ops = { - .alloc_inode = sock_alloc_inode, - .destroy_inode =sock_destroy_inode, - .statfs = simple_statfs, -}; - -static int sockfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) -{ - return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, - mnt); -} - -static struct vfsmount *sock_mnt __read_mostly; - -static struct file_system_type sock_fs_type = { - .name = "sockfs", - .get_sb = sockfs_get_sb, - .kill_sb = kill_anon_super, -}; - -static int sockfs_delete_dentry(struct dentry *dentry) -{ - /* - * At creation time, we pretended this dentry was hashed - * (by clearing DCACHE_UNHASHED bit in d_flags) - * At delete time, we restore the truth : not hashed. - * (so that dput() can proceed correctly) - */ - dentry->d_flags |= DCACHE_UNHASHED; - return 0; -} - -/* - * sockfs_dname() is called from d_path(). - */ -static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) -{ - return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", - dentry->d_inode->i_ino); -} - -static struct dentry_operations sockfs_dentry_operations = { - .d_delete = sockfs_delete_dentry, - .d_dname = sockfs_dname, -}; - -/* - * Obtains the first available file descriptor and sets it up for use. - * - * These functions create file structures and maps them to fd space - * of the current process. On success it returns file descriptor - * and file struct implicitly stored in sock->file. - * Note that another thread may close file descriptor before we return - * from this function. We use the fact that now we do not refer - * to socket after mapping. If one day we will need it, this - * function will increment ref. count on file by 1. - * - * In any case returned fd MAY BE not valid! - * This race condition is unavoidable - * with shared fd spaces, we cannot solve it inside kernel, - * but we take care of internal coherence yet. - */ - -static int sock_alloc_fd(struct file **filep, int flags) -{ - int fd; - - fd = get_unused_fd_flags(flags); - if (likely(fd >= 0)) { - struct file *file = get_empty_filp(); - - *filep = file; - if (unlikely(!file)) { - put_unused_fd(fd); - return -ENFILE; - } - } else - *filep = NULL; - return fd; -} - -static int sock_attach_fd(struct socket *sock, struct file *file, int flags) -{ - struct dentry *dentry; - struct qstr name = { .name = "" }; - - dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); - if (unlikely(!dentry)) - return -ENOMEM; - - dentry->d_op = &sockfs_dentry_operations; - /* - * We dont want to push this dentry into global dentry hash table. - * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED - * This permits a working /proc/$pid/fd/XXX on sockets - */ - dentry->d_flags &= ~DCACHE_UNHASHED; - d_instantiate(dentry, SOCK_INODE(sock)); - - sock->file = file; - init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE, - &socket_file_ops); - SOCK_INODE(sock)->i_fop = &socket_file_ops; - file->f_flags = O_RDWR | (flags & O_NONBLOCK); - file->f_pos = 0; - file->private_data = sock; - - return 0; -} - -int sock_map_fd(struct socket *sock, int flags) -{ - struct file *newfile; - int fd = sock_alloc_fd(&newfile, flags); - - if (likely(fd >= 0)) { - int err = sock_attach_fd(sock, newfile, flags); - - if (unlikely(err < 0)) { - put_filp(newfile); - put_unused_fd(fd); - return err; - } - fd_install(fd, newfile); - } - return fd; -} - -static struct socket *sock_from_file(struct file *file, int *err) -{ - if (file->f_op == &socket_file_ops) - return file->private_data; /* set in sock_map_fd */ - - *err = -ENOTSOCK; - return NULL; -} - -/** - * sockfd_lookup - Go from a file number to its socket slot - * @fd: file handle - * @err: pointer to an error code return - * - * The file handle passed in is locked and the socket it is bound - * too is returned. If an error occurs the err pointer is overwritten - * with a negative errno code and NULL is returned. The function checks - * for both invalid handles and passing a handle which is not a socket. - * - * On a success the socket object pointer is returned. - */ - -struct socket *sockfd_lookup(int fd, int *err) -{ - struct file *file; - struct socket *sock; - - file = fget(fd); - if (!file) { - *err = -EBADF; - return NULL; - } - - sock = sock_from_file(file, err); - if (!sock) - fput(file); - return sock; -} - -static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) -{ - struct file *file; - struct socket *sock; - - *err = -EBADF; - file = fget_light(fd, fput_needed); - if (file) { - sock = sock_from_file(file, err); - if (sock) - return sock; - fput_light(file, *fput_needed); - } - return NULL; -} - -/** - * sock_alloc - allocate a socket - * - * Allocate a new inode and socket object. The two are bound together - * and initialised. The socket is then returned. If we are out of inodes - * NULL is returned. - */ - -static struct socket *sock_alloc(void) -{ - struct inode *inode; - struct socket *sock; - - inode = new_inode(sock_mnt->mnt_sb); - if (!inode) - return NULL; - - sock = SOCKET_I(inode); - - inode->i_mode = S_IFSOCK | S_IRWXUGO; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); - - get_cpu_var(sockets_in_use)++; - put_cpu_var(sockets_in_use); - return sock; -} - -/* - * In theory you can't get an open on this inode, but /proc provides - * a back door. Remember to keep it shut otherwise you'll let the - * creepy crawlies in. - */ - -static int sock_no_open(struct inode *irrelevant, struct file *dontcare) -{ - return -ENXIO; -} - -const struct file_operations bad_sock_fops = { - .owner = THIS_MODULE, - .open = sock_no_open, -}; - -/** - * sock_release - close a socket - * @sock: socket to close - * - * The socket is released from the protocol stack if it has a release - * callback, and the inode is then released if the socket is bound to - * an inode not a file. - */ - -void sock_release(struct socket *sock) -{ - if (sock->ops) { - struct module *owner = sock->ops->owner; - - sock->ops->release(sock); - sock->ops = NULL; - module_put(owner); - } - - if (sock->fasync_list) - printk(KERN_ERR "sock_release: fasync list not empty!\n"); - - get_cpu_var(sockets_in_use)--; - put_cpu_var(sockets_in_use); - if (!sock->file) { - iput(SOCK_INODE(sock)); - return; - } - sock->file = NULL; -} - -static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size) -{ - struct sock_iocb *si = kiocb_to_siocb(iocb); - int err; - - si->sock = sock; - si->scm = NULL; - si->msg = msg; - si->size = size; - - err = security_socket_sendmsg(sock, msg, size); - if (err) - return err; - - return sock->ops->sendmsg(iocb, sock, msg, size); -} - -int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) -{ - struct kiocb iocb; - struct sock_iocb siocb; - int ret; - - init_sync_kiocb(&iocb, NULL); - iocb.private = &siocb; - ret = __sock_sendmsg(&iocb, sock, msg, size); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&iocb); - return ret; -} - -int kernel_sendmsg(struct socket *sock, struct msghdr *msg, - struct kvec *vec, size_t num, size_t size) -{ - mm_segment_t oldfs = get_fs(); - int result; - - set_fs(KERNEL_DS); - /* - * the following is safe, since for compiler definitions of kvec and - * iovec are identical, yielding the same in-core layout and alignment - */ - msg->msg_iov = (struct iovec *)vec; - msg->msg_iovlen = num; - result = sock_sendmsg(sock, msg, size); - set_fs(oldfs); - return result; -} - -/* - * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) - */ -void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) -{ - ktime_t kt = skb->tstamp; - - if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { - struct timeval tv; - /* Race occurred between timestamp enabling and packet - receiving. Fill in the current time for now. */ - if (kt.tv64 == 0) - kt = ktime_get_real(); - skb->tstamp = kt; - tv = ktime_to_timeval(kt); - put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv); - } else { - struct timespec ts; - /* Race occurred between timestamp enabling and packet - receiving. Fill in the current time for now. */ - if (kt.tv64 == 0) - kt = ktime_get_real(); - skb->tstamp = kt; - ts = ktime_to_timespec(kt); - put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(ts), &ts); - } -} - -EXPORT_SYMBOL_GPL(__sock_recv_timestamp); - -static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size, int flags) -{ - int err; - struct sock_iocb *si = kiocb_to_siocb(iocb); - - si->sock = sock; - si->scm = NULL; - si->msg = msg; - si->size = size; - si->flags = flags; - - err = security_socket_recvmsg(sock, msg, size, flags); - if (err) - return err; - - return sock->ops->recvmsg(iocb, sock, msg, size, flags); -} - -int sock_recvmsg(struct socket *sock, struct msghdr *msg, - size_t size, int flags) -{ - struct kiocb iocb; - struct sock_iocb siocb; - int ret; - - init_sync_kiocb(&iocb, NULL); - iocb.private = &siocb; - ret = __sock_recvmsg(&iocb, sock, msg, size, flags); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&iocb); - return ret; -} - -int kernel_recvmsg(struct socket *sock, struct msghdr *msg, - struct kvec *vec, size_t num, size_t size, int flags) -{ - mm_segment_t oldfs = get_fs(); - int result; - - set_fs(KERNEL_DS); - /* - * the following is safe, since for compiler definitions of kvec and - * iovec are identical, yielding the same in-core layout and alignment - */ - msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; - result = sock_recvmsg(sock, msg, size, flags); - set_fs(oldfs); - return result; -} - -static void sock_aio_dtor(struct kiocb *iocb) -{ - kfree(iocb->private); -} - -static ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more) -{ - struct socket *sock; - int flags; - - sock = file->private_data; - - flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; - if (more) - flags |= MSG_MORE; - - return sock->ops->sendpage(sock, page, offset, size, flags); -} - -static ssize_t sock_splice_read(struct file *file, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) -{ - struct socket *sock = file->private_data; - - if (unlikely(!sock->ops->splice_read)) - return -EINVAL; - - return sock->ops->splice_read(sock, ppos, pipe, len, flags); -} - -static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, - struct sock_iocb *siocb) -{ - if (!is_sync_kiocb(iocb)) { - siocb = kmalloc(sizeof(*siocb), GFP_KERNEL); - if (!siocb) - return NULL; - iocb->ki_dtor = sock_aio_dtor; - } - - siocb->kiocb = iocb; - iocb->private = siocb; - return siocb; -} - -static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, - struct file *file, const struct iovec *iov, - unsigned long nr_segs) -{ - struct socket *sock = file->private_data; - size_t size = 0; - int i; - - for (i = 0; i < nr_segs; i++) - size += iov[i].iov_len; - - msg->msg_name = NULL; - msg->msg_namelen = 0; - msg->msg_control = NULL; - msg->msg_controllen = 0; - msg->msg_iov = (struct iovec *)iov; - msg->msg_iovlen = nr_segs; - msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; - - return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); -} - -static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) -{ - struct sock_iocb siocb, *x; - - if (pos != 0) - return -ESPIPE; - - if (iocb->ki_left == 0) /* Match SYS5 behaviour */ - return 0; - - - x = alloc_sock_iocb(iocb, &siocb); - if (!x) - return -ENOMEM; - return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); -} - -static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, - struct file *file, const struct iovec *iov, - unsigned long nr_segs) -{ - struct socket *sock = file->private_data; - size_t size = 0; - int i; - - for (i = 0; i < nr_segs; i++) - size += iov[i].iov_len; - - msg->msg_name = NULL; - msg->msg_namelen = 0; - msg->msg_control = NULL; - msg->msg_controllen = 0; - msg->msg_iov = (struct iovec *)iov; - msg->msg_iovlen = nr_segs; - msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; - if (sock->type == SOCK_SEQPACKET) - msg->msg_flags |= MSG_EOR; - - return __sock_sendmsg(iocb, sock, msg, size); -} - -static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) -{ - struct sock_iocb siocb, *x; - - if (pos != 0) - return -ESPIPE; - - x = alloc_sock_iocb(iocb, &siocb); - if (!x) - return -ENOMEM; - - return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); -} - -/* - * Atomic setting of ioctl hooks to avoid race - * with module unload. - */ - -static DEFINE_MUTEX(br_ioctl_mutex); -static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg) = NULL; - -void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) -{ - mutex_lock(&br_ioctl_mutex); - br_ioctl_hook = hook; - mutex_unlock(&br_ioctl_mutex); -} - -EXPORT_SYMBOL(brioctl_set); - -static DEFINE_MUTEX(vlan_ioctl_mutex); -static int (*vlan_ioctl_hook) (struct net *, void __user *arg); - -void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) -{ - mutex_lock(&vlan_ioctl_mutex); - vlan_ioctl_hook = hook; - mutex_unlock(&vlan_ioctl_mutex); -} - -EXPORT_SYMBOL(vlan_ioctl_set); - -static DEFINE_MUTEX(dlci_ioctl_mutex); -static int (*dlci_ioctl_hook) (unsigned int, void __user *); - -void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) -{ - mutex_lock(&dlci_ioctl_mutex); - dlci_ioctl_hook = hook; - mutex_unlock(&dlci_ioctl_mutex); -} - -EXPORT_SYMBOL(dlci_ioctl_set); - -/* - * With an ioctl, arg may well be a user mode pointer, but we don't know - * what to do with it - that's up to the protocol still. - */ - -static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - struct socket *sock; - struct sock *sk; - void __user *argp = (void __user *)arg; - int pid, err; - struct net *net; - - sock = file->private_data; - sk = sock->sk; - net = sock_net(sk); - if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - err = dev_ioctl(net, cmd, argp); - } else -#ifdef CONFIG_WIRELESS_EXT - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - err = dev_ioctl(net, cmd, argp); - } else -#endif /* CONFIG_WIRELESS_EXT */ - switch (cmd) { - case FIOSETOWN: - case SIOCSPGRP: - err = -EFAULT; - if (get_user(pid, (int __user *)argp)) - break; - err = f_setown(sock->file, pid, 1); - break; - case FIOGETOWN: - case SIOCGPGRP: - err = put_user(f_getown(sock->file), - (int __user *)argp); - break; - case SIOCGIFBR: - case SIOCSIFBR: - case SIOCBRADDBR: - case SIOCBRDELBR: - err = -ENOPKG; - if (!br_ioctl_hook) - request_module("bridge"); - - mutex_lock(&br_ioctl_mutex); - if (br_ioctl_hook) - err = br_ioctl_hook(net, cmd, argp); - mutex_unlock(&br_ioctl_mutex); - break; - case SIOCGIFVLAN: - case SIOCSIFVLAN: - err = -ENOPKG; - if (!vlan_ioctl_hook) - request_module("8021q"); - - mutex_lock(&vlan_ioctl_mutex); - if (vlan_ioctl_hook) - err = vlan_ioctl_hook(net, argp); - mutex_unlock(&vlan_ioctl_mutex); - break; - case SIOCADDDLCI: - case SIOCDELDLCI: - err = -ENOPKG; - if (!dlci_ioctl_hook) - request_module("dlci"); - - mutex_lock(&dlci_ioctl_mutex); - if (dlci_ioctl_hook) - err = dlci_ioctl_hook(cmd, argp); - mutex_unlock(&dlci_ioctl_mutex); - break; - default: - err = sock->ops->ioctl(sock, cmd, arg); - - /* - * If this ioctl is unknown try to hand it down - * to the NIC driver. - */ - if (err == -ENOIOCTLCMD) - err = dev_ioctl(net, cmd, argp); - break; - } - return err; -} - -int sock_create_lite(int family, int type, int protocol, struct socket **res) -{ - int err; - struct socket *sock = NULL; - - err = security_socket_create(family, type, protocol, 1); - if (err) - goto out; - - sock = sock_alloc(); - if (!sock) { - err = -ENOMEM; - goto out; - } - - sock->type = type; - err = security_socket_post_create(sock, family, type, protocol, 1); - if (err) - goto out_release; - -out: - *res = sock; - return err; -out_release: - sock_release(sock); - sock = NULL; - goto out; -} - -/* No kernel lock held - perfect */ -static unsigned int sock_poll(struct file *file, poll_table *wait) -{ - struct socket *sock; - - /* - * We can't return errors to poll, so it's either yes or no. - */ - sock = file->private_data; - return sock->ops->poll(file, sock, wait); -} - -static int sock_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct socket *sock = file->private_data; - - return sock->ops->mmap(file, sock, vma); -} - -static int sock_close(struct inode *inode, struct file *filp) -{ - /* - * It was possible the inode is NULL we were - * closing an unfinished socket. - */ - - if (!inode) { - printk(KERN_DEBUG "sock_close: NULL inode\n"); - return 0; - } - sock_release(SOCKET_I(inode)); - return 0; -} - -/* - * Update the socket async list - * - * Fasync_list locking strategy. - * - * 1. fasync_list is modified only under process context socket lock - * i.e. under semaphore. - * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) - * or under socket lock. - * 3. fasync_list can be used from softirq context, so that - * modification under socket lock have to be enhanced with - * write_lock_bh(&sk->sk_callback_lock). - * --ANK (990710) - */ - -static int sock_fasync(int fd, struct file *filp, int on) -{ - struct fasync_struct *fa, *fna = NULL, **prev; - struct socket *sock; - struct sock *sk; - - if (on) { - fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); - if (fna == NULL) - return -ENOMEM; - } - - sock = filp->private_data; - - sk = sock->sk; - if (sk == NULL) { - kfree(fna); - return -EINVAL; - } - - lock_sock(sk); - - prev = &(sock->fasync_list); - - for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev) - if (fa->fa_file == filp) - break; - - if (on) { - if (fa != NULL) { - write_lock_bh(&sk->sk_callback_lock); - fa->fa_fd = fd; - write_unlock_bh(&sk->sk_callback_lock); - - kfree(fna); - goto out; - } - fna->fa_file = filp; - fna->fa_fd = fd; - fna->magic = FASYNC_MAGIC; - fna->fa_next = sock->fasync_list; - write_lock_bh(&sk->sk_callback_lock); - sock->fasync_list = fna; - write_unlock_bh(&sk->sk_callback_lock); - } else { - if (fa != NULL) { - write_lock_bh(&sk->sk_callback_lock); - *prev = fa->fa_next; - write_unlock_bh(&sk->sk_callback_lock); - kfree(fa); - } - } - -out: - release_sock(sock->sk); - return 0; -} - -/* This function may be called only under socket lock or callback_lock */ - -int sock_wake_async(struct socket *sock, int how, int band) -{ - if (!sock || !sock->fasync_list) - return -1; - switch (how) { - case SOCK_WAKE_WAITD: - if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) - break; - goto call_kill; - case SOCK_WAKE_SPACE: - if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) - break; - /* fall through */ - case SOCK_WAKE_IO: -call_kill: - __kill_fasync(sock->fasync_list, SIGIO, band); - break; - case SOCK_WAKE_URG: - __kill_fasync(sock->fasync_list, SIGURG, band); - } - return 0; -} - -static int __sock_create(struct net *net, int family, int type, int protocol, - struct socket **res, int kern) -{ - int err; - struct socket *sock; - const struct net_proto_family *pf; - - /* - * Check protocol is in range - */ - if (family < 0 || family >= NPROTO) - return -EAFNOSUPPORT; - if (type < 0 || type >= SOCK_MAX) - return -EINVAL; - - /* Compatibility. - - This uglymoron is moved from INET layer to here to avoid - deadlock in module load. - */ - if (family == PF_INET && type == SOCK_PACKET) { - static int warned; - if (!warned) { - warned = 1; - printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", - current->comm); - } - family = PF_PACKET; - } - - err = security_socket_create(family, type, protocol, kern); - if (err) - return err; - - /* - * Allocate the socket and allow the family to set things up. if - * the protocol is 0, the family is instructed to select an appropriate - * default. - */ - sock = sock_alloc(); - if (!sock) { - if (net_ratelimit()) - printk(KERN_WARNING "socket: no more sockets\n"); - return -ENFILE; /* Not exactly a match, but its the - closest posix thing */ - } - - sock->type = type; - -#ifdef CONFIG_MODULES - /* Attempt to load a protocol module if the find failed. - * - * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user - * requested real, full-featured networking support upon configuration. - * Otherwise module support will break! - */ - if (net_families[family] == NULL) - request_module("net-pf-%d", family); -#endif - - rcu_read_lock(); - pf = rcu_dereference(net_families[family]); - err = -EAFNOSUPPORT; - if (!pf) - goto out_release; - - /* - * We will call the ->create function, that possibly is in a loadable - * module, so we have to bump that loadable module refcnt first. - */ - if (!try_module_get(pf->owner)) - goto out_release; - - /* Now protected by module ref count */ - rcu_read_unlock(); - - err = pf->create(net, sock, protocol); - if (err < 0) - goto out_module_put; - - /* - * Now to bump the refcnt of the [loadable] module that owns this - * socket at sock_release time we decrement its refcnt. - */ - if (!try_module_get(sock->ops->owner)) - goto out_module_busy; - - /* - * Now that we're done with the ->create function, the [loadable] - * module can have its refcnt decremented - */ - module_put(pf->owner); - err = security_socket_post_create(sock, family, type, protocol, kern); - if (err) - goto out_sock_release; - *res = sock; - - return 0; - -out_module_busy: - err = -EAFNOSUPPORT; -out_module_put: - sock->ops = NULL; - module_put(pf->owner); -out_sock_release: - sock_release(sock); - return err; - -out_release: - rcu_read_unlock(); - goto out_sock_release; -} - -int sock_create(int family, int type, int protocol, struct socket **res) -{ - return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); -} - -int sock_create_kern(int family, int type, int protocol, struct socket **res) -{ - return __sock_create(&init_net, family, type, protocol, res, 1); -} - -SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) -{ - int retval; - struct socket *sock; - int flags; - - /* Check the SOCK_* constants for consistency. */ - BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); - BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); - BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); - BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); - - flags = type & ~SOCK_TYPE_MASK; - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return -EINVAL; - type &= SOCK_TYPE_MASK; - - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - - retval = sock_create(family, type, protocol, &sock); - if (retval < 0) - goto out; - - retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); - if (retval < 0) - goto out_release; - -out: - /* It may be already another descriptor 8) Not kernel problem. */ - return retval; - -out_release: - sock_release(sock); - return retval; -} - -/* - * Create a pair of connected sockets. - */ - -SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, - int __user *, usockvec) -{ - struct socket *sock1, *sock2; - int fd1, fd2, err; - struct file *newfile1, *newfile2; - int flags; - - flags = type & ~SOCK_TYPE_MASK; - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return -EINVAL; - type &= SOCK_TYPE_MASK; - - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - - /* - * Obtain the first socket and check if the underlying protocol - * supports the socketpair call. - */ - - err = sock_create(family, type, protocol, &sock1); - if (err < 0) - goto out; - - err = sock_create(family, type, protocol, &sock2); - if (err < 0) - goto out_release_1; - - err = sock1->ops->socketpair(sock1, sock2); - if (err < 0) - goto out_release_both; - - fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC); - if (unlikely(fd1 < 0)) { - err = fd1; - goto out_release_both; - } - - fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC); - if (unlikely(fd2 < 0)) { - err = fd2; - put_filp(newfile1); - put_unused_fd(fd1); - goto out_release_both; - } - - err = sock_attach_fd(sock1, newfile1, flags & O_NONBLOCK); - if (unlikely(err < 0)) { - goto out_fd2; - } - - err = sock_attach_fd(sock2, newfile2, flags & O_NONBLOCK); - if (unlikely(err < 0)) { - fput(newfile1); - goto out_fd1; - } - - audit_fd_pair(fd1, fd2); - fd_install(fd1, newfile1); - fd_install(fd2, newfile2); - /* fd1 and fd2 may be already another descriptors. - * Not kernel problem. - */ - - err = put_user(fd1, &usockvec[0]); - if (!err) - err = put_user(fd2, &usockvec[1]); - if (!err) - return 0; - - sys_close(fd2); - sys_close(fd1); - return err; - -out_release_both: - sock_release(sock2); -out_release_1: - sock_release(sock1); -out: - return err; - -out_fd2: - put_filp(newfile1); - sock_release(sock1); -out_fd1: - put_filp(newfile2); - sock_release(sock2); - put_unused_fd(fd1); - put_unused_fd(fd2); - goto out; -} - -/* - * Bind a name to a socket. Nothing much to do here since it's - * the protocol's responsibility to handle the local address. - * - * We move the socket address to kernel space before we call - * the protocol layer (having also checked the address is ok). - */ - -SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) -{ - struct socket *sock; - struct sockaddr_storage address; - int err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock) { - err = move_addr_to_kernel(umyaddr, addrlen, (struct sockaddr *)&address); - if (err >= 0) { - err = security_socket_bind(sock, - (struct sockaddr *)&address, - addrlen); - if (!err) - err = sock->ops->bind(sock, - (struct sockaddr *) - &address, addrlen); - } - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Perform a listen. Basically, we allow the protocol to do anything - * necessary for a listen, and if that works, we mark the socket as - * ready for listening. - */ - -SYSCALL_DEFINE2(listen, int, fd, int, backlog) -{ - struct socket *sock; - int err, fput_needed; - int somaxconn; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock) { - somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; - if ((unsigned)backlog > somaxconn) - backlog = somaxconn; - - err = security_socket_listen(sock, backlog); - if (!err) - err = sock->ops->listen(sock, backlog); - - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * For accept, we attempt to create a new socket, set up the link - * with the client, wake up the client, then return the new - * connected fd. We collect the address of the connector in kernel - * space and move it to user at the very end. This is unclean because - * we open the socket then return an error. - * - * 1003.1g adds the ability to recvmsg() to query connection pending - * status to recvmsg. We need to add that support in a way thats - * clean when we restucture accept also. - */ - -SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, - int __user *, upeer_addrlen, int, flags) -{ - struct socket *sock, *newsock; - struct file *newfile; - int err, len, newfd, fput_needed; - struct sockaddr_storage address; - - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return -EINVAL; - - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = -ENFILE; - if (!(newsock = sock_alloc())) - goto out_put; - - newsock->type = sock->type; - newsock->ops = sock->ops; - - /* - * We don't need try_module_get here, as the listening socket (sock) - * has the protocol module (sock->ops->owner) held. - */ - __module_get(newsock->ops->owner); - - newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC); - if (unlikely(newfd < 0)) { - err = newfd; - sock_release(newsock); - goto out_put; - } - - err = sock_attach_fd(newsock, newfile, flags & O_NONBLOCK); - if (err < 0) - goto out_fd_simple; - - err = security_socket_accept(sock, newsock); - if (err) - goto out_fd; - - err = sock->ops->accept(sock, newsock, sock->file->f_flags); - if (err < 0) - goto out_fd; - - if (upeer_sockaddr) { - if (newsock->ops->getname(newsock, (struct sockaddr *)&address, - &len, 2) < 0) { - err = -ECONNABORTED; - goto out_fd; - } - err = move_addr_to_user((struct sockaddr *)&address, - len, upeer_sockaddr, upeer_addrlen); - if (err < 0) - goto out_fd; - } - - /* File flags are not inherited via accept() unlike another OSes. */ - - fd_install(newfd, newfile); - err = newfd; - - security_socket_post_accept(sock, newsock); - -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -out_fd_simple: - sock_release(newsock); - put_filp(newfile); - put_unused_fd(newfd); - goto out_put; -out_fd: - fput(newfile); - put_unused_fd(newfd); - goto out_put; -} - -SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, - int __user *, upeer_addrlen) -{ - return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); -} - -/* - * Attempt to connect to a socket with the server address. The address - * is in user space so we verify it is OK and move it to kernel space. - * - * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to - * break bindings - * - * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and - * other SEQPACKET protocols that take time to connect() as it doesn't - * include the -EINPROGRESS status for such sockets. - */ - -SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, - int, addrlen) -{ - struct socket *sock; - struct sockaddr_storage address; - int err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - err = move_addr_to_kernel(uservaddr, addrlen, (struct sockaddr *)&address); - if (err < 0) - goto out_put; - - err = - security_socket_connect(sock, (struct sockaddr *)&address, addrlen); - if (err) - goto out_put; - - err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, - sock->file->f_flags); -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Get the local address ('name') of a socket object. Move the obtained - * name to user space. - */ - -SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, - int __user *, usockaddr_len) -{ - struct socket *sock; - struct sockaddr_storage address; - int len, err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = security_socket_getsockname(sock); - if (err) - goto out_put; - - err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); - if (err) - goto out_put; - err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, usockaddr_len); - -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Get the remote address ('name') of a socket object. Move the obtained - * name to user space. - */ - -SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, - int __user *, usockaddr_len) -{ - struct socket *sock; - struct sockaddr_storage address; - int len, err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_getpeername(sock); - if (err) { - fput_light(sock->file, fput_needed); - return err; - } - - err = - sock->ops->getname(sock, (struct sockaddr *)&address, &len, - 1); - if (!err) - err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, - usockaddr_len); - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Send a datagram to a given address. We move the address into kernel - * space and check the user space data area is readable before invoking - * the protocol. - */ - -SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, - unsigned, flags, struct sockaddr __user *, addr, - int, addr_len) -{ - struct socket *sock; - struct sockaddr_storage address; - int err; - struct msghdr msg; - struct iovec iov; - int fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - iov.iov_base = buff; - iov.iov_len = len; - msg.msg_name = NULL; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_namelen = 0; - if (addr) { - err = move_addr_to_kernel(addr, addr_len, (struct sockaddr *)&address); - if (err < 0) - goto out_put; - msg.msg_name = (struct sockaddr *)&address; - msg.msg_namelen = addr_len; - } - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - msg.msg_flags = flags; - err = sock_sendmsg(sock, &msg, len); - -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Send a datagram down a socket. - */ - -SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, - unsigned, flags) -{ - return sys_sendto(fd, buff, len, flags, NULL, 0); -} - -/* - * Receive a frame from the socket and optionally record the address of the - * sender. We verify the buffers are writable and if needed move the - * sender address from kernel to user space. - */ - -SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, - unsigned, flags, struct sockaddr __user *, addr, - int __user *, addr_len) -{ - struct socket *sock; - struct iovec iov; - struct msghdr msg; - struct sockaddr_storage address; - int err, err2; - int fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_iovlen = 1; - msg.msg_iov = &iov; - iov.iov_len = size; - iov.iov_base = ubuf; - msg.msg_name = (struct sockaddr *)&address; - msg.msg_namelen = sizeof(address); - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &msg, size, flags); - - if (err >= 0 && addr != NULL) { - err2 = move_addr_to_user((struct sockaddr *)&address, - msg.msg_namelen, addr, addr_len); - if (err2 < 0) - err = err2; - } - - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Receive a datagram from a socket. - */ - -asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size, - unsigned flags) -{ - return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); -} - -/* - * Set a socket option. Because we don't know the option lengths we have - * to pass the user mode parameter for the protocols to sort out. - */ - -SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, - char __user *, optval, int, optlen) -{ - int err, fput_needed; - struct socket *sock; - - if (optlen < 0) - return -EINVAL; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_setsockopt(sock, level, optname); - if (err) - goto out_put; - - if (level == SOL_SOCKET) - err = - sock_setsockopt(sock, level, optname, optval, - optlen); - else - err = - sock->ops->setsockopt(sock, level, optname, optval, - optlen); -out_put: - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Get a socket option. Because we don't know the option lengths we have - * to pass a user mode parameter for the protocols to sort out. - */ - -SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, - char __user *, optval, int __user *, optlen) -{ - int err, fput_needed; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_getsockopt(sock, level, optname); - if (err) - goto out_put; - - if (level == SOL_SOCKET) - err = - sock_getsockopt(sock, level, optname, optval, - optlen); - else - err = - sock->ops->getsockopt(sock, level, optname, optval, - optlen); -out_put: - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Shutdown a socket. - */ - -SYSCALL_DEFINE2(shutdown, int, fd, int, how) -{ - int err, fput_needed; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_shutdown(sock, how); - if (!err) - err = sock->ops->shutdown(sock, how); - fput_light(sock->file, fput_needed); - } - return err; -} - -/* A couple of helpful macros for getting the address of the 32/64 bit - * fields which are the same type (int / unsigned) on our platforms. - */ -#define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) -#define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) -#define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) - -/* - * BSD sendmsg interface - */ - -SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) -{ - struct compat_msghdr __user *msg_compat = - (struct compat_msghdr __user *)msg; - struct socket *sock; - struct sockaddr_storage address; - struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; - unsigned char ctl[sizeof(struct cmsghdr) + 20] - __attribute__ ((aligned(sizeof(__kernel_size_t)))); - /* 20 is size of ipv6_pktinfo */ - unsigned char *ctl_buf = ctl; - struct msghdr msg_sys; - int err, ctl_len, iov_size, total_len; - int fput_needed; - - err = -EFAULT; - if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(&msg_sys, msg_compat)) - return -EFAULT; - } - else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) - return -EFAULT; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - /* do not move before msg_sys is valid */ - err = -EMSGSIZE; - if (msg_sys.msg_iovlen > UIO_MAXIOV) - goto out_put; - - /* Check whether to allocate the iovec area */ - err = -ENOMEM; - iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); - if (msg_sys.msg_iovlen > UIO_FASTIOV) { - iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); - if (!iov) - goto out_put; - } - - /* This will also move the address data into kernel space */ - if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(&msg_sys, iov, - (struct sockaddr *)&address, - VERIFY_READ); - } else - err = verify_iovec(&msg_sys, iov, - (struct sockaddr *)&address, - VERIFY_READ); - if (err < 0) - goto out_freeiov; - total_len = err; - - err = -ENOBUFS; - - if (msg_sys.msg_controllen > INT_MAX) - goto out_freeiov; - ctl_len = msg_sys.msg_controllen; - if ((MSG_CMSG_COMPAT & flags) && ctl_len) { - err = - cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, - sizeof(ctl)); - if (err) - goto out_freeiov; - ctl_buf = msg_sys.msg_control; - ctl_len = msg_sys.msg_controllen; - } else if (ctl_len) { - if (ctl_len > sizeof(ctl)) { - ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); - if (ctl_buf == NULL) - goto out_freeiov; - } - err = -EFAULT; - /* - * Careful! Before this, msg_sys.msg_control contains a user pointer. - * Afterwards, it will be a kernel pointer. Thus the compiler-assisted - * checking falls down on this. - */ - if (copy_from_user(ctl_buf, (void __user *)msg_sys.msg_control, - ctl_len)) - goto out_freectl; - msg_sys.msg_control = ctl_buf; - } - msg_sys.msg_flags = flags; - - if (sock->file->f_flags & O_NONBLOCK) - msg_sys.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &msg_sys, total_len); - -out_freectl: - if (ctl_buf != ctl) - sock_kfree_s(sock->sk, ctl_buf, ctl_len); -out_freeiov: - if (iov != iovstack) - sock_kfree_s(sock->sk, iov, iov_size); -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * BSD recvmsg interface - */ - -SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, - unsigned int, flags) -{ - struct compat_msghdr __user *msg_compat = - (struct compat_msghdr __user *)msg; - struct socket *sock; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - struct msghdr msg_sys; - unsigned long cmsg_ptr; - int err, iov_size, total_len, len; - int fput_needed; - - /* kernel mode address */ - struct sockaddr_storage addr; - - /* user mode address pointers */ - struct sockaddr __user *uaddr; - int __user *uaddr_len; - - if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(&msg_sys, msg_compat)) - return -EFAULT; - } - else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) - return -EFAULT; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = -EMSGSIZE; - if (msg_sys.msg_iovlen > UIO_MAXIOV) - goto out_put; - - /* Check whether to allocate the iovec area */ - err = -ENOMEM; - iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); - if (msg_sys.msg_iovlen > UIO_FASTIOV) { - iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); - if (!iov) - goto out_put; - } - - /* - * Save the user-mode address (verify_iovec will change the - * kernel msghdr to use the kernel address space) - */ - - uaddr = (__force void __user *)msg_sys.msg_name; - uaddr_len = COMPAT_NAMELEN(msg); - if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(&msg_sys, iov, - (struct sockaddr *)&addr, - VERIFY_WRITE); - } else - err = verify_iovec(&msg_sys, iov, - (struct sockaddr *)&addr, - VERIFY_WRITE); - if (err < 0) - goto out_freeiov; - total_len = err; - - cmsg_ptr = (unsigned long)msg_sys.msg_control; - msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); - - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &msg_sys, total_len, flags); - if (err < 0) - goto out_freeiov; - len = err; - - if (uaddr != NULL) { - err = move_addr_to_user((struct sockaddr *)&addr, - msg_sys.msg_namelen, uaddr, - uaddr_len); - if (err < 0) - goto out_freeiov; - } - err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT), - COMPAT_FLAGS(msg)); - if (err) - goto out_freeiov; - if (MSG_CMSG_COMPAT & flags) - err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr, - &msg_compat->msg_controllen); - else - err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr, - &msg->msg_controllen); - if (err) - goto out_freeiov; - err = len; - -out_freeiov: - if (iov != iovstack) - sock_kfree_s(sock->sk, iov, iov_size); -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -#ifdef __ARCH_WANT_SYS_SOCKETCALL - -/* Argument list sizes for sys_socketcall */ -#define AL(x) ((x) * sizeof(unsigned long)) -static const unsigned char nargs[19]={ - AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), - AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), - AL(6),AL(2),AL(5),AL(5),AL(3),AL(3), - AL(4) -}; - -#undef AL - -/* - * System call vectors. - * - * Argument checking cleaned up. Saved 20% in size. - * This function doesn't need to set the kernel lock because - * it is set by the callees. - */ - -SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) -{ - unsigned long a[6]; - unsigned long a0, a1; - int err; - - if (call < 1 || call > SYS_ACCEPT4) - return -EINVAL; - - /* copy_from_user should be SMP safe. */ - if (copy_from_user(a, args, nargs[call])) - return -EFAULT; - - audit_socketcall(nargs[call] / sizeof(unsigned long), a); - - a0 = a[0]; - a1 = a[1]; - - switch (call) { - case SYS_SOCKET: - err = sys_socket(a0, a1, a[2]); - break; - case SYS_BIND: - err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); - break; - case SYS_CONNECT: - err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); - break; - case SYS_LISTEN: - err = sys_listen(a0, a1); - break; - case SYS_ACCEPT: - err = sys_accept4(a0, (struct sockaddr __user *)a1, - (int __user *)a[2], 0); - break; - case SYS_GETSOCKNAME: - err = - sys_getsockname(a0, (struct sockaddr __user *)a1, - (int __user *)a[2]); - break; - case SYS_GETPEERNAME: - err = - sys_getpeername(a0, (struct sockaddr __user *)a1, - (int __user *)a[2]); - break; - case SYS_SOCKETPAIR: - err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); - break; - case SYS_SEND: - err = sys_send(a0, (void __user *)a1, a[2], a[3]); - break; - case SYS_SENDTO: - err = sys_sendto(a0, (void __user *)a1, a[2], a[3], - (struct sockaddr __user *)a[4], a[5]); - break; - case SYS_RECV: - err = sys_recv(a0, (void __user *)a1, a[2], a[3]); - break; - case SYS_RECVFROM: - err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], - (struct sockaddr __user *)a[4], - (int __user *)a[5]); - break; - case SYS_SHUTDOWN: - err = sys_shutdown(a0, a1); - break; - case SYS_SETSOCKOPT: - err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); - break; - case SYS_GETSOCKOPT: - err = - sys_getsockopt(a0, a1, a[2], (char __user *)a[3], - (int __user *)a[4]); - break; - case SYS_SENDMSG: - err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); - break; - case SYS_RECVMSG: - err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); - break; - case SYS_ACCEPT4: - err = sys_accept4(a0, (struct sockaddr __user *)a1, - (int __user *)a[2], a[3]); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -#endif /* __ARCH_WANT_SYS_SOCKETCALL */ - -/** - * sock_register - add a socket protocol handler - * @ops: description of protocol - * - * This function is called by a protocol handler that wants to - * advertise its address family, and have it linked into the - * socket interface. The value ops->family coresponds to the - * socket system call protocol family. - */ -int sock_register(const struct net_proto_family *ops) -{ - int err; - - if (ops->family >= NPROTO) { - printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, - NPROTO); - return -ENOBUFS; - } - - spin_lock(&net_family_lock); - if (net_families[ops->family]) - err = -EEXIST; - else { - net_families[ops->family] = ops; - err = 0; - } - spin_unlock(&net_family_lock); - - printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family); - return err; -} - -/** - * sock_unregister - remove a protocol handler - * @family: protocol family to remove - * - * This function is called by a protocol handler that wants to - * remove its address family, and have it unlinked from the - * new socket creation. - * - * If protocol handler is a module, then it can use module reference - * counts to protect against new references. If protocol handler is not - * a module then it needs to provide its own protection in - * the ops->create routine. - */ -void sock_unregister(int family) -{ - BUG_ON(family < 0 || family >= NPROTO); - - spin_lock(&net_family_lock); - net_families[family] = NULL; - spin_unlock(&net_family_lock); - - synchronize_rcu(); - - printk(KERN_INFO "NET: Unregistered protocol family %d\n", family); -} - -static int __init sock_init(void) -{ - /* - * Initialize sock SLAB cache. - */ - - sk_init(); - - /* - * Initialize skbuff SLAB cache - */ - skb_init(); - - /* - * Initialize the protocols module. - */ - - init_inodecache(); - register_filesystem(&sock_fs_type); - sock_mnt = kern_mount(&sock_fs_type); - - /* The real protocol initialization is performed in later initcalls. - */ - -#ifdef CONFIG_NETFILTER - netfilter_init(); -#endif - - return 0; -} - -core_initcall(sock_init); /* early initcall */ - -#ifdef CONFIG_PROC_FS -void socket_seq_show(struct seq_file *seq) -{ - int cpu; - int counter = 0; - - for_each_possible_cpu(cpu) - counter += per_cpu(sockets_in_use, cpu); - - /* It can be negative, by the way. 8) */ - if (counter < 0) - counter = 0; - - seq_printf(seq, "sockets: used %d\n", counter); -} -#endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_COMPAT -static long compat_sock_ioctl(struct file *file, unsigned cmd, - unsigned long arg) -{ - struct socket *sock = file->private_data; - int ret = -ENOIOCTLCMD; - struct sock *sk; - struct net *net; - - sk = sock->sk; - net = sock_net(sk); - - if (sock->ops->compat_ioctl) - ret = sock->ops->compat_ioctl(sock, cmd, arg); - - if (ret == -ENOIOCTLCMD && - (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) - ret = compat_wext_handle_ioctl(net, cmd, arg); - - return ret; -} -#endif - -int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) -{ - return sock->ops->bind(sock, addr, addrlen); -} - -int kernel_listen(struct socket *sock, int backlog) -{ - return sock->ops->listen(sock, backlog); -} - -int kernel_accept(struct socket *sock, struct socket **newsock, int flags) -{ - struct sock *sk = sock->sk; - int err; - - err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, - newsock); - if (err < 0) - goto done; - - err = sock->ops->accept(sock, *newsock, flags); - if (err < 0) { - sock_release(*newsock); - *newsock = NULL; - goto done; - } - - (*newsock)->ops = sock->ops; - __module_get((*newsock)->ops->owner); - -done: - return err; -} - -int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, - int flags) -{ - return sock->ops->connect(sock, addr, addrlen, flags); -} - -int kernel_getsockname(struct socket *sock, struct sockaddr *addr, - int *addrlen) -{ - return sock->ops->getname(sock, addr, addrlen, 0); -} - -int kernel_getpeername(struct socket *sock, struct sockaddr *addr, - int *addrlen) -{ - return sock->ops->getname(sock, addr, addrlen, 1); -} - -int kernel_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - mm_segment_t oldfs = get_fs(); - int err; - - set_fs(KERNEL_DS); - if (level == SOL_SOCKET) - err = sock_getsockopt(sock, level, optname, optval, optlen); - else - err = sock->ops->getsockopt(sock, level, optname, optval, - optlen); - set_fs(oldfs); - return err; -} - -int kernel_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) -{ - mm_segment_t oldfs = get_fs(); - int err; - - set_fs(KERNEL_DS); - if (level == SOL_SOCKET) - err = sock_setsockopt(sock, level, optname, optval, optlen); - else - err = sock->ops->setsockopt(sock, level, optname, optval, - optlen); - set_fs(oldfs); - return err; -} - -int kernel_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags) -{ - if (sock->ops->sendpage) - return sock->ops->sendpage(sock, page, offset, size, flags); - - return sock_no_sendpage(sock, page, offset, size, flags); -} - -int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) -{ - mm_segment_t oldfs = get_fs(); - int err; - - set_fs(KERNEL_DS); - err = sock->ops->ioctl(sock, cmd, arg); - set_fs(oldfs); - - return err; -} - -int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) -{ - return sock->ops->shutdown(sock, how); -} - -EXPORT_SYMBOL(sock_create); -EXPORT_SYMBOL(sock_create_kern); -EXPORT_SYMBOL(sock_create_lite); -EXPORT_SYMBOL(sock_map_fd); -EXPORT_SYMBOL(sock_recvmsg); -EXPORT_SYMBOL(sock_register); -EXPORT_SYMBOL(sock_release); -EXPORT_SYMBOL(sock_sendmsg); -EXPORT_SYMBOL(sock_unregister); -EXPORT_SYMBOL(sock_wake_async); -EXPORT_SYMBOL(sockfd_lookup); -EXPORT_SYMBOL(kernel_sendmsg); -EXPORT_SYMBOL(kernel_recvmsg); -EXPORT_SYMBOL(kernel_bind); -EXPORT_SYMBOL(kernel_listen); -EXPORT_SYMBOL(kernel_accept); -EXPORT_SYMBOL(kernel_connect); -EXPORT_SYMBOL(kernel_getsockname); -EXPORT_SYMBOL(kernel_getpeername); -EXPORT_SYMBOL(kernel_getsockopt); -EXPORT_SYMBOL(kernel_setsockopt); -EXPORT_SYMBOL(kernel_sendpage); -EXPORT_SYMBOL(kernel_sock_ioctl); -EXPORT_SYMBOL(kernel_sock_shutdown); diff --git a/libdde_linux26/contrib/net/core/.svn/all-wcprops b/libdde_linux26/contrib/net/core/.svn/all-wcprops deleted file mode 100644 index 0b670d94..00000000 --- a/libdde_linux26/contrib/net/core/.svn/all-wcprops +++ /dev/null @@ -1,77 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 67 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core -END -dev.c -K 25 -svn:wc:ra_dav:version-url -V 73 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/dev.c -END -ethtool.c -K 25 -svn:wc:ra_dav:version-url -V 77 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/ethtool.c -END -sock.c -K 25 -svn:wc:ra_dav:version-url -V 74 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/sock.c -END -net-sysfs.h -K 25 -svn:wc:ra_dav:version-url -V 79 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/net-sysfs.h -END -neighbour.c -K 25 -svn:wc:ra_dav:version-url -V 79 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/neighbour.c -END -dev_mcast.c -K 25 -svn:wc:ra_dav:version-url -V 79 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/dev_mcast.c -END -filter.c -K 25 -svn:wc:ra_dav:version-url -V 76 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/filter.c -END -netevent.c -K 25 -svn:wc:ra_dav:version-url -V 78 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/netevent.c -END -rtnetlink.c -K 25 -svn:wc:ra_dav:version-url -V 79 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/rtnetlink.c -END -net-sysfs.c -K 25 -svn:wc:ra_dav:version-url -V 79 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/net-sysfs.c -END -kmap_skb.h -K 25 -svn:wc:ra_dav:version-url -V 78 -/repos/tudos/!svn/ver/188/trunk/l4/pkg/dde/linux26/contrib/net/core/kmap_skb.h -END -skb_dma_map.c -K 25 -svn:wc:ra_dav:version-url -V 81 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/core/skb_dma_map.c -END diff --git a/libdde_linux26/contrib/net/core/.svn/entries b/libdde_linux26/contrib/net/core/.svn/entries deleted file mode 100644 index 963fd146..00000000 --- a/libdde_linux26/contrib/net/core/.svn/entries +++ /dev/null @@ -1,436 +0,0 @@ -9 - -dir -465 -http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/contrib/net/core -http://svn.tudos.org/repos/tudos - - - -2009-05-20T14:32:55.606606Z -455 -l4check - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -a704ac0b-3a55-4d43-a2a9-7be6f07c34fb - -dev.c -file - - - - -2009-11-15T17:16:35.000000Z -9a23c563416176602c530d37fe7bf369 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -129785 - -ethtool.c -file - - - - -2009-11-15T17:16:35.000000Z -266e5aa6b127622f7a3b00574800a69b -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -25199 - -sock.c -file - - - - -2009-11-15T17:16:35.000000Z -d7fcc1125f9f19eb15f9662d4ce6df75 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -57794 - -net-sysfs.h -file - - - - -2009-11-15T17:16:35.000000Z -8c3cd9452327fa177f9b8150d13eb2ad -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -243 - -neighbour.c -file - - - - -2009-11-15T17:16:35.000000Z -a923815456fb10bef441bd8bbaa2b58f -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -68158 - -dev_mcast.c -file - - - - -2009-11-15T17:16:35.000000Z -6c796069f8cf28d49132eed3dc5d8110 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -5650 - -filter.c -file - - - - -2009-11-15T17:16:35.000000Z -890f8ddba6b64959215aa4baf156ee44 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -12589 - -netevent.c -file - - - - -2009-11-15T17:16:35.000000Z -bde97ba216631dd98321adc454f80d53 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -2078 - -rtnetlink.c -file - - - - -2009-11-15T17:16:35.000000Z -01f4f3b7252455460ce9c46f34f1351a -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -34276 - -net-sysfs.c -file - - - - -2009-11-15T17:16:35.000000Z -54928f891b5e2e40336074eca26a2b2b -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -14072 - -kmap_skb.h -file - - - - -2009-11-15T17:16:35.000000Z -dd4f4f93c1ab135f2d31314d41b1c373 -2007-09-13T02:53:43.697541Z -188 -l4check - - - - - - - - - - - - - - - - - - - - - -360 - -skb_dma_map.c -file - - - - -2009-11-15T17:16:35.000000Z -dd4a1adb13e56cb4ecf75c1f4b7d6aa9 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -1468 - diff --git a/libdde_linux26/contrib/net/core/.svn/format b/libdde_linux26/contrib/net/core/.svn/format deleted file mode 100644 index ec635144..00000000 --- a/libdde_linux26/contrib/net/core/.svn/format +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/dev.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/dev.c.svn-base deleted file mode 100644 index e3fe5c70..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/dev.c.svn-base +++ /dev/null @@ -1,5277 +0,0 @@ -/* - * NET3 Protocol independent device support routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Derived from the non IP parts of dev.c 1.0.19 - * Authors: Ross Biro - * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> - * Mark Evans, <evansmp@uhura.aston.ac.uk> - * - * Additional Authors: - * Florian la Roche <rzsfl@rz.uni-sb.de> - * Alan Cox <gw4pts@gw4pts.ampr.org> - * David Hinds <dahinds@users.sourceforge.net> - * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> - * Adam Sulmicki <adam@cfar.umd.edu> - * Pekka Riikonen <priikone@poesidon.pspt.fi> - * - * Changes: - * D.J. Barrow : Fixed bug where dev->refcnt gets set - * to 2 if register_netdev gets called - * before net_dev_init & also removed a - * few lines of code in the process. - * Alan Cox : device private ioctl copies fields back. - * Alan Cox : Transmit queue code does relevant - * stunts to keep the queue safe. - * Alan Cox : Fixed double lock. - * Alan Cox : Fixed promisc NULL pointer trap - * ???????? : Support the full private ioctl range - * Alan Cox : Moved ioctl permission check into - * drivers - * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI - * Alan Cox : 100 backlog just doesn't cut it when - * you start doing multicast video 8) - * Alan Cox : Rewrote net_bh and list manager. - * Alan Cox : Fix ETH_P_ALL echoback lengths. - * Alan Cox : Took out transmit every packet pass - * Saved a few bytes in the ioctl handler - * Alan Cox : Network driver sets packet type before - * calling netif_rx. Saves a function - * call a packet. - * Alan Cox : Hashed net_bh() - * Richard Kooijman: Timestamp fixes. - * Alan Cox : Wrong field in SIOCGIFDSTADDR - * Alan Cox : Device lock protection. - * Alan Cox : Fixed nasty side effect of device close - * changes. - * Rudi Cilibrasi : Pass the right thing to - * set_mac_address() - * Dave Miller : 32bit quantity for the device lock to - * make it work out on a Sparc. - * Bjorn Ekwall : Added KERNELD hack. - * Alan Cox : Cleaned up the backlog initialise. - * Craig Metz : SIOCGIFCONF fix if space for under - * 1 device. - * Thomas Bogendoerfer : Return ENODEV for dev_open, if there - * is no device open function. - * Andi Kleen : Fix error reporting for SIOCGIFCONF - * Michael Chastain : Fix signed/unsigned for SIOCGIFCONF - * Cyrus Durgin : Cleaned for KMOD - * Adam Sulmicki : Bug Fix : Network Device Unload - * A network device unload needs to purge - * the backlog queue. - * Paul Rusty Russell : SIOCSIFNAME - * Pekka Riikonen : Netdev boot-time settings code - * Andrew Morton : Make unregister_netdevice wait - * indefinitely on dev->refcnt - * J Hadi Salim : - Backlog queue sampling - * - netif_rx() feedback - */ - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <linux/bitops.h> -#include <linux/capability.h> -#include <linux/cpu.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mutex.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/socket.h> -#include <linux/sockios.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/if_ether.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/notifier.h> -#include <linux/skbuff.h> -#include <net/net_namespace.h> -#include <net/sock.h> -#include <linux/rtnetlink.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/stat.h> -#include <linux/if_bridge.h> -#include <linux/if_macvlan.h> -#include <net/dst.h> -#include <net/pkt_sched.h> -#include <net/checksum.h> -#include <linux/highmem.h> -#include <linux/init.h> -#include <linux/kmod.h> -#include <linux/module.h> -#include <linux/netpoll.h> -#include <linux/rcupdate.h> -#include <linux/delay.h> -#include <net/wext.h> -#include <net/iw_handler.h> -#include <asm/current.h> -#include <linux/audit.h> -#include <linux/dmaengine.h> -#include <linux/err.h> -#include <linux/ctype.h> -#include <linux/if_arp.h> -#include <linux/if_vlan.h> -#include <linux/ip.h> -#include <net/ip.h> -#include <linux/ipv6.h> -#include <linux/in.h> -#include <linux/jhash.h> -#include <linux/random.h> - -#include "net-sysfs.h" - -/* Instead of increasing this, you should create a hash table. */ -#define MAX_GRO_SKBS 8 - -/* This should be increased if a protocol with a bigger head is added. */ -#define GRO_MAX_HEAD (MAX_HEADER + 128) - -/* - * The list of packet types we will receive (as opposed to discard) - * and the routines to invoke. - * - * Why 16. Because with 16 the only overlap we get on a hash of the - * low nibble of the protocol value is RARP/SNAP/X.25. - * - * NOTE: That is no longer true with the addition of VLAN tags. Not - * sure which should go first, but I bet it won't make much - * difference if we are running VLANs. The good news is that - * this protocol won't be in the list unless compiled in, so - * the average user (w/out VLANs) will not be adversely affected. - * --BLG - * - * 0800 IP - * 8100 802.1Q VLAN - * 0001 802.3 - * 0002 AX.25 - * 0004 802.2 - * 8035 RARP - * 0005 SNAP - * 0805 X.25 - * 0806 ARP - * 8137 IPX - * 0009 Localtalk - * 86DD IPv6 - */ - -#define PTYPE_HASH_SIZE (16) -#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1) - -static DEFINE_SPINLOCK(ptype_lock); -static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; -static struct list_head ptype_all __read_mostly; /* Taps */ - -/* - * The @dev_base_head list is protected by @dev_base_lock and the rtnl - * semaphore. - * - * Pure readers hold dev_base_lock for reading. - * - * Writers must hold the rtnl semaphore while they loop through the - * dev_base_head list, and hold dev_base_lock for writing when they do the - * actual updates. This allows pure readers to access the list even - * while a writer is preparing to update it. - * - * To put it another way, dev_base_lock is held for writing only to - * protect against pure readers; the rtnl semaphore provides the - * protection against other writers. - * - * See, for example usages, register_netdevice() and - * unregister_netdevice(), which must be called with the rtnl - * semaphore held. - */ -DEFINE_RWLOCK(dev_base_lock); - -EXPORT_SYMBOL(dev_base_lock); - -#define NETDEV_HASHBITS 8 -#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) - -static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) -{ - unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); - return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)]; -} - -static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) -{ - return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; -} - -/* Device list insertion */ -static int list_netdevice(struct net_device *dev) -{ - struct net *net = dev_net(dev); - - ASSERT_RTNL(); - - write_lock_bh(&dev_base_lock); - list_add_tail(&dev->dev_list, &net->dev_base_head); - hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); - hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); - write_unlock_bh(&dev_base_lock); - return 0; -} - -/* Device list removal */ -static void unlist_netdevice(struct net_device *dev) -{ - ASSERT_RTNL(); - - /* Unlink dev from the device chain */ - write_lock_bh(&dev_base_lock); - list_del(&dev->dev_list); - hlist_del(&dev->name_hlist); - hlist_del(&dev->index_hlist); - write_unlock_bh(&dev_base_lock); -} - -/* - * Our notifier list - */ - -static RAW_NOTIFIER_HEAD(netdev_chain); - -/* - * Device drivers call our routines to queue packets here. We empty the - * queue in the local softnet handler. - */ - -DEFINE_PER_CPU(struct softnet_data, softnet_data); - -#ifdef CONFIG_LOCKDEP -/* - * register_netdevice() inits txq->_xmit_lock and sets lockdep class - * according to dev->type - */ -static const unsigned short netdev_lock_type[] = - {ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25, - ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET, - ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM, - ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, - ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, - ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, - ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP, - ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, - ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, - ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, - ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, - ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, - ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, - ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, - ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE}; - -static const char *netdev_lock_name[] = - {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", - "_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET", - "_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM", - "_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP", - "_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD", - "_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25", - "_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP", - "_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", - "_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI", - "_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE", - "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", - "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", - "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", - "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", - "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"}; - -static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; -static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; - -static inline unsigned short netdev_lock_pos(unsigned short dev_type) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++) - if (netdev_lock_type[i] == dev_type) - return i; - /* the last key is used by default */ - return ARRAY_SIZE(netdev_lock_type) - 1; -} - -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, - unsigned short dev_type) -{ - int i; - - i = netdev_lock_pos(dev_type); - lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i], - netdev_lock_name[i]); -} - -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ - int i; - - i = netdev_lock_pos(dev->type); - lockdep_set_class_and_name(&dev->addr_list_lock, - &netdev_addr_lock_key[i], - netdev_lock_name[i]); -} -#else -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, - unsigned short dev_type) -{ -} -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ -} -#endif - -/******************************************************************************* - - Protocol management and registration routines - -*******************************************************************************/ - -/* - * Add a protocol ID to the list. Now that the input handler is - * smarter we can dispense with all the messy stuff that used to be - * here. - * - * BEWARE!!! Protocol handlers, mangling input packets, - * MUST BE last in hash buckets and checking protocol handlers - * MUST start from promiscuous ptype_all chain in net_bh. - * It is true now, do not change it. - * Explanation follows: if protocol handler, mangling packet, will - * be the first on list, it is not able to sense, that packet - * is cloned and should be copied-on-write, so that it will - * change it and subsequent readers will get broken packet. - * --ANK (980803) - */ - -/** - * dev_add_pack - add packet handler - * @pt: packet type declaration - * - * Add a protocol handler to the networking stack. The passed &packet_type - * is linked into kernel lists and may not be freed until it has been - * removed from the kernel lists. - * - * This call does not sleep therefore it can not - * guarantee all CPU's that are in middle of receiving packets - * will see the new packet type (until the next received packet). - */ - -void dev_add_pack(struct packet_type *pt) -{ - int hash; - - spin_lock_bh(&ptype_lock); - if (pt->type == htons(ETH_P_ALL)) - list_add_rcu(&pt->list, &ptype_all); - else { - hash = ntohs(pt->type) & PTYPE_HASH_MASK; - list_add_rcu(&pt->list, &ptype_base[hash]); - } - spin_unlock_bh(&ptype_lock); -} - -/** - * __dev_remove_pack - remove packet handler - * @pt: packet type declaration - * - * Remove a protocol handler that was previously added to the kernel - * protocol handlers by dev_add_pack(). The passed &packet_type is removed - * from the kernel lists and can be freed or reused once this function - * returns. - * - * The packet type might still be in use by receivers - * and must not be freed until after all the CPU's have gone - * through a quiescent state. - */ -void __dev_remove_pack(struct packet_type *pt) -{ - struct list_head *head; - struct packet_type *pt1; - - spin_lock_bh(&ptype_lock); - - if (pt->type == htons(ETH_P_ALL)) - head = &ptype_all; - else - head = &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK]; - - list_for_each_entry(pt1, head, list) { - if (pt == pt1) { - list_del_rcu(&pt->list); - goto out; - } - } - - printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt); -out: - spin_unlock_bh(&ptype_lock); -} -/** - * dev_remove_pack - remove packet handler - * @pt: packet type declaration - * - * Remove a protocol handler that was previously added to the kernel - * protocol handlers by dev_add_pack(). The passed &packet_type is removed - * from the kernel lists and can be freed or reused once this function - * returns. - * - * This call sleeps to guarantee that no CPU is looking at the packet - * type after return. - */ -void dev_remove_pack(struct packet_type *pt) -{ - __dev_remove_pack(pt); - - synchronize_net(); -} - -/****************************************************************************** - - Device Boot-time Settings Routines - -*******************************************************************************/ - -/* Boot time configuration table */ -static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; - -/** - * netdev_boot_setup_add - add new setup entry - * @name: name of the device - * @map: configured settings for the device - * - * Adds new setup entry to the dev_boot_setup list. The function - * returns 0 on error and 1 on success. This is a generic routine to - * all netdevices. - */ -static int netdev_boot_setup_add(char *name, struct ifmap *map) -{ - struct netdev_boot_setup *s; - int i; - - s = dev_boot_setup; - for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { - if (s[i].name[0] == '\0' || s[i].name[0] == ' ') { - memset(s[i].name, 0, sizeof(s[i].name)); - strlcpy(s[i].name, name, IFNAMSIZ); - memcpy(&s[i].map, map, sizeof(s[i].map)); - break; - } - } - - return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1; -} - -/** - * netdev_boot_setup_check - check boot time settings - * @dev: the netdevice - * - * Check boot time settings for the device. - * The found settings are set for the device to be used - * later in the device probing. - * Returns 0 if no settings found, 1 if they are. - */ -int netdev_boot_setup_check(struct net_device *dev) -{ - struct netdev_boot_setup *s = dev_boot_setup; - int i; - - for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { - if (s[i].name[0] != '\0' && s[i].name[0] != ' ' && - !strcmp(dev->name, s[i].name)) { - dev->irq = s[i].map.irq; - dev->base_addr = s[i].map.base_addr; - dev->mem_start = s[i].map.mem_start; - dev->mem_end = s[i].map.mem_end; - return 1; - } - } - return 0; -} - - -/** - * netdev_boot_base - get address from boot time settings - * @prefix: prefix for network device - * @unit: id for network device - * - * Check boot time settings for the base address of device. - * The found settings are set for the device to be used - * later in the device probing. - * Returns 0 if no settings found. - */ -unsigned long netdev_boot_base(const char *prefix, int unit) -{ - const struct netdev_boot_setup *s = dev_boot_setup; - char name[IFNAMSIZ]; - int i; - - sprintf(name, "%s%d", prefix, unit); - - /* - * If device already registered then return base of 1 - * to indicate not to probe for this interface - */ - if (__dev_get_by_name(&init_net, name)) - return 1; - - for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) - if (!strcmp(name, s[i].name)) - return s[i].map.base_addr; - return 0; -} - -/* - * Saves at boot time configured settings for any netdevice. - */ -int __init netdev_boot_setup(char *str) -{ - int ints[5]; - struct ifmap map; - - str = get_options(str, ARRAY_SIZE(ints), ints); - if (!str || !*str) - return 0; - - /* Save settings */ - memset(&map, 0, sizeof(map)); - if (ints[0] > 0) - map.irq = ints[1]; - if (ints[0] > 1) - map.base_addr = ints[2]; - if (ints[0] > 2) - map.mem_start = ints[3]; - if (ints[0] > 3) - map.mem_end = ints[4]; - - /* Add new entry to the list */ - return netdev_boot_setup_add(str, &map); -} - -__setup("netdev=", netdev_boot_setup); - -/******************************************************************************* - - Device Interface Subroutines - -*******************************************************************************/ - -/** - * __dev_get_by_name - find a device by its name - * @net: the applicable net namespace - * @name: name to find - * - * Find an interface by name. Must be called under RTNL semaphore - * or @dev_base_lock. If the name is found a pointer to the device - * is returned. If the name is not found then %NULL is returned. The - * reference counters are not incremented so the caller must be - * careful with locks. - */ - -struct net_device *__dev_get_by_name(struct net *net, const char *name) -{ - struct hlist_node *p; - - hlist_for_each(p, dev_name_hash(net, name)) { - struct net_device *dev - = hlist_entry(p, struct net_device, name_hlist); - if (!strncmp(dev->name, name, IFNAMSIZ)) - return dev; - } - return NULL; -} - -/** - * dev_get_by_name - find a device by its name - * @net: the applicable net namespace - * @name: name to find - * - * Find an interface by name. This can be called from any - * context and does its own locking. The returned handle has - * the usage count incremented and the caller must use dev_put() to - * release it when it is no longer needed. %NULL is returned if no - * matching device is found. - */ - -struct net_device *dev_get_by_name(struct net *net, const char *name) -{ - struct net_device *dev; - - read_lock(&dev_base_lock); - dev = __dev_get_by_name(net, name); - if (dev) - dev_hold(dev); - read_unlock(&dev_base_lock); - return dev; -} - -/** - * __dev_get_by_index - find a device by its ifindex - * @net: the applicable net namespace - * @ifindex: index of device - * - * Search for an interface by index. Returns %NULL if the device - * is not found or a pointer to the device. The device has not - * had its reference counter increased so the caller must be careful - * about locking. The caller must hold either the RTNL semaphore - * or @dev_base_lock. - */ - -struct net_device *__dev_get_by_index(struct net *net, int ifindex) -{ - struct hlist_node *p; - - hlist_for_each(p, dev_index_hash(net, ifindex)) { - struct net_device *dev - = hlist_entry(p, struct net_device, index_hlist); - if (dev->ifindex == ifindex) - return dev; - } - return NULL; -} - - -/** - * dev_get_by_index - find a device by its ifindex - * @net: the applicable net namespace - * @ifindex: index of device - * - * Search for an interface by index. Returns NULL if the device - * is not found or a pointer to the device. The device returned has - * had a reference added and the pointer is safe until the user calls - * dev_put to indicate they have finished with it. - */ - -struct net_device *dev_get_by_index(struct net *net, int ifindex) -{ - struct net_device *dev; - - read_lock(&dev_base_lock); - dev = __dev_get_by_index(net, ifindex); - if (dev) - dev_hold(dev); - read_unlock(&dev_base_lock); - return dev; -} - -/** - * dev_getbyhwaddr - find a device by its hardware address - * @net: the applicable net namespace - * @type: media type of device - * @ha: hardware address - * - * Search for an interface by MAC address. Returns NULL if the device - * is not found or a pointer to the device. The caller must hold the - * rtnl semaphore. The returned device has not had its ref count increased - * and the caller must therefore be careful about locking - * - * BUGS: - * If the API was consistent this would be __dev_get_by_hwaddr - */ - -struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha) -{ - struct net_device *dev; - - ASSERT_RTNL(); - - for_each_netdev(net, dev) - if (dev->type == type && - !memcmp(dev->dev_addr, ha, dev->addr_len)) - return dev; - - return NULL; -} - -EXPORT_SYMBOL(dev_getbyhwaddr); - -struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) -{ - struct net_device *dev; - - ASSERT_RTNL(); - for_each_netdev(net, dev) - if (dev->type == type) - return dev; - - return NULL; -} - -EXPORT_SYMBOL(__dev_getfirstbyhwtype); - -struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) -{ - struct net_device *dev; - - rtnl_lock(); - dev = __dev_getfirstbyhwtype(net, type); - if (dev) - dev_hold(dev); - rtnl_unlock(); - return dev; -} - -EXPORT_SYMBOL(dev_getfirstbyhwtype); - -/** - * dev_get_by_flags - find any device with given flags - * @net: the applicable net namespace - * @if_flags: IFF_* values - * @mask: bitmask of bits in if_flags to check - * - * Search for any interface with the given flags. Returns NULL if a device - * is not found or a pointer to the device. The device returned has - * had a reference added and the pointer is safe until the user calls - * dev_put to indicate they have finished with it. - */ - -struct net_device * dev_get_by_flags(struct net *net, unsigned short if_flags, unsigned short mask) -{ - struct net_device *dev, *ret; - - ret = NULL; - read_lock(&dev_base_lock); - for_each_netdev(net, dev) { - if (((dev->flags ^ if_flags) & mask) == 0) { - dev_hold(dev); - ret = dev; - break; - } - } - read_unlock(&dev_base_lock); - return ret; -} - -/** - * dev_valid_name - check if name is okay for network device - * @name: name string - * - * Network device names need to be valid file names to - * to allow sysfs to work. We also disallow any kind of - * whitespace. - */ -int dev_valid_name(const char *name) -{ - if (*name == '\0') - return 0; - if (strlen(name) >= IFNAMSIZ) - return 0; - if (!strcmp(name, ".") || !strcmp(name, "..")) - return 0; - - while (*name) { - if (*name == '/' || isspace(*name)) - return 0; - name++; - } - return 1; -} - -/** - * __dev_alloc_name - allocate a name for a device - * @net: network namespace to allocate the device name in - * @name: name format string - * @buf: scratch buffer and result name string - * - * Passed a format string - eg "lt%d" it will try and find a suitable - * id. It scans list of devices to build up a free map, then chooses - * the first empty slot. The caller must hold the dev_base or rtnl lock - * while allocating the name and adding the device in order to avoid - * duplicates. - * Limited to bits_per_byte * page size devices (ie 32K on most platforms). - * Returns the number of the unit assigned or a negative errno code. - */ - -static int __dev_alloc_name(struct net *net, const char *name, char *buf) -{ - int i = 0; - const char *p; - const int max_netdevices = 8*PAGE_SIZE; - unsigned long *inuse; - struct net_device *d; - - p = strnchr(name, IFNAMSIZ-1, '%'); - if (p) { - /* - * Verify the string as this thing may have come from - * the user. There must be either one "%d" and no other "%" - * characters. - */ - if (p[1] != 'd' || strchr(p + 2, '%')) - return -EINVAL; - - /* Use one page as a bit array of possible slots */ - inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC); - if (!inuse) - return -ENOMEM; - - for_each_netdev(net, d) { - if (!sscanf(d->name, name, &i)) - continue; - if (i < 0 || i >= max_netdevices) - continue; - - /* avoid cases where sscanf is not exact inverse of printf */ - snprintf(buf, IFNAMSIZ, name, i); - if (!strncmp(buf, d->name, IFNAMSIZ)) - set_bit(i, inuse); - } - - i = find_first_zero_bit(inuse, max_netdevices); - free_page((unsigned long) inuse); - } - - snprintf(buf, IFNAMSIZ, name, i); - if (!__dev_get_by_name(net, buf)) - return i; - - /* It is possible to run out of possible slots - * when the name is long and there isn't enough space left - * for the digits, or if all bits are used. - */ - return -ENFILE; -} - -/** - * dev_alloc_name - allocate a name for a device - * @dev: device - * @name: name format string - * - * Passed a format string - eg "lt%d" it will try and find a suitable - * id. It scans list of devices to build up a free map, then chooses - * the first empty slot. The caller must hold the dev_base or rtnl lock - * while allocating the name and adding the device in order to avoid - * duplicates. - * Limited to bits_per_byte * page size devices (ie 32K on most platforms). - * Returns the number of the unit assigned or a negative errno code. - */ - -int dev_alloc_name(struct net_device *dev, const char *name) -{ - char buf[IFNAMSIZ]; - struct net *net; - int ret; - - BUG_ON(!dev_net(dev)); - net = dev_net(dev); - ret = __dev_alloc_name(net, name, buf); - if (ret >= 0) - strlcpy(dev->name, buf, IFNAMSIZ); - return ret; -} - - -/** - * dev_change_name - change name of a device - * @dev: device - * @newname: name (or format string) must be at least IFNAMSIZ - * - * Change name of a device, can pass format strings "eth%d". - * for wildcarding. - */ -int dev_change_name(struct net_device *dev, const char *newname) -{ - char oldname[IFNAMSIZ]; - int err = 0; - int ret; - struct net *net; - - ASSERT_RTNL(); - BUG_ON(!dev_net(dev)); - - net = dev_net(dev); - if (dev->flags & IFF_UP) - return -EBUSY; - - if (!dev_valid_name(newname)) - return -EINVAL; - - if (strncmp(newname, dev->name, IFNAMSIZ) == 0) - return 0; - - memcpy(oldname, dev->name, IFNAMSIZ); - - if (strchr(newname, '%')) { - err = dev_alloc_name(dev, newname); - if (err < 0) - return err; - } - else if (__dev_get_by_name(net, newname)) - return -EEXIST; - else - strlcpy(dev->name, newname, IFNAMSIZ); - -rollback: - /* For now only devices in the initial network namespace - * are in sysfs. - */ - if (net == &init_net) { - ret = device_rename(&dev->dev, dev->name); - if (ret) { - memcpy(dev->name, oldname, IFNAMSIZ); - return ret; - } - } - - write_lock_bh(&dev_base_lock); - hlist_del(&dev->name_hlist); - hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); - write_unlock_bh(&dev_base_lock); - - ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); - ret = notifier_to_errno(ret); - - if (ret) { - if (err) { - printk(KERN_ERR - "%s: name change rollback failed: %d.\n", - dev->name, ret); - } else { - err = ret; - memcpy(dev->name, oldname, IFNAMSIZ); - goto rollback; - } - } - - return err; -} - -/** - * dev_set_alias - change ifalias of a device - * @dev: device - * @alias: name up to IFALIASZ - * @len: limit of bytes to copy from info - * - * Set ifalias for a device, - */ -int dev_set_alias(struct net_device *dev, const char *alias, size_t len) -{ - ASSERT_RTNL(); - - if (len >= IFALIASZ) - return -EINVAL; - - if (!len) { - if (dev->ifalias) { - kfree(dev->ifalias); - dev->ifalias = NULL; - } - return 0; - } - - dev->ifalias = krealloc(dev->ifalias, len+1, GFP_KERNEL); - if (!dev->ifalias) - return -ENOMEM; - - strlcpy(dev->ifalias, alias, len+1); - return len; -} - - -/** - * netdev_features_change - device changes features - * @dev: device to cause notification - * - * Called to indicate a device has changed features. - */ -void netdev_features_change(struct net_device *dev) -{ - call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev); -} -EXPORT_SYMBOL(netdev_features_change); - -/** - * netdev_state_change - device changes state - * @dev: device to cause notification - * - * Called to indicate a device has changed state. This function calls - * the notifier chains for netdev_chain and sends a NEWLINK message - * to the routing socket. - */ -void netdev_state_change(struct net_device *dev) -{ - if (dev->flags & IFF_UP) { - call_netdevice_notifiers(NETDEV_CHANGE, dev); - rtmsg_ifinfo(RTM_NEWLINK, dev, 0); - } -} - -void netdev_bonding_change(struct net_device *dev) -{ - call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev); -} -EXPORT_SYMBOL(netdev_bonding_change); - -/** - * dev_load - load a network module - * @net: the applicable net namespace - * @name: name of interface - * - * If a network interface is not present and the process has suitable - * privileges this function loads the module. If module loading is not - * available in this kernel then it becomes a nop. - */ - -void dev_load(struct net *net, const char *name) -{ - struct net_device *dev; - - read_lock(&dev_base_lock); - dev = __dev_get_by_name(net, name); - read_unlock(&dev_base_lock); - - if (!dev && capable(CAP_SYS_MODULE)) - request_module("%s", name); -} - -/** - * dev_open - prepare an interface for use. - * @dev: device to open - * - * Takes a device from down to up state. The device's private open - * function is invoked and then the multicast lists are loaded. Finally - * the device is moved into the up state and a %NETDEV_UP message is - * sent to the netdev notifier chain. - * - * Calling this function on an active interface is a nop. On a failure - * a negative errno code is returned. - */ -int dev_open(struct net_device *dev) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int ret = 0; - - ASSERT_RTNL(); - - /* - * Is it already up? - */ - - if (dev->flags & IFF_UP) - return 0; - - /* - * Is it even present? - */ - if (!netif_device_present(dev)) - return -ENODEV; - - /* - * Call device private open method - */ - set_bit(__LINK_STATE_START, &dev->state); - - if (ops->ndo_validate_addr) - ret = ops->ndo_validate_addr(dev); - - if (!ret && ops->ndo_open) - ret = ops->ndo_open(dev); - - /* - * If it went open OK then: - */ - - if (ret) - clear_bit(__LINK_STATE_START, &dev->state); - else { - /* - * Set the flags. - */ - dev->flags |= IFF_UP; - - /* - * Enable NET_DMA - */ - net_dmaengine_get(); - - /* - * Initialize multicasting status - */ - dev_set_rx_mode(dev); - - /* - * Wakeup transmit queue engine - */ - dev_activate(dev); - - /* - * ... and announce new interface. - */ - call_netdevice_notifiers(NETDEV_UP, dev); - } - - return ret; -} - -/** - * dev_close - shutdown an interface. - * @dev: device to shutdown - * - * This function moves an active device into down state. A - * %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device - * is then deactivated and finally a %NETDEV_DOWN is sent to the notifier - * chain. - */ -int dev_close(struct net_device *dev) -{ - const struct net_device_ops *ops = dev->netdev_ops; - ASSERT_RTNL(); - - might_sleep(); - - if (!(dev->flags & IFF_UP)) - return 0; - - /* - * Tell people we are going down, so that they can - * prepare to death, when device is still operating. - */ - call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); - - clear_bit(__LINK_STATE_START, &dev->state); - - /* Synchronize to scheduled poll. We cannot touch poll list, - * it can be even on different cpu. So just clear netif_running(). - * - * dev->stop() will invoke napi_disable() on all of it's - * napi_struct instances on this device. - */ - smp_mb__after_clear_bit(); /* Commit netif_running(). */ - - dev_deactivate(dev); - - /* - * Call the device specific close. This cannot fail. - * Only if device is UP - * - * We allow it to be called even after a DETACH hot-plug - * event. - */ - if (ops->ndo_stop) - ops->ndo_stop(dev); - - /* - * Device is now down. - */ - - dev->flags &= ~IFF_UP; - - /* - * Tell people we are down - */ - call_netdevice_notifiers(NETDEV_DOWN, dev); - - /* - * Shutdown NET_DMA - */ - net_dmaengine_put(); - - return 0; -} - - -/** - * dev_disable_lro - disable Large Receive Offload on a device - * @dev: device - * - * Disable Large Receive Offload (LRO) on a net device. Must be - * called under RTNL. This is needed if received packets may be - * forwarded to another interface. - */ -void dev_disable_lro(struct net_device *dev) -{ - if (dev->ethtool_ops && dev->ethtool_ops->get_flags && - dev->ethtool_ops->set_flags) { - u32 flags = dev->ethtool_ops->get_flags(dev); - if (flags & ETH_FLAG_LRO) { - flags &= ~ETH_FLAG_LRO; - dev->ethtool_ops->set_flags(dev, flags); - } - } - WARN_ON(dev->features & NETIF_F_LRO); -} -EXPORT_SYMBOL(dev_disable_lro); - - -static int dev_boot_phase = 1; - -/* - * Device change register/unregister. These are not inline or static - * as we export them to the world. - */ - -/** - * register_netdevice_notifier - register a network notifier block - * @nb: notifier - * - * Register a notifier to be called when network device events occur. - * The notifier passed is linked into the kernel structures and must - * not be reused until it has been unregistered. A negative errno code - * is returned on a failure. - * - * When registered all registration and up events are replayed - * to the new notifier to allow device to have a race free - * view of the network device list. - */ - -int register_netdevice_notifier(struct notifier_block *nb) -{ - struct net_device *dev; - struct net_device *last; - struct net *net; - int err; - - rtnl_lock(); - err = raw_notifier_chain_register(&netdev_chain, nb); - if (err) - goto unlock; - if (dev_boot_phase) - goto unlock; - for_each_net(net) { - for_each_netdev(net, dev) { - err = nb->notifier_call(nb, NETDEV_REGISTER, dev); - err = notifier_to_errno(err); - if (err) - goto rollback; - - if (!(dev->flags & IFF_UP)) - continue; - - nb->notifier_call(nb, NETDEV_UP, dev); - } - } - -unlock: - rtnl_unlock(); - return err; - -rollback: - last = dev; - for_each_net(net) { - for_each_netdev(net, dev) { - if (dev == last) - break; - - if (dev->flags & IFF_UP) { - nb->notifier_call(nb, NETDEV_GOING_DOWN, dev); - nb->notifier_call(nb, NETDEV_DOWN, dev); - } - nb->notifier_call(nb, NETDEV_UNREGISTER, dev); - } - } - - raw_notifier_chain_unregister(&netdev_chain, nb); - goto unlock; -} - -/** - * unregister_netdevice_notifier - unregister a network notifier block - * @nb: notifier - * - * Unregister a notifier previously registered by - * register_netdevice_notifier(). The notifier is unlinked into the - * kernel structures and may then be reused. A negative errno code - * is returned on a failure. - */ - -int unregister_netdevice_notifier(struct notifier_block *nb) -{ - int err; - - rtnl_lock(); - err = raw_notifier_chain_unregister(&netdev_chain, nb); - rtnl_unlock(); - return err; -} - -/** - * call_netdevice_notifiers - call all network notifier blocks - * @val: value passed unmodified to notifier function - * @dev: net_device pointer passed unmodified to notifier function - * - * Call all network notifier blocks. Parameters and return value - * are as for raw_notifier_call_chain(). - */ - -int call_netdevice_notifiers(unsigned long val, struct net_device *dev) -{ - return raw_notifier_call_chain(&netdev_chain, val, dev); -} - -/* When > 0 there are consumers of rx skb time stamps */ -static atomic_t netstamp_needed = ATOMIC_INIT(0); - -void net_enable_timestamp(void) -{ - atomic_inc(&netstamp_needed); -} - -void net_disable_timestamp(void) -{ - atomic_dec(&netstamp_needed); -} - -static inline void net_timestamp(struct sk_buff *skb) -{ - if (atomic_read(&netstamp_needed)) - __net_timestamp(skb); - else - skb->tstamp.tv64 = 0; -} - -/* - * Support routine. Sends outgoing frames to any network - * taps currently in use. - */ - -static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) -{ - struct packet_type *ptype; - - net_timestamp(skb); - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, &ptype_all, list) { - /* Never send packets back to the socket - * they originated from - MvS (miquels@drinkel.ow.org) - */ - if ((ptype->dev == dev || !ptype->dev) && - (ptype->af_packet_priv == NULL || - (struct sock *)ptype->af_packet_priv != skb->sk)) { - struct sk_buff *skb2= skb_clone(skb, GFP_ATOMIC); - if (!skb2) - break; - - /* skb->nh should be correctly - set by sender, so that the second statement is - just protection against buggy protocols. - */ - skb_reset_mac_header(skb2); - - if (skb_network_header(skb2) < skb2->data || - skb2->network_header > skb2->tail) { - if (net_ratelimit()) - printk(KERN_CRIT "protocol %04x is " - "buggy, dev %s\n", - skb2->protocol, dev->name); - skb_reset_network_header(skb2); - } - - skb2->transport_header = skb2->network_header; - skb2->pkt_type = PACKET_OUTGOING; - ptype->func(skb2, skb->dev, ptype, skb->dev); - } - } - rcu_read_unlock(); -} - - -static inline void __netif_reschedule(struct Qdisc *q) -{ - struct softnet_data *sd; - unsigned long flags; - - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - q->next_sched = sd->output_queue; - sd->output_queue = q; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); -} - -void __netif_schedule(struct Qdisc *q) -{ - if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) - __netif_reschedule(q); -} -EXPORT_SYMBOL(__netif_schedule); - -void dev_kfree_skb_irq(struct sk_buff *skb) -{ - if (atomic_dec_and_test(&skb->users)) { - struct softnet_data *sd; - unsigned long flags; - - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - skb->next = sd->completion_queue; - sd->completion_queue = skb; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); - } -} -EXPORT_SYMBOL(dev_kfree_skb_irq); - -void dev_kfree_skb_any(struct sk_buff *skb) -{ - if (in_irq() || irqs_disabled()) - dev_kfree_skb_irq(skb); - else - dev_kfree_skb(skb); -} -EXPORT_SYMBOL(dev_kfree_skb_any); - - -/** - * netif_device_detach - mark device as removed - * @dev: network device - * - * Mark device as removed from system and therefore no longer available. - */ -void netif_device_detach(struct net_device *dev) -{ - if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && - netif_running(dev)) { - netif_stop_queue(dev); - } -} -EXPORT_SYMBOL(netif_device_detach); - -/** - * netif_device_attach - mark device as attached - * @dev: network device - * - * Mark device as attached from system and restart if needed. - */ -void netif_device_attach(struct net_device *dev) -{ - if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && - netif_running(dev)) { - netif_wake_queue(dev); - __netdev_watchdog_up(dev); - } -} -EXPORT_SYMBOL(netif_device_attach); - -static bool can_checksum_protocol(unsigned long features, __be16 protocol) -{ - return ((features & NETIF_F_GEN_CSUM) || - ((features & NETIF_F_IP_CSUM) && - protocol == htons(ETH_P_IP)) || - ((features & NETIF_F_IPV6_CSUM) && - protocol == htons(ETH_P_IPV6))); -} - -static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb) -{ - if (can_checksum_protocol(dev->features, skb->protocol)) - return true; - - if (skb->protocol == htons(ETH_P_8021Q)) { - struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; - if (can_checksum_protocol(dev->features & dev->vlan_features, - veh->h_vlan_encapsulated_proto)) - return true; - } - - return false; -} - -/* - * Invalidate hardware checksum when packet is to be mangled, and - * complete checksum manually on outgoing path. - */ -int skb_checksum_help(struct sk_buff *skb) -{ - __wsum csum; - int ret = 0, offset; - - if (skb->ip_summed == CHECKSUM_COMPLETE) - goto out_set_summed; - - if (unlikely(skb_shinfo(skb)->gso_size)) { - /* Let GSO fix up the checksum. */ - goto out_set_summed; - } - - offset = skb->csum_start - skb_headroom(skb); - BUG_ON(offset >= skb_headlen(skb)); - csum = skb_checksum(skb, offset, skb->len - offset, 0); - - offset += skb->csum_offset; - BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb)); - - if (skb_cloned(skb) && - !skb_clone_writable(skb, offset + sizeof(__sum16))) { - ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - if (ret) - goto out; - } - - *(__sum16 *)(skb->data + offset) = csum_fold(csum); -out_set_summed: - skb->ip_summed = CHECKSUM_NONE; -out: - return ret; -} - -/** - * skb_gso_segment - Perform segmentation on skb. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - * - * This function segments the given skb and returns a list of segments. - * - * It may return NULL if the skb requires no segmentation. This is - * only possible when GSO is used for verifying header integrity. - */ -struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) -{ - struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); - struct packet_type *ptype; - __be16 type = skb->protocol; - int err; - - skb_reset_mac_header(skb); - skb->mac_len = skb->network_header - skb->mac_header; - __skb_pull(skb, skb->mac_len); - - if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { - struct net_device *dev = skb->dev; - struct ethtool_drvinfo info = {}; - - if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) - dev->ethtool_ops->get_drvinfo(dev, &info); - - WARN(1, "%s: caps=(0x%lx, 0x%lx) len=%d data_len=%d " - "ip_summed=%d", - info.driver, dev ? dev->features : 0L, - skb->sk ? skb->sk->sk_route_caps : 0L, - skb->len, skb->data_len, skb->ip_summed); - - if (skb_header_cloned(skb) && - (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) - return ERR_PTR(err); - } - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, - &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { - if (ptype->type == type && !ptype->dev && ptype->gso_segment) { - if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { - err = ptype->gso_send_check(skb); - segs = ERR_PTR(err); - if (err || skb_gso_ok(skb, features)) - break; - __skb_push(skb, (skb->data - - skb_network_header(skb))); - } - segs = ptype->gso_segment(skb, features); - break; - } - } - rcu_read_unlock(); - - __skb_push(skb, skb->data - skb_mac_header(skb)); - - return segs; -} - -EXPORT_SYMBOL(skb_gso_segment); - -/* Take action when hardware reception checksum errors are detected. */ -#ifdef CONFIG_BUG -void netdev_rx_csum_fault(struct net_device *dev) -{ - if (net_ratelimit()) { - printk(KERN_ERR "%s: hw csum failure.\n", - dev ? dev->name : "<unknown>"); - dump_stack(); - } -} -EXPORT_SYMBOL(netdev_rx_csum_fault); -#endif - -/* Actually, we should eliminate this check as soon as we know, that: - * 1. IOMMU is present and allows to map all the memory. - * 2. No high memory really exists on this machine. - */ - -static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) -{ -#ifdef CONFIG_HIGHMEM - int i; - - if (dev->features & NETIF_F_HIGHDMA) - return 0; - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - if (PageHighMem(skb_shinfo(skb)->frags[i].page)) - return 1; - -#endif - return 0; -} - -struct dev_gso_cb { - void (*destructor)(struct sk_buff *skb); -}; - -#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb) - -static void dev_gso_skb_destructor(struct sk_buff *skb) -{ - struct dev_gso_cb *cb; - - do { - struct sk_buff *nskb = skb->next; - - skb->next = nskb->next; - nskb->next = NULL; - kfree_skb(nskb); - } while (skb->next); - - cb = DEV_GSO_CB(skb); - if (cb->destructor) - cb->destructor(skb); -} - -/** - * dev_gso_segment - Perform emulated hardware segmentation on skb. - * @skb: buffer to segment - * - * This function segments the given skb and stores the list of segments - * in skb->next. - */ -static int dev_gso_segment(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct sk_buff *segs; - int features = dev->features & ~(illegal_highdma(dev, skb) ? - NETIF_F_SG : 0); - - segs = skb_gso_segment(skb, features); - - /* Verifying header integrity only. */ - if (!segs) - return 0; - - if (IS_ERR(segs)) - return PTR_ERR(segs); - - skb->next = segs; - DEV_GSO_CB(skb)->destructor = skb->destructor; - skb->destructor = dev_gso_skb_destructor; - - return 0; -} - -int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, - struct netdev_queue *txq) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - prefetch(&dev->netdev_ops->ndo_start_xmit); - if (likely(!skb->next)) { - if (!list_empty(&ptype_all)) - dev_queue_xmit_nit(skb, dev); - - if (netif_needs_gso(dev, skb)) { - if (unlikely(dev_gso_segment(skb))) - goto out_kfree_skb; - if (skb->next) - goto gso; - } - - return ops->ndo_start_xmit(skb, dev); - } - -gso: - do { - struct sk_buff *nskb = skb->next; - int rc; - - skb->next = nskb->next; - nskb->next = NULL; - rc = ops->ndo_start_xmit(nskb, dev); - if (unlikely(rc)) { - nskb->next = skb->next; - skb->next = nskb; - return rc; - } - if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) - return NETDEV_TX_BUSY; - } while (skb->next); - - skb->destructor = DEV_GSO_CB(skb)->destructor; - -out_kfree_skb: - kfree_skb(skb); - return 0; -} - -static u32 simple_tx_hashrnd; -static int simple_tx_hashrnd_initialized = 0; - -static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb) -{ - u32 addr1, addr2, ports; - u32 hash, ihl; - u8 ip_proto = 0; - - if (unlikely(!simple_tx_hashrnd_initialized)) { - get_random_bytes(&simple_tx_hashrnd, 4); - simple_tx_hashrnd_initialized = 1; - } - - switch (skb->protocol) { - case htons(ETH_P_IP): - if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))) - ip_proto = ip_hdr(skb)->protocol; - addr1 = ip_hdr(skb)->saddr; - addr2 = ip_hdr(skb)->daddr; - ihl = ip_hdr(skb)->ihl; - break; - case htons(ETH_P_IPV6): - ip_proto = ipv6_hdr(skb)->nexthdr; - addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3]; - addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3]; - ihl = (40 >> 2); - break; - default: - return 0; - } - - - switch (ip_proto) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_DCCP: - case IPPROTO_ESP: - case IPPROTO_AH: - case IPPROTO_SCTP: - case IPPROTO_UDPLITE: - ports = *((u32 *) (skb_network_header(skb) + (ihl * 4))); - break; - - default: - ports = 0; - break; - } - - hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd); - - return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32); -} - -static struct netdev_queue *dev_pick_tx(struct net_device *dev, - struct sk_buff *skb) -{ - const struct net_device_ops *ops = dev->netdev_ops; - u16 queue_index = 0; - - if (ops->ndo_select_queue) - queue_index = ops->ndo_select_queue(dev, skb); - else if (dev->real_num_tx_queues > 1) - queue_index = simple_tx_hash(dev, skb); - - skb_set_queue_mapping(skb, queue_index); - return netdev_get_tx_queue(dev, queue_index); -} - -/** - * dev_queue_xmit - transmit a buffer - * @skb: buffer to transmit - * - * Queue a buffer for transmission to a network device. The caller must - * have set the device and priority and built the buffer before calling - * this function. The function can be called from an interrupt. - * - * A negative errno code is returned on a failure. A success does not - * guarantee the frame will be transmitted as it may be dropped due - * to congestion or traffic shaping. - * - * ----------------------------------------------------------------------------------- - * I notice this method can also return errors from the queue disciplines, - * including NET_XMIT_DROP, which is a positive value. So, errors can also - * be positive. - * - * Regardless of the return value, the skb is consumed, so it is currently - * difficult to retry a send to this method. (You can bump the ref count - * before sending to hold a reference for retry if you are careful.) - * - * When calling this method, interrupts MUST be enabled. This is because - * the BH enable code must have IRQs enabled so that it will not deadlock. - * --BLG - */ -int dev_queue_xmit(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct netdev_queue *txq; - struct Qdisc *q; - int rc = -ENOMEM; - - /* GSO will handle the following emulations directly. */ - if (netif_needs_gso(dev, skb)) - goto gso; - - if (skb_shinfo(skb)->frag_list && - !(dev->features & NETIF_F_FRAGLIST) && - __skb_linearize(skb)) - goto out_kfree_skb; - - /* Fragmented skb is linearized if device does not support SG, - * or if at least one of fragments is in highmem and device - * does not support DMA from it. - */ - if (skb_shinfo(skb)->nr_frags && - (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && - __skb_linearize(skb)) - goto out_kfree_skb; - - /* If packet is not checksummed and device does not support - * checksumming for this protocol, complete checksumming here. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - skb_set_transport_header(skb, skb->csum_start - - skb_headroom(skb)); - if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb)) - goto out_kfree_skb; - } - -gso: - /* Disable soft irqs for various locks below. Also - * stops preemption for RCU. - */ - rcu_read_lock_bh(); - - txq = dev_pick_tx(dev, skb); - q = rcu_dereference(txq->qdisc); - -#ifdef CONFIG_NET_CLS_ACT - skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); -#endif - if (q->enqueue) { - spinlock_t *root_lock = qdisc_lock(q); - - spin_lock(root_lock); - - if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { - kfree_skb(skb); - rc = NET_XMIT_DROP; - } else { - rc = qdisc_enqueue_root(skb, q); - qdisc_run(q); - } - spin_unlock(root_lock); - - goto out; - } - - /* The device has no queue. Common case for software devices: - loopback, all the sorts of tunnels... - - Really, it is unlikely that netif_tx_lock protection is necessary - here. (f.e. loopback and IP tunnels are clean ignoring statistics - counters.) - However, it is possible, that they rely on protection - made by us here. - - Check this and shot the lock. It is not prone from deadlocks. - Either shot noqueue qdisc, it is even simpler 8) - */ - if (dev->flags & IFF_UP) { - int cpu = smp_processor_id(); /* ok because BHs are off */ - - if (txq->xmit_lock_owner != cpu) { - - HARD_TX_LOCK(dev, txq, cpu); - - if (!netif_tx_queue_stopped(txq)) { - rc = 0; - if (!dev_hard_start_xmit(skb, dev, txq)) { - HARD_TX_UNLOCK(dev, txq); - goto out; - } - } - HARD_TX_UNLOCK(dev, txq); - if (net_ratelimit()) - printk(KERN_CRIT "Virtual device %s asks to " - "queue packet!\n", dev->name); - } else { - /* Recursion is detected! It is possible, - * unfortunately */ - if (net_ratelimit()) - printk(KERN_CRIT "Dead loop on virtual device " - "%s, fix it urgently!\n", dev->name); - } - } - - rc = -ENETDOWN; - rcu_read_unlock_bh(); - -out_kfree_skb: - kfree_skb(skb); - return rc; -out: - rcu_read_unlock_bh(); - return rc; -} - - -/*======================================================================= - Receiver routines - =======================================================================*/ - -int netdev_max_backlog __read_mostly = 1000; -int netdev_budget __read_mostly = 300; -int weight_p __read_mostly = 64; /* old backlog weight */ - -DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, }; - - -/** - * netif_rx - post buffer to the network code - * @skb: buffer to post - * - * This function receives a packet from a device driver and queues it for - * the upper (protocol) levels to process. It always succeeds. The buffer - * may be dropped during processing for congestion control or by the - * protocol layers. - * - * return values: - * NET_RX_SUCCESS (no congestion) - * NET_RX_DROP (packet was dropped) - * - */ - -int netif_rx(struct sk_buff *skb) -{ - struct softnet_data *queue; - unsigned long flags; - - /* if netpoll wants it, pretend we never saw it */ - if (netpoll_rx(skb)) - return NET_RX_DROP; - - if (!skb->tstamp.tv64) - net_timestamp(skb); - - /* - * The code is rearranged so that the path is the most - * short when CPU is congested, but is still operating. - */ - local_irq_save(flags); - queue = &__get_cpu_var(softnet_data); - - __get_cpu_var(netdev_rx_stat).total++; - if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { - if (queue->input_pkt_queue.qlen) { -enqueue: - __skb_queue_tail(&queue->input_pkt_queue, skb); - local_irq_restore(flags); - return NET_RX_SUCCESS; - } - - napi_schedule(&queue->backlog); - goto enqueue; - } - - __get_cpu_var(netdev_rx_stat).dropped++; - local_irq_restore(flags); - - kfree_skb(skb); - return NET_RX_DROP; -} - -int netif_rx_ni(struct sk_buff *skb) -{ - int err; - - preempt_disable(); - err = netif_rx(skb); - if (local_softirq_pending()) - do_softirq(); - preempt_enable(); - - return err; -} - -EXPORT_SYMBOL(netif_rx_ni); - -static void net_tx_action(struct softirq_action *h) -{ - struct softnet_data *sd = &__get_cpu_var(softnet_data); - - if (sd->completion_queue) { - struct sk_buff *clist; - - local_irq_disable(); - clist = sd->completion_queue; - sd->completion_queue = NULL; - local_irq_enable(); - - while (clist) { - struct sk_buff *skb = clist; - clist = clist->next; - - WARN_ON(atomic_read(&skb->users)); - __kfree_skb(skb); - } - } - - if (sd->output_queue) { - struct Qdisc *head; - - local_irq_disable(); - head = sd->output_queue; - sd->output_queue = NULL; - local_irq_enable(); - - while (head) { - struct Qdisc *q = head; - spinlock_t *root_lock; - - head = head->next_sched; - - root_lock = qdisc_lock(q); - if (spin_trylock(root_lock)) { - smp_mb__before_clear_bit(); - clear_bit(__QDISC_STATE_SCHED, - &q->state); - qdisc_run(q); - spin_unlock(root_lock); - } else { - if (!test_bit(__QDISC_STATE_DEACTIVATED, - &q->state)) { - __netif_reschedule(q); - } else { - smp_mb__before_clear_bit(); - clear_bit(__QDISC_STATE_SCHED, - &q->state); - } - } - } - } -} - -static inline int deliver_skb(struct sk_buff *skb, - struct packet_type *pt_prev, - struct net_device *orig_dev) -{ - atomic_inc(&skb->users); - return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); -} - -#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) -/* These hooks defined here for ATM */ -struct net_bridge; -struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, - unsigned char *addr); -void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly; - -/* - * If bridge module is loaded call bridging hook. - * returns NULL if packet was consumed. - */ -struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, - struct sk_buff *skb) __read_mostly; -static inline struct sk_buff *handle_bridge(struct sk_buff *skb, - struct packet_type **pt_prev, int *ret, - struct net_device *orig_dev) -{ - struct net_bridge_port *port; - - if (skb->pkt_type == PACKET_LOOPBACK || - (port = rcu_dereference(skb->dev->br_port)) == NULL) - return skb; - - if (*pt_prev) { - *ret = deliver_skb(skb, *pt_prev, orig_dev); - *pt_prev = NULL; - } - - return br_handle_frame_hook(port, skb); -} -#else -#define handle_bridge(skb, pt_prev, ret, orig_dev) (skb) -#endif - -#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *skb) __read_mostly; -EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook); - -static inline struct sk_buff *handle_macvlan(struct sk_buff *skb, - struct packet_type **pt_prev, - int *ret, - struct net_device *orig_dev) -{ - if (skb->dev->macvlan_port == NULL) - return skb; - - if (*pt_prev) { - *ret = deliver_skb(skb, *pt_prev, orig_dev); - *pt_prev = NULL; - } - return macvlan_handle_frame_hook(skb); -} -#else -#define handle_macvlan(skb, pt_prev, ret, orig_dev) (skb) -#endif - -#ifdef CONFIG_NET_CLS_ACT -/* TODO: Maybe we should just force sch_ingress to be compiled in - * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions - * a compare and 2 stores extra right now if we dont have it on - * but have CONFIG_NET_CLS_ACT - * NOTE: This doesnt stop any functionality; if you dont have - * the ingress scheduler, you just cant add policies on ingress. - * - */ -static int ing_filter(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - u32 ttl = G_TC_RTTL(skb->tc_verd); - struct netdev_queue *rxq; - int result = TC_ACT_OK; - struct Qdisc *q; - - if (MAX_RED_LOOP < ttl++) { - printk(KERN_WARNING - "Redir loop detected Dropping packet (%d->%d)\n", - skb->iif, dev->ifindex); - return TC_ACT_SHOT; - } - - skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl); - skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); - - rxq = &dev->rx_queue; - - q = rxq->qdisc; - if (q != &noop_qdisc) { - spin_lock(qdisc_lock(q)); - if (likely(!test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) - result = qdisc_enqueue_root(skb, q); - spin_unlock(qdisc_lock(q)); - } - - return result; -} - -static inline struct sk_buff *handle_ing(struct sk_buff *skb, - struct packet_type **pt_prev, - int *ret, struct net_device *orig_dev) -{ - if (skb->dev->rx_queue.qdisc == &noop_qdisc) - goto out; - - if (*pt_prev) { - *ret = deliver_skb(skb, *pt_prev, orig_dev); - *pt_prev = NULL; - } else { - /* Huh? Why does turning on AF_PACKET affect this? */ - skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); - } - - switch (ing_filter(skb)) { - case TC_ACT_SHOT: - case TC_ACT_STOLEN: - kfree_skb(skb); - return NULL; - } - -out: - skb->tc_verd = 0; - return skb; -} -#endif - -/* - * netif_nit_deliver - deliver received packets to network taps - * @skb: buffer - * - * This function is used to deliver incoming packets to network - * taps. It should be used when the normal netif_receive_skb path - * is bypassed, for example because of VLAN acceleration. - */ -void netif_nit_deliver(struct sk_buff *skb) -{ - struct packet_type *ptype; - - if (list_empty(&ptype_all)) - return; - - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - skb->mac_len = skb->network_header - skb->mac_header; - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, &ptype_all, list) { - if (!ptype->dev || ptype->dev == skb->dev) - deliver_skb(skb, ptype, skb->dev); - } - rcu_read_unlock(); -} - -/** - * netif_receive_skb - process receive buffer from network - * @skb: buffer to process - * - * netif_receive_skb() is the main receive data processing function. - * It always succeeds. The buffer may be dropped during processing - * for congestion control or by the protocol layers. - * - * This function may only be called from softirq context and interrupts - * should be enabled. - * - * Return values (usually ignored): - * NET_RX_SUCCESS: no congestion - * NET_RX_DROP: packet was dropped - */ -int netif_receive_skb(struct sk_buff *skb) -{ - struct packet_type *ptype, *pt_prev; - struct net_device *orig_dev; - struct net_device *null_or_orig; - int ret = NET_RX_DROP; - __be16 type; - - if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) - return NET_RX_SUCCESS; - - /* if we've gotten here through NAPI, check netpoll */ - if (netpoll_receive_skb(skb)) - return NET_RX_DROP; - - if (!skb->tstamp.tv64) - net_timestamp(skb); - - if (!skb->iif) - skb->iif = skb->dev->ifindex; - - null_or_orig = NULL; - orig_dev = skb->dev; - if (orig_dev->master) { - if (skb_bond_should_drop(skb)) - null_or_orig = orig_dev; /* deliver only exact match */ - else - skb->dev = orig_dev->master; - } - - __get_cpu_var(netdev_rx_stat).total++; - - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - skb->mac_len = skb->network_header - skb->mac_header; - - pt_prev = NULL; - - rcu_read_lock(); - -#ifdef CONFIG_NET_CLS_ACT - if (skb->tc_verd & TC_NCLS) { - skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); - goto ncls; - } -#endif - - list_for_each_entry_rcu(ptype, &ptype_all, list) { - if (ptype->dev == null_or_orig || ptype->dev == skb->dev || - ptype->dev == orig_dev) { - if (pt_prev) - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = ptype; - } - } - -#ifdef CONFIG_NET_CLS_ACT - skb = handle_ing(skb, &pt_prev, &ret, orig_dev); - if (!skb) - goto out; -ncls: -#endif - - skb = handle_bridge(skb, &pt_prev, &ret, orig_dev); - if (!skb) - goto out; - skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev); - if (!skb) - goto out; - - type = skb->protocol; - list_for_each_entry_rcu(ptype, - &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { - if (ptype->type == type && - (ptype->dev == null_or_orig || ptype->dev == skb->dev || - ptype->dev == orig_dev)) { - if (pt_prev) - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = ptype; - } - } - - if (pt_prev) { - ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); - } else { - kfree_skb(skb); - /* Jamal, now you will not able to escape explaining - * me how you were going to use this. :-) - */ - ret = NET_RX_DROP; - } - -out: - rcu_read_unlock(); - return ret; -} - -/* Network device is going away, flush any packets still pending */ -static void flush_backlog(void *arg) -{ - struct net_device *dev = arg; - struct softnet_data *queue = &__get_cpu_var(softnet_data); - struct sk_buff *skb, *tmp; - - skb_queue_walk_safe(&queue->input_pkt_queue, skb, tmp) - if (skb->dev == dev) { - __skb_unlink(skb, &queue->input_pkt_queue); - kfree_skb(skb); - } -} - -static int napi_gro_complete(struct sk_buff *skb) -{ - struct packet_type *ptype; - __be16 type = skb->protocol; - struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; - int err = -ENOENT; - - if (NAPI_GRO_CB(skb)->count == 1) - goto out; - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, head, list) { - if (ptype->type != type || ptype->dev || !ptype->gro_complete) - continue; - - err = ptype->gro_complete(skb); - break; - } - rcu_read_unlock(); - - if (err) { - WARN_ON(&ptype->list == head); - kfree_skb(skb); - return NET_RX_SUCCESS; - } - -out: - skb_shinfo(skb)->gso_size = 0; - __skb_push(skb, -skb_network_offset(skb)); - return netif_receive_skb(skb); -} - -void napi_gro_flush(struct napi_struct *napi) -{ - struct sk_buff *skb, *next; - - for (skb = napi->gro_list; skb; skb = next) { - next = skb->next; - skb->next = NULL; - napi_gro_complete(skb); - } - - napi->gro_list = NULL; -} -EXPORT_SYMBOL(napi_gro_flush); - -int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -{ - struct sk_buff **pp = NULL; - struct packet_type *ptype; - __be16 type = skb->protocol; - struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; - int count = 0; - int same_flow; - int mac_len; - int free; - - if (!(skb->dev->features & NETIF_F_GRO)) - goto normal; - - if (skb_is_gso(skb) || skb_shinfo(skb)->frag_list) - goto normal; - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, head, list) { - struct sk_buff *p; - - if (ptype->type != type || ptype->dev || !ptype->gro_receive) - continue; - - skb_reset_network_header(skb); - mac_len = skb->network_header - skb->mac_header; - skb->mac_len = mac_len; - NAPI_GRO_CB(skb)->same_flow = 0; - NAPI_GRO_CB(skb)->flush = 0; - NAPI_GRO_CB(skb)->free = 0; - - for (p = napi->gro_list; p; p = p->next) { - count++; - - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - if (p->mac_len != mac_len || - memcmp(skb_mac_header(p), skb_mac_header(skb), - mac_len)) - NAPI_GRO_CB(p)->same_flow = 0; - } - - pp = ptype->gro_receive(&napi->gro_list, skb); - break; - } - rcu_read_unlock(); - - if (&ptype->list == head) - goto normal; - - same_flow = NAPI_GRO_CB(skb)->same_flow; - free = NAPI_GRO_CB(skb)->free; - - if (pp) { - struct sk_buff *nskb = *pp; - - *pp = nskb->next; - nskb->next = NULL; - napi_gro_complete(nskb); - count--; - } - - if (same_flow) - goto ok; - - if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) { - __skb_push(skb, -skb_network_offset(skb)); - goto normal; - } - - NAPI_GRO_CB(skb)->count = 1; - skb_shinfo(skb)->gso_size = skb->len; - skb->next = napi->gro_list; - napi->gro_list = skb; - -ok: - return free; - -normal: - return -1; -} -EXPORT_SYMBOL(dev_gro_receive); - -static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -{ - struct sk_buff *p; - - for (p = napi->gro_list; p; p = p->next) { - NAPI_GRO_CB(p)->same_flow = 1; - NAPI_GRO_CB(p)->flush = 0; - } - - return dev_gro_receive(napi, skb); -} - -int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -{ - if (netpoll_receive_skb(skb)) - return NET_RX_DROP; - - switch (__napi_gro_receive(napi, skb)) { - case -1: - return netif_receive_skb(skb); - - case 1: - kfree_skb(skb); - break; - } - - return NET_RX_SUCCESS; -} -EXPORT_SYMBOL(napi_gro_receive); - -void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) -{ - __skb_pull(skb, skb_headlen(skb)); - skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb)); - - napi->skb = skb; -} -EXPORT_SYMBOL(napi_reuse_skb); - -struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, - struct napi_gro_fraginfo *info) -{ - struct net_device *dev = napi->dev; - struct sk_buff *skb = napi->skb; - - napi->skb = NULL; - - if (!skb) { - skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN); - if (!skb) - goto out; - - skb_reserve(skb, NET_IP_ALIGN); - } - - BUG_ON(info->nr_frags > MAX_SKB_FRAGS); - skb_shinfo(skb)->nr_frags = info->nr_frags; - memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags)); - - skb->data_len = info->len; - skb->len += info->len; - skb->truesize += info->len; - - if (!pskb_may_pull(skb, ETH_HLEN)) { - napi_reuse_skb(napi, skb); - skb = NULL; - goto out; - } - - skb->protocol = eth_type_trans(skb, dev); - - skb->ip_summed = info->ip_summed; - skb->csum = info->csum; - -out: - return skb; -} -EXPORT_SYMBOL(napi_fraginfo_skb); - -int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info) -{ - struct sk_buff *skb = napi_fraginfo_skb(napi, info); - int err = NET_RX_DROP; - - if (!skb) - goto out; - - if (netpoll_receive_skb(skb)) - goto out; - - err = NET_RX_SUCCESS; - - switch (__napi_gro_receive(napi, skb)) { - case -1: - return netif_receive_skb(skb); - - case 0: - goto out; - } - - napi_reuse_skb(napi, skb); - -out: - return err; -} -EXPORT_SYMBOL(napi_gro_frags); - -static int process_backlog(struct napi_struct *napi, int quota) -{ - int work = 0; - struct softnet_data *queue = &__get_cpu_var(softnet_data); - unsigned long start_time = jiffies; - - napi->weight = weight_p; - do { - struct sk_buff *skb; - - local_irq_disable(); - skb = __skb_dequeue(&queue->input_pkt_queue); - if (!skb) { - local_irq_enable(); - napi_complete(napi); - goto out; - } - local_irq_enable(); - - napi_gro_receive(napi, skb); - } while (++work < quota && jiffies == start_time); - - napi_gro_flush(napi); - -out: - return work; -} - -/** - * __napi_schedule - schedule for receive - * @n: entry to schedule - * - * The entry's receive function will be scheduled to run - */ -void __napi_schedule(struct napi_struct *n) -{ - unsigned long flags; - - local_irq_save(flags); - list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list); - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - local_irq_restore(flags); -} -EXPORT_SYMBOL(__napi_schedule); - -void __napi_complete(struct napi_struct *n) -{ - BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); - BUG_ON(n->gro_list); - - list_del(&n->poll_list); - smp_mb__before_clear_bit(); - clear_bit(NAPI_STATE_SCHED, &n->state); -} -EXPORT_SYMBOL(__napi_complete); - -void napi_complete(struct napi_struct *n) -{ - unsigned long flags; - - /* - * don't let napi dequeue from the cpu poll list - * just in case its running on a different cpu - */ - if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) - return; - - napi_gro_flush(n); - local_irq_save(flags); - __napi_complete(n); - local_irq_restore(flags); -} -EXPORT_SYMBOL(napi_complete); - -void netif_napi_add(struct net_device *dev, struct napi_struct *napi, - int (*poll)(struct napi_struct *, int), int weight) -{ - INIT_LIST_HEAD(&napi->poll_list); - napi->gro_list = NULL; - napi->skb = NULL; - napi->poll = poll; - napi->weight = weight; - list_add(&napi->dev_list, &dev->napi_list); - napi->dev = dev; -#ifdef CONFIG_NETPOLL - spin_lock_init(&napi->poll_lock); - napi->poll_owner = -1; -#endif - set_bit(NAPI_STATE_SCHED, &napi->state); -} -EXPORT_SYMBOL(netif_napi_add); - -void netif_napi_del(struct napi_struct *napi) -{ - struct sk_buff *skb, *next; - - list_del_init(&napi->dev_list); - kfree_skb(napi->skb); - - for (skb = napi->gro_list; skb; skb = next) { - next = skb->next; - skb->next = NULL; - kfree_skb(skb); - } - - napi->gro_list = NULL; -} -EXPORT_SYMBOL(netif_napi_del); - - -static void net_rx_action(struct softirq_action *h) -{ - struct list_head *list = &__get_cpu_var(softnet_data).poll_list; - unsigned long time_limit = jiffies + 2; - int budget = netdev_budget; - void *have; - - local_irq_disable(); - - while (!list_empty(list)) { - struct napi_struct *n; - int work, weight; - - /* If softirq window is exhuasted then punt. - * Allow this to run for 2 jiffies since which will allow - * an average latency of 1.5/HZ. - */ - if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) - goto softnet_break; - - local_irq_enable(); - - /* Even though interrupts have been re-enabled, this - * access is safe because interrupts can only add new - * entries to the tail of this list, and only ->poll() - * calls can remove this head entry from the list. - */ - n = list_entry(list->next, struct napi_struct, poll_list); - - have = netpoll_poll_lock(n); - - weight = n->weight; - - /* This NAPI_STATE_SCHED test is for avoiding a race - * with netpoll's poll_napi(). Only the entity which - * obtains the lock and sees NAPI_STATE_SCHED set will - * actually make the ->poll() call. Therefore we avoid - * accidently calling ->poll() when NAPI is not scheduled. - */ - work = 0; - if (test_bit(NAPI_STATE_SCHED, &n->state)) - work = n->poll(n, weight); - - WARN_ON_ONCE(work > weight); - - budget -= work; - - local_irq_disable(); - - /* Drivers must not modify the NAPI state if they - * consume the entire weight. In such cases this code - * still "owns" the NAPI instance and therefore can - * move the instance around on the list at-will. - */ - if (unlikely(work == weight)) { - if (unlikely(napi_disable_pending(n))) - __napi_complete(n); - else - list_move_tail(&n->poll_list, list); - } - - netpoll_poll_unlock(have); - } -out: - local_irq_enable(); - -#ifdef CONFIG_NET_DMA - /* - * There may not be any more sk_buffs coming right now, so push - * any pending DMA copies to hardware - */ - dma_issue_pending_all(); -#endif - - return; - -softnet_break: - __get_cpu_var(netdev_rx_stat).time_squeeze++; - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - goto out; -} - -static gifconf_func_t * gifconf_list [NPROTO]; - -/** - * register_gifconf - register a SIOCGIF handler - * @family: Address family - * @gifconf: Function handler - * - * Register protocol dependent address dumping routines. The handler - * that is passed must not be freed or reused until it has been replaced - * by another handler. - */ -int register_gifconf(unsigned int family, gifconf_func_t * gifconf) -{ - if (family >= NPROTO) - return -EINVAL; - gifconf_list[family] = gifconf; - return 0; -} - - -/* - * Map an interface index to its name (SIOCGIFNAME) - */ - -/* - * We need this ioctl for efficient implementation of the - * if_indextoname() function required by the IPv6 API. Without - * it, we would have to search all the interfaces to find a - * match. --pb - */ - -static int dev_ifname(struct net *net, struct ifreq __user *arg) -{ - struct net_device *dev; - struct ifreq ifr; - - /* - * Fetch the caller's info block. - */ - - if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) - return -EFAULT; - - read_lock(&dev_base_lock); - dev = __dev_get_by_index(net, ifr.ifr_ifindex); - if (!dev) { - read_unlock(&dev_base_lock); - return -ENODEV; - } - - strcpy(ifr.ifr_name, dev->name); - read_unlock(&dev_base_lock); - - if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) - return -EFAULT; - return 0; -} - -/* - * Perform a SIOCGIFCONF call. This structure will change - * size eventually, and there is nothing I can do about it. - * Thus we will need a 'compatibility mode'. - */ - -static int dev_ifconf(struct net *net, char __user *arg) -{ - struct ifconf ifc; - struct net_device *dev; - char __user *pos; - int len; - int total; - int i; - - /* - * Fetch the caller's info block. - */ - - if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) - return -EFAULT; - - pos = ifc.ifc_buf; - len = ifc.ifc_len; - - /* - * Loop over the interfaces, and write an info block for each. - */ - - total = 0; - for_each_netdev(net, dev) { - for (i = 0; i < NPROTO; i++) { - if (gifconf_list[i]) { - int done; - if (!pos) - done = gifconf_list[i](dev, NULL, 0); - else - done = gifconf_list[i](dev, pos + total, - len - total); - if (done < 0) - return -EFAULT; - total += done; - } - } - } - - /* - * All done. Write the updated control block back to the caller. - */ - ifc.ifc_len = total; - - /* - * Both BSD and Solaris return 0 here, so we do too. - */ - return copy_to_user(arg, &ifc, sizeof(struct ifconf)) ? -EFAULT : 0; -} - -#ifdef CONFIG_PROC_FS -/* - * This is invoked by the /proc filesystem handler to display a device - * in detail. - */ -void *dev_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) -{ - struct net *net = seq_file_net(seq); - loff_t off; - struct net_device *dev; - - read_lock(&dev_base_lock); - if (!*pos) - return SEQ_START_TOKEN; - - off = 1; - for_each_netdev(net, dev) - if (off++ == *pos) - return dev; - - return NULL; -} - -void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct net *net = seq_file_net(seq); - ++*pos; - return v == SEQ_START_TOKEN ? - first_net_device(net) : next_net_device((struct net_device *)v); -} - -void dev_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) -{ - read_unlock(&dev_base_lock); -} - -static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) -{ - const struct net_device_stats *stats = dev_get_stats(dev); - - seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " - "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", - dev->name, stats->rx_bytes, stats->rx_packets, - stats->rx_errors, - stats->rx_dropped + stats->rx_missed_errors, - stats->rx_fifo_errors, - stats->rx_length_errors + stats->rx_over_errors + - stats->rx_crc_errors + stats->rx_frame_errors, - stats->rx_compressed, stats->multicast, - stats->tx_bytes, stats->tx_packets, - stats->tx_errors, stats->tx_dropped, - stats->tx_fifo_errors, stats->collisions, - stats->tx_carrier_errors + - stats->tx_aborted_errors + - stats->tx_window_errors + - stats->tx_heartbeat_errors, - stats->tx_compressed); -} - -/* - * Called from the PROCfs module. This now uses the new arbitrary sized - * /proc/net interface to create /proc/net/dev - */ -static int dev_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, "Inter-| Receive " - " | Transmit\n" - " face |bytes packets errs drop fifo frame " - "compressed multicast|bytes packets errs " - "drop fifo colls carrier compressed\n"); - else - dev_seq_printf_stats(seq, v); - return 0; -} - -static struct netif_rx_stats *softnet_get_online(loff_t *pos) -{ - struct netif_rx_stats *rc = NULL; - - while (*pos < nr_cpu_ids) - if (cpu_online(*pos)) { - rc = &per_cpu(netdev_rx_stat, *pos); - break; - } else - ++*pos; - return rc; -} - -static void *softnet_seq_start(struct seq_file *seq, loff_t *pos) -{ - return softnet_get_online(pos); -} - -static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return softnet_get_online(pos); -} - -static void softnet_seq_stop(struct seq_file *seq, void *v) -{ -} - -static int softnet_seq_show(struct seq_file *seq, void *v) -{ - struct netif_rx_stats *s = v; - - seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", - s->total, s->dropped, s->time_squeeze, 0, - 0, 0, 0, 0, /* was fastroute */ - s->cpu_collision ); - return 0; -} - -static const struct seq_operations dev_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = dev_seq_show, -}; - -static int dev_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &dev_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations dev_seq_fops = { - .owner = THIS_MODULE, - .open = dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static const struct seq_operations softnet_seq_ops = { - .start = softnet_seq_start, - .next = softnet_seq_next, - .stop = softnet_seq_stop, - .show = softnet_seq_show, -}; - -static int softnet_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &softnet_seq_ops); -} - -static const struct file_operations softnet_seq_fops = { - .owner = THIS_MODULE, - .open = softnet_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static void *ptype_get_idx(loff_t pos) -{ - struct packet_type *pt = NULL; - loff_t i = 0; - int t; - - list_for_each_entry_rcu(pt, &ptype_all, list) { - if (i == pos) - return pt; - ++i; - } - - for (t = 0; t < PTYPE_HASH_SIZE; t++) { - list_for_each_entry_rcu(pt, &ptype_base[t], list) { - if (i == pos) - return pt; - ++i; - } - } - return NULL; -} - -static void *ptype_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN; -} - -static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct packet_type *pt; - struct list_head *nxt; - int hash; - - ++*pos; - if (v == SEQ_START_TOKEN) - return ptype_get_idx(0); - - pt = v; - nxt = pt->list.next; - if (pt->type == htons(ETH_P_ALL)) { - if (nxt != &ptype_all) - goto found; - hash = 0; - nxt = ptype_base[0].next; - } else - hash = ntohs(pt->type) & PTYPE_HASH_MASK; - - while (nxt == &ptype_base[hash]) { - if (++hash >= PTYPE_HASH_SIZE) - return NULL; - nxt = ptype_base[hash].next; - } -found: - return list_entry(nxt, struct packet_type, list); -} - -static void ptype_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - -static int ptype_seq_show(struct seq_file *seq, void *v) -{ - struct packet_type *pt = v; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, "Type Device Function\n"); - else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) { - if (pt->type == htons(ETH_P_ALL)) - seq_puts(seq, "ALL "); - else - seq_printf(seq, "%04x", ntohs(pt->type)); - - seq_printf(seq, " %-8s %pF\n", - pt->dev ? pt->dev->name : "", pt->func); - } - - return 0; -} - -static const struct seq_operations ptype_seq_ops = { - .start = ptype_seq_start, - .next = ptype_seq_next, - .stop = ptype_seq_stop, - .show = ptype_seq_show, -}; - -static int ptype_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &ptype_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations ptype_seq_fops = { - .owner = THIS_MODULE, - .open = ptype_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - - -static int __net_init dev_proc_net_init(struct net *net) -{ - int rc = -ENOMEM; - - if (!proc_net_fops_create(net, "dev", S_IRUGO, &dev_seq_fops)) - goto out; - if (!proc_net_fops_create(net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) - goto out_dev; - if (!proc_net_fops_create(net, "ptype", S_IRUGO, &ptype_seq_fops)) - goto out_softnet; - - if (wext_proc_init(net)) - goto out_ptype; - rc = 0; -out: - return rc; -out_ptype: - proc_net_remove(net, "ptype"); -out_softnet: - proc_net_remove(net, "softnet_stat"); -out_dev: - proc_net_remove(net, "dev"); - goto out; -} - -static void __net_exit dev_proc_net_exit(struct net *net) -{ - wext_proc_exit(net); - - proc_net_remove(net, "ptype"); - proc_net_remove(net, "softnet_stat"); - proc_net_remove(net, "dev"); -} - -static struct pernet_operations __net_initdata dev_proc_ops = { - .init = dev_proc_net_init, - .exit = dev_proc_net_exit, -}; - -static int __init dev_proc_init(void) -{ - return register_pernet_subsys(&dev_proc_ops); -} -#else -#define dev_proc_init() 0 -#endif /* CONFIG_PROC_FS */ - - -/** - * netdev_set_master - set up master/slave pair - * @slave: slave device - * @master: new master device - * - * Changes the master device of the slave. Pass %NULL to break the - * bonding. The caller must hold the RTNL semaphore. On a failure - * a negative errno code is returned. On success the reference counts - * are adjusted, %RTM_NEWLINK is sent to the routing socket and the - * function returns zero. - */ -int netdev_set_master(struct net_device *slave, struct net_device *master) -{ - struct net_device *old = slave->master; - - ASSERT_RTNL(); - - if (master) { - if (old) - return -EBUSY; - dev_hold(master); - } - - slave->master = master; - - synchronize_net(); - - if (old) - dev_put(old); - - if (master) - slave->flags |= IFF_SLAVE; - else - slave->flags &= ~IFF_SLAVE; - - rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE); - return 0; -} - -static void dev_change_rx_flags(struct net_device *dev, int flags) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags) - ops->ndo_change_rx_flags(dev, flags); -} - -static int __dev_set_promiscuity(struct net_device *dev, int inc) -{ - unsigned short old_flags = dev->flags; - uid_t uid; - gid_t gid; - - ASSERT_RTNL(); - - dev->flags |= IFF_PROMISC; - dev->promiscuity += inc; - if (dev->promiscuity == 0) { - /* - * Avoid overflow. - * If inc causes overflow, untouch promisc and return error. - */ - if (inc < 0) - dev->flags &= ~IFF_PROMISC; - else { - dev->promiscuity -= inc; - printk(KERN_WARNING "%s: promiscuity touches roof, " - "set promiscuity failed, promiscuity feature " - "of device might be broken.\n", dev->name); - return -EOVERFLOW; - } - } - if (dev->flags != old_flags) { - printk(KERN_INFO "device %s %s promiscuous mode\n", - dev->name, (dev->flags & IFF_PROMISC) ? "entered" : - "left"); - if (audit_enabled) { - current_uid_gid(&uid, &gid); - audit_log(current->audit_context, GFP_ATOMIC, - AUDIT_ANOM_PROMISCUOUS, - "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u", - dev->name, (dev->flags & IFF_PROMISC), - (old_flags & IFF_PROMISC), - audit_get_loginuid(current), - uid, gid, - audit_get_sessionid(current)); - } - - dev_change_rx_flags(dev, IFF_PROMISC); - } - return 0; -} - -/** - * dev_set_promiscuity - update promiscuity count on a device - * @dev: device - * @inc: modifier - * - * Add or remove promiscuity from a device. While the count in the device - * remains above zero the interface remains promiscuous. Once it hits zero - * the device reverts back to normal filtering operation. A negative inc - * value is used to drop promiscuity on the device. - * Return 0 if successful or a negative errno code on error. - */ -int dev_set_promiscuity(struct net_device *dev, int inc) -{ - unsigned short old_flags = dev->flags; - int err; - - err = __dev_set_promiscuity(dev, inc); - if (err < 0) - return err; - if (dev->flags != old_flags) - dev_set_rx_mode(dev); - return err; -} - -/** - * dev_set_allmulti - update allmulti count on a device - * @dev: device - * @inc: modifier - * - * Add or remove reception of all multicast frames to a device. While the - * count in the device remains above zero the interface remains listening - * to all interfaces. Once it hits zero the device reverts back to normal - * filtering operation. A negative @inc value is used to drop the counter - * when releasing a resource needing all multicasts. - * Return 0 if successful or a negative errno code on error. - */ - -int dev_set_allmulti(struct net_device *dev, int inc) -{ - unsigned short old_flags = dev->flags; - - ASSERT_RTNL(); - - dev->flags |= IFF_ALLMULTI; - dev->allmulti += inc; - if (dev->allmulti == 0) { - /* - * Avoid overflow. - * If inc causes overflow, untouch allmulti and return error. - */ - if (inc < 0) - dev->flags &= ~IFF_ALLMULTI; - else { - dev->allmulti -= inc; - printk(KERN_WARNING "%s: allmulti touches roof, " - "set allmulti failed, allmulti feature of " - "device might be broken.\n", dev->name); - return -EOVERFLOW; - } - } - if (dev->flags ^ old_flags) { - dev_change_rx_flags(dev, IFF_ALLMULTI); - dev_set_rx_mode(dev); - } - return 0; -} - -/* - * Upload unicast and multicast address lists to device and - * configure RX filtering. When the device doesn't support unicast - * filtering it is put in promiscuous mode while unicast addresses - * are present. - */ -void __dev_set_rx_mode(struct net_device *dev) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - /* dev_open will call this function so the list will stay sane. */ - if (!(dev->flags&IFF_UP)) - return; - - if (!netif_device_present(dev)) - return; - - if (ops->ndo_set_rx_mode) - ops->ndo_set_rx_mode(dev); - else { - /* Unicast addresses changes may only happen under the rtnl, - * therefore calling __dev_set_promiscuity here is safe. - */ - if (dev->uc_count > 0 && !dev->uc_promisc) { - __dev_set_promiscuity(dev, 1); - dev->uc_promisc = 1; - } else if (dev->uc_count == 0 && dev->uc_promisc) { - __dev_set_promiscuity(dev, -1); - dev->uc_promisc = 0; - } - - if (ops->ndo_set_multicast_list) - ops->ndo_set_multicast_list(dev); - } -} - -void dev_set_rx_mode(struct net_device *dev) -{ - netif_addr_lock_bh(dev); - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); -} - -int __dev_addr_delete(struct dev_addr_list **list, int *count, - void *addr, int alen, int glbl) -{ - struct dev_addr_list *da; - - for (; (da = *list) != NULL; list = &da->next) { - if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 && - alen == da->da_addrlen) { - if (glbl) { - int old_glbl = da->da_gusers; - da->da_gusers = 0; - if (old_glbl == 0) - break; - } - if (--da->da_users) - return 0; - - *list = da->next; - kfree(da); - (*count)--; - return 0; - } - } - return -ENOENT; -} - -int __dev_addr_add(struct dev_addr_list **list, int *count, - void *addr, int alen, int glbl) -{ - struct dev_addr_list *da; - - for (da = *list; da != NULL; da = da->next) { - if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 && - da->da_addrlen == alen) { - if (glbl) { - int old_glbl = da->da_gusers; - da->da_gusers = 1; - if (old_glbl) - return 0; - } - da->da_users++; - return 0; - } - } - - da = kzalloc(sizeof(*da), GFP_ATOMIC); - if (da == NULL) - return -ENOMEM; - memcpy(da->da_addr, addr, alen); - da->da_addrlen = alen; - da->da_users = 1; - da->da_gusers = glbl ? 1 : 0; - da->next = *list; - *list = da; - (*count)++; - return 0; -} - -/** - * dev_unicast_delete - Release secondary unicast address. - * @dev: device - * @addr: address to delete - * @alen: length of @addr - * - * Release reference to a secondary unicast address and remove it - * from the device if the reference count drops to zero. - * - * The caller must hold the rtnl_mutex. - */ -int dev_unicast_delete(struct net_device *dev, void *addr, int alen) -{ - int err; - - ASSERT_RTNL(); - - netif_addr_lock_bh(dev); - err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(dev_unicast_delete); - -/** - * dev_unicast_add - add a secondary unicast address - * @dev: device - * @addr: address to add - * @alen: length of @addr - * - * Add a secondary unicast address to the device or increase - * the reference count if it already exists. - * - * The caller must hold the rtnl_mutex. - */ -int dev_unicast_add(struct net_device *dev, void *addr, int alen) -{ - int err; - - ASSERT_RTNL(); - - netif_addr_lock_bh(dev); - err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(dev_unicast_add); - -int __dev_addr_sync(struct dev_addr_list **to, int *to_count, - struct dev_addr_list **from, int *from_count) -{ - struct dev_addr_list *da, *next; - int err = 0; - - da = *from; - while (da != NULL) { - next = da->next; - if (!da->da_synced) { - err = __dev_addr_add(to, to_count, - da->da_addr, da->da_addrlen, 0); - if (err < 0) - break; - da->da_synced = 1; - da->da_users++; - } else if (da->da_users == 1) { - __dev_addr_delete(to, to_count, - da->da_addr, da->da_addrlen, 0); - __dev_addr_delete(from, from_count, - da->da_addr, da->da_addrlen, 0); - } - da = next; - } - return err; -} - -void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, - struct dev_addr_list **from, int *from_count) -{ - struct dev_addr_list *da, *next; - - da = *from; - while (da != NULL) { - next = da->next; - if (da->da_synced) { - __dev_addr_delete(to, to_count, - da->da_addr, da->da_addrlen, 0); - da->da_synced = 0; - __dev_addr_delete(from, from_count, - da->da_addr, da->da_addrlen, 0); - } - da = next; - } -} - -/** - * dev_unicast_sync - Synchronize device's unicast list to another device - * @to: destination device - * @from: source device - * - * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_tx_lock_bh. - * - * This function is intended to be called from the dev->set_rx_mode - * function of layered software devices. - */ -int dev_unicast_sync(struct net_device *to, struct net_device *from) -{ - int err = 0; - - netif_addr_lock_bh(to); - err = __dev_addr_sync(&to->uc_list, &to->uc_count, - &from->uc_list, &from->uc_count); - if (!err) - __dev_set_rx_mode(to); - netif_addr_unlock_bh(to); - return err; -} -EXPORT_SYMBOL(dev_unicast_sync); - -/** - * dev_unicast_unsync - Remove synchronized addresses from the destination device - * @to: destination device - * @from: source device - * - * Remove all addresses that were added to the destination device by - * dev_unicast_sync(). This function is intended to be called from the - * dev->stop function of layered software devices. - */ -void dev_unicast_unsync(struct net_device *to, struct net_device *from) -{ - netif_addr_lock_bh(from); - netif_addr_lock(to); - - __dev_addr_unsync(&to->uc_list, &to->uc_count, - &from->uc_list, &from->uc_count); - __dev_set_rx_mode(to); - - netif_addr_unlock(to); - netif_addr_unlock_bh(from); -} -EXPORT_SYMBOL(dev_unicast_unsync); - -static void __dev_addr_discard(struct dev_addr_list **list) -{ - struct dev_addr_list *tmp; - - while (*list != NULL) { - tmp = *list; - *list = tmp->next; - if (tmp->da_users > tmp->da_gusers) - printk("__dev_addr_discard: address leakage! " - "da_users=%d\n", tmp->da_users); - kfree(tmp); - } -} - -static void dev_addr_discard(struct net_device *dev) -{ - netif_addr_lock_bh(dev); - - __dev_addr_discard(&dev->uc_list); - dev->uc_count = 0; - - __dev_addr_discard(&dev->mc_list); - dev->mc_count = 0; - - netif_addr_unlock_bh(dev); -} - -/** - * dev_get_flags - get flags reported to userspace - * @dev: device - * - * Get the combination of flag bits exported through APIs to userspace. - */ -unsigned dev_get_flags(const struct net_device *dev) -{ - unsigned flags; - - flags = (dev->flags & ~(IFF_PROMISC | - IFF_ALLMULTI | - IFF_RUNNING | - IFF_LOWER_UP | - IFF_DORMANT)) | - (dev->gflags & (IFF_PROMISC | - IFF_ALLMULTI)); - - if (netif_running(dev)) { - if (netif_oper_up(dev)) - flags |= IFF_RUNNING; - if (netif_carrier_ok(dev)) - flags |= IFF_LOWER_UP; - if (netif_dormant(dev)) - flags |= IFF_DORMANT; - } - - return flags; -} - -/** - * dev_change_flags - change device settings - * @dev: device - * @flags: device state flags - * - * Change settings on device based state flags. The flags are - * in the userspace exported format. - */ -int dev_change_flags(struct net_device *dev, unsigned flags) -{ - int ret, changes; - int old_flags = dev->flags; - - ASSERT_RTNL(); - - /* - * Set the flags on our device. - */ - - dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | - IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | - IFF_AUTOMEDIA)) | - (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | - IFF_ALLMULTI)); - - /* - * Load in the correct multicast list now the flags have changed. - */ - - if ((old_flags ^ flags) & IFF_MULTICAST) - dev_change_rx_flags(dev, IFF_MULTICAST); - - dev_set_rx_mode(dev); - - /* - * Have we downed the interface. We handle IFF_UP ourselves - * according to user attempts to set it, rather than blindly - * setting it. - */ - - ret = 0; - if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */ - ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); - - if (!ret) - dev_set_rx_mode(dev); - } - - if (dev->flags & IFF_UP && - ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | - IFF_VOLATILE))) - call_netdevice_notifiers(NETDEV_CHANGE, dev); - - if ((flags ^ dev->gflags) & IFF_PROMISC) { - int inc = (flags & IFF_PROMISC) ? +1 : -1; - dev->gflags ^= IFF_PROMISC; - dev_set_promiscuity(dev, inc); - } - - /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI - is important. Some (broken) drivers set IFF_PROMISC, when - IFF_ALLMULTI is requested not asking us and not reporting. - */ - if ((flags ^ dev->gflags) & IFF_ALLMULTI) { - int inc = (flags & IFF_ALLMULTI) ? +1 : -1; - dev->gflags ^= IFF_ALLMULTI; - dev_set_allmulti(dev, inc); - } - - /* Exclude state transition flags, already notified */ - changes = (old_flags ^ dev->flags) & ~(IFF_UP | IFF_RUNNING); - if (changes) - rtmsg_ifinfo(RTM_NEWLINK, dev, changes); - - return ret; -} - -/** - * dev_set_mtu - Change maximum transfer unit - * @dev: device - * @new_mtu: new transfer unit - * - * Change the maximum transfer size of the network device. - */ -int dev_set_mtu(struct net_device *dev, int new_mtu) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int err; - - if (new_mtu == dev->mtu) - return 0; - - /* MTU must be positive. */ - if (new_mtu < 0) - return -EINVAL; - - if (!netif_device_present(dev)) - return -ENODEV; - - err = 0; - if (ops->ndo_change_mtu) - err = ops->ndo_change_mtu(dev, new_mtu); - else - dev->mtu = new_mtu; - - if (!err && dev->flags & IFF_UP) - call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); - return err; -} - -/** - * dev_set_mac_address - Change Media Access Control Address - * @dev: device - * @sa: new address - * - * Change the hardware (MAC) address of the device - */ -int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int err; - - if (!ops->ndo_set_mac_address) - return -EOPNOTSUPP; - if (sa->sa_family != dev->type) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - err = ops->ndo_set_mac_address(dev, sa); - if (!err) - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return err; -} - -/* - * Perform the SIOCxIFxxx calls, inside read_lock(dev_base_lock) - */ -static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) -{ - int err; - struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); - - if (!dev) - return -ENODEV; - - switch (cmd) { - case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = dev_get_flags(dev); - return 0; - - case SIOCGIFMETRIC: /* Get the metric on the interface - (currently unused) */ - ifr->ifr_metric = 0; - return 0; - - case SIOCGIFMTU: /* Get the MTU of a device */ - ifr->ifr_mtu = dev->mtu; - return 0; - - case SIOCGIFHWADDR: - if (!dev->addr_len) - memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data); - else - memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, - min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - ifr->ifr_hwaddr.sa_family = dev->type; - return 0; - - case SIOCGIFSLAVE: - err = -EINVAL; - break; - - case SIOCGIFMAP: - ifr->ifr_map.mem_start = dev->mem_start; - ifr->ifr_map.mem_end = dev->mem_end; - ifr->ifr_map.base_addr = dev->base_addr; - ifr->ifr_map.irq = dev->irq; - ifr->ifr_map.dma = dev->dma; - ifr->ifr_map.port = dev->if_port; - return 0; - - case SIOCGIFINDEX: - ifr->ifr_ifindex = dev->ifindex; - return 0; - - case SIOCGIFTXQLEN: - ifr->ifr_qlen = dev->tx_queue_len; - return 0; - - default: - /* dev_ioctl() should ensure this case - * is never reached - */ - WARN_ON(1); - err = -EINVAL; - break; - - } - return err; -} - -/* - * Perform the SIOCxIFxxx calls, inside rtnl_lock() - */ -static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) -{ - int err; - struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); - const struct net_device_ops *ops; - - if (!dev) - return -ENODEV; - - ops = dev->netdev_ops; - - switch (cmd) { - case SIOCSIFFLAGS: /* Set interface flags */ - return dev_change_flags(dev, ifr->ifr_flags); - - case SIOCSIFMETRIC: /* Set the metric on the interface - (currently unused) */ - return -EOPNOTSUPP; - - case SIOCSIFMTU: /* Set the MTU of a device */ - return dev_set_mtu(dev, ifr->ifr_mtu); - - case SIOCSIFHWADDR: - return dev_set_mac_address(dev, &ifr->ifr_hwaddr); - - case SIOCSIFHWBROADCAST: - if (ifr->ifr_hwaddr.sa_family != dev->type) - return -EINVAL; - memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, - min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return 0; - - case SIOCSIFMAP: - if (ops->ndo_set_config) { - if (!netif_device_present(dev)) - return -ENODEV; - return ops->ndo_set_config(dev, &ifr->ifr_map); - } - return -EOPNOTSUPP; - - case SIOCADDMULTI: - if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || - ifr->ifr_hwaddr.sa_family != AF_UNSPEC) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - return dev_mc_add(dev, ifr->ifr_hwaddr.sa_data, - dev->addr_len, 1); - - case SIOCDELMULTI: - if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || - ifr->ifr_hwaddr.sa_family != AF_UNSPEC) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data, - dev->addr_len, 1); - - case SIOCSIFTXQLEN: - if (ifr->ifr_qlen < 0) - return -EINVAL; - dev->tx_queue_len = ifr->ifr_qlen; - return 0; - - case SIOCSIFNAME: - ifr->ifr_newname[IFNAMSIZ-1] = '\0'; - return dev_change_name(dev, ifr->ifr_newname); - - /* - * Unknown or private ioctl - */ - - default: - if ((cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15) || - cmd == SIOCBONDENSLAVE || - cmd == SIOCBONDRELEASE || - cmd == SIOCBONDSETHWADDR || - cmd == SIOCBONDSLAVEINFOQUERY || - cmd == SIOCBONDINFOQUERY || - cmd == SIOCBONDCHANGEACTIVE || - cmd == SIOCGMIIPHY || - cmd == SIOCGMIIREG || - cmd == SIOCSMIIREG || - cmd == SIOCBRADDIF || - cmd == SIOCBRDELIF || - cmd == SIOCWANDEV) { - err = -EOPNOTSUPP; - if (ops->ndo_do_ioctl) { - if (netif_device_present(dev)) - err = ops->ndo_do_ioctl(dev, ifr, cmd); - else - err = -ENODEV; - } - } else - err = -EINVAL; - - } - return err; -} - -/* - * This function handles all "interface"-type I/O control requests. The actual - * 'doing' part of this is dev_ifsioc above. - */ - -/** - * dev_ioctl - network device ioctl - * @net: the applicable net namespace - * @cmd: command to issue - * @arg: pointer to a struct ifreq in user space - * - * Issue ioctl functions to devices. This is normally called by the - * user space syscall interfaces but can sometimes be useful for - * other purposes. The return value is the return from the syscall if - * positive or a negative errno code on error. - */ - -int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) -{ - struct ifreq ifr; - int ret; - char *colon; - - /* One special case: SIOCGIFCONF takes ifconf argument - and requires shared lock, because it sleeps writing - to user space. - */ - - if (cmd == SIOCGIFCONF) { - rtnl_lock(); - ret = dev_ifconf(net, (char __user *) arg); - rtnl_unlock(); - return ret; - } - if (cmd == SIOCGIFNAME) - return dev_ifname(net, (struct ifreq __user *)arg); - - if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) - return -EFAULT; - - ifr.ifr_name[IFNAMSIZ-1] = 0; - - colon = strchr(ifr.ifr_name, ':'); - if (colon) - *colon = 0; - - /* - * See which interface the caller is talking about. - */ - - switch (cmd) { - /* - * These ioctl calls: - * - can be done by all. - * - atomic and do not require locking. - * - return a value - */ - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFHWADDR: - case SIOCGIFSLAVE: - case SIOCGIFMAP: - case SIOCGIFINDEX: - case SIOCGIFTXQLEN: - dev_load(net, ifr.ifr_name); - read_lock(&dev_base_lock); - ret = dev_ifsioc_locked(net, &ifr, cmd); - read_unlock(&dev_base_lock); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; - - case SIOCETHTOOL: - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ethtool(net, &ifr); - rtnl_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; - - /* - * These ioctl calls: - * - require superuser power. - * - require strict serialization. - * - return a value - */ - case SIOCGMIIPHY: - case SIOCGMIIREG: - case SIOCSIFNAME: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; - - /* - * These ioctl calls: - * - require superuser power. - * - require strict serialization. - * - do not return a value - */ - case SIOCSIFFLAGS: - case SIOCSIFMETRIC: - case SIOCSIFMTU: - case SIOCSIFMAP: - case SIOCSIFHWADDR: - case SIOCSIFSLAVE: - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCSIFHWBROADCAST: - case SIOCSIFTXQLEN: - case SIOCSMIIREG: - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - case SIOCBRADDIF: - case SIOCBRDELIF: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* fall through */ - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - return ret; - - case SIOCGIFMEM: - /* Get the per device memory space. We can add this but - * currently do not support it */ - case SIOCSIFMEM: - /* Set the per device memory buffer space. - * Not applicable in our case */ - case SIOCSIFLINK: - return -EINVAL; - - /* - * Unknown or private ioctl. - */ - default: - if (cmd == SIOCWANDEV || - (cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15)) { - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - if (!ret && copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - return ret; - } - /* Take care of Wireless Extensions */ - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) - return wext_handle_ioctl(net, &ifr, cmd, arg); - return -EINVAL; - } -} - - -/** - * dev_new_index - allocate an ifindex - * @net: the applicable net namespace - * - * Returns a suitable unique value for a new device interface - * number. The caller must hold the rtnl semaphore or the - * dev_base_lock to be sure it remains unique. - */ -static int dev_new_index(struct net *net) -{ - static int ifindex; - for (;;) { - if (++ifindex <= 0) - ifindex = 1; - if (!__dev_get_by_index(net, ifindex)) - return ifindex; - } -} - -/* Delayed registration/unregisteration */ -static LIST_HEAD(net_todo_list); - -static void net_set_todo(struct net_device *dev) -{ - list_add_tail(&dev->todo_list, &net_todo_list); -} - -static void rollback_registered(struct net_device *dev) -{ - BUG_ON(dev_boot_phase); - ASSERT_RTNL(); - - /* Some devices call without registering for initialization unwind. */ - if (dev->reg_state == NETREG_UNINITIALIZED) { - printk(KERN_DEBUG "unregister_netdevice: device %s/%p never " - "was registered\n", dev->name, dev); - - WARN_ON(1); - return; - } - - BUG_ON(dev->reg_state != NETREG_REGISTERED); - - /* If device is running, close it first. */ - dev_close(dev); - - /* And unlink it from device chain. */ - unlist_netdevice(dev); - - dev->reg_state = NETREG_UNREGISTERING; - - synchronize_net(); - - /* Shutdown queueing discipline. */ - dev_shutdown(dev); - - - /* Notify protocols, that we are about to destroy - this device. They should clean all the things. - */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - - /* - * Flush the unicast and multicast chains - */ - dev_addr_discard(dev); - - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); - - /* Notifier chain MUST detach us from master device. */ - WARN_ON(dev->master); - - /* Remove entries from kobject tree */ - netdev_unregister_kobject(dev); - - synchronize_net(); - - dev_put(dev); -} - -static void __netdev_init_queue_locks_one(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_unused) -{ - spin_lock_init(&dev_queue->_xmit_lock); - netdev_set_xmit_lockdep_class(&dev_queue->_xmit_lock, dev->type); - dev_queue->xmit_lock_owner = -1; -} - -static void netdev_init_queue_locks(struct net_device *dev) -{ - netdev_for_each_tx_queue(dev, __netdev_init_queue_locks_one, NULL); - __netdev_init_queue_locks_one(dev, &dev->rx_queue, NULL); -} - -unsigned long netdev_fix_features(unsigned long features, const char *name) -{ - /* Fix illegal SG+CSUM combinations. */ - if ((features & NETIF_F_SG) && - !(features & NETIF_F_ALL_CSUM)) { - if (name) - printk(KERN_NOTICE "%s: Dropping NETIF_F_SG since no " - "checksum feature.\n", name); - features &= ~NETIF_F_SG; - } - - /* TSO requires that SG is present as well. */ - if ((features & NETIF_F_TSO) && !(features & NETIF_F_SG)) { - if (name) - printk(KERN_NOTICE "%s: Dropping NETIF_F_TSO since no " - "SG feature.\n", name); - features &= ~NETIF_F_TSO; - } - - if (features & NETIF_F_UFO) { - if (!(features & NETIF_F_GEN_CSUM)) { - if (name) - printk(KERN_ERR "%s: Dropping NETIF_F_UFO " - "since no NETIF_F_HW_CSUM feature.\n", - name); - features &= ~NETIF_F_UFO; - } - - if (!(features & NETIF_F_SG)) { - if (name) - printk(KERN_ERR "%s: Dropping NETIF_F_UFO " - "since no NETIF_F_SG feature.\n", name); - features &= ~NETIF_F_UFO; - } - } - - return features; -} -EXPORT_SYMBOL(netdev_fix_features); - -/* Some devices need to (re-)set their netdev_ops inside - * ->init() or similar. If that happens, we have to setup - * the compat pointers again. - */ -void netdev_resync_ops(struct net_device *dev) -{ -#ifdef CONFIG_COMPAT_NET_DEV_OPS - const struct net_device_ops *ops = dev->netdev_ops; - - dev->init = ops->ndo_init; - dev->uninit = ops->ndo_uninit; - dev->open = ops->ndo_open; - dev->change_rx_flags = ops->ndo_change_rx_flags; - dev->set_rx_mode = ops->ndo_set_rx_mode; - dev->set_multicast_list = ops->ndo_set_multicast_list; - dev->set_mac_address = ops->ndo_set_mac_address; - dev->validate_addr = ops->ndo_validate_addr; - dev->do_ioctl = ops->ndo_do_ioctl; - dev->set_config = ops->ndo_set_config; - dev->change_mtu = ops->ndo_change_mtu; - dev->neigh_setup = ops->ndo_neigh_setup; - dev->tx_timeout = ops->ndo_tx_timeout; - dev->get_stats = ops->ndo_get_stats; - dev->vlan_rx_register = ops->ndo_vlan_rx_register; - dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ops->ndo_poll_controller; -#endif -#endif -} -EXPORT_SYMBOL(netdev_resync_ops); - -/** - * register_netdevice - register a network device - * @dev: device to register - * - * Take a completed network device structure and add it to the kernel - * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier - * chain. 0 is returned on success. A negative errno code is returned - * on a failure to set up the device, or if the name is a duplicate. - * - * Callers must hold the rtnl semaphore. You may want - * register_netdev() instead of this. - * - * BUGS: - * The locking appears insufficient to guarantee two parallel registers - * will not get the same name. - */ - -int register_netdevice(struct net_device *dev) -{ - struct hlist_head *head; - struct hlist_node *p; - int ret; - struct net *net = dev_net(dev); - - BUG_ON(dev_boot_phase); - ASSERT_RTNL(); - - might_sleep(); - - /* When net_device's are persistent, this will be fatal. */ - BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); - BUG_ON(!net); - - spin_lock_init(&dev->addr_list_lock); - netdev_set_addr_lockdep_class(dev); - netdev_init_queue_locks(dev); - - dev->iflink = -1; - -#ifdef CONFIG_COMPAT_NET_DEV_OPS - /* Netdevice_ops API compatiability support. - * This is temporary until all network devices are converted. - */ - if (dev->netdev_ops) { - netdev_resync_ops(dev); - } else { - char drivername[64]; - pr_info("%s (%s): not using net_device_ops yet\n", - dev->name, netdev_drivername(dev, drivername, 64)); - - /* This works only because net_device_ops and the - compatiablity structure are the same. */ - dev->netdev_ops = (void *) &(dev->init); - } -#endif - - /* Init, if this function is available */ - if (dev->netdev_ops->ndo_init) { - ret = dev->netdev_ops->ndo_init(dev); - if (ret) { - if (ret > 0) - ret = -EIO; - goto out; - } - } - - if (!dev_valid_name(dev->name)) { - ret = -EINVAL; - goto err_uninit; - } - - dev->ifindex = dev_new_index(net); - if (dev->iflink == -1) - dev->iflink = dev->ifindex; - - /* Check for existence of name */ - head = dev_name_hash(net, dev->name); - hlist_for_each(p, head) { - struct net_device *d - = hlist_entry(p, struct net_device, name_hlist); - if (!strncmp(d->name, dev->name, IFNAMSIZ)) { - ret = -EEXIST; - goto err_uninit; - } - } - - /* Fix illegal checksum combinations */ - if ((dev->features & NETIF_F_HW_CSUM) && - (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { - printk(KERN_NOTICE "%s: mixed HW and IP checksum settings.\n", - dev->name); - dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); - } - - if ((dev->features & NETIF_F_NO_CSUM) && - (dev->features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { - printk(KERN_NOTICE "%s: mixed no checksumming and other settings.\n", - dev->name); - dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM); - } - - dev->features = netdev_fix_features(dev->features, dev->name); - - /* Enable software GSO if SG is supported. */ - if (dev->features & NETIF_F_SG) - dev->features |= NETIF_F_GSO; - - netdev_initialize_kobject(dev); - ret = netdev_register_kobject(dev); - if (ret) - goto err_uninit; - dev->reg_state = NETREG_REGISTERED; - - /* - * Default initial state at registry is that the - * device is present. - */ - - set_bit(__LINK_STATE_PRESENT, &dev->state); - - dev_init_scheduler(dev); - dev_hold(dev); - list_netdevice(dev); - - /* Notify protocols, that a new device appeared. */ - ret = call_netdevice_notifiers(NETDEV_REGISTER, dev); - ret = notifier_to_errno(ret); - if (ret) { - rollback_registered(dev); - dev->reg_state = NETREG_UNREGISTERED; - } - -out: - return ret; - -err_uninit: - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); - goto out; -} - -/** - * init_dummy_netdev - init a dummy network device for NAPI - * @dev: device to init - * - * This takes a network device structure and initialize the minimum - * amount of fields so it can be used to schedule NAPI polls without - * registering a full blown interface. This is to be used by drivers - * that need to tie several hardware interfaces to a single NAPI - * poll scheduler due to HW limitations. - */ -int init_dummy_netdev(struct net_device *dev) -{ - /* Clear everything. Note we don't initialize spinlocks - * are they aren't supposed to be taken by any of the - * NAPI code and this dummy netdev is supposed to be - * only ever used for NAPI polls - */ - memset(dev, 0, sizeof(struct net_device)); - - /* make sure we BUG if trying to hit standard - * register/unregister code path - */ - dev->reg_state = NETREG_DUMMY; - - /* initialize the ref count */ - atomic_set(&dev->refcnt, 1); - - /* NAPI wants this */ - INIT_LIST_HEAD(&dev->napi_list); - - /* a dummy interface is started by default */ - set_bit(__LINK_STATE_PRESENT, &dev->state); - set_bit(__LINK_STATE_START, &dev->state); - - return 0; -} -EXPORT_SYMBOL_GPL(init_dummy_netdev); - - -/** - * register_netdev - register a network device - * @dev: device to register - * - * Take a completed network device structure and add it to the kernel - * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier - * chain. 0 is returned on success. A negative errno code is returned - * on a failure to set up the device, or if the name is a duplicate. - * - * This is a wrapper around register_netdevice that takes the rtnl semaphore - * and expands the device name if you passed a format string to - * alloc_netdev. - */ -int register_netdev(struct net_device *dev) -{ - int err; - - rtnl_lock(); - - /* - * If the name is a format string the caller wants us to do a - * name allocation. - */ - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto out; - } - - err = register_netdevice(dev); -out: - rtnl_unlock(); - return err; -} -EXPORT_SYMBOL(register_netdev); - -/* - * netdev_wait_allrefs - wait until all references are gone. - * - * This is called when unregistering network devices. - * - * Any protocol or device that holds a reference should register - * for netdevice notification, and cleanup and put back the - * reference if they receive an UNREGISTER event. - * We can get stuck here if buggy protocols don't correctly - * call dev_put. - */ -static void netdev_wait_allrefs(struct net_device *dev) -{ - unsigned long rebroadcast_time, warning_time; - - rebroadcast_time = warning_time = jiffies; - while (atomic_read(&dev->refcnt) != 0) { - if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { - rtnl_lock(); - - /* Rebroadcast unregister notification */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - - if (test_bit(__LINK_STATE_LINKWATCH_PENDING, - &dev->state)) { - /* We must not have linkwatch events - * pending on unregister. If this - * happens, we simply run the queue - * unscheduled, resulting in a noop - * for this device. - */ - linkwatch_run_queue(); - } - - __rtnl_unlock(); - - rebroadcast_time = jiffies; - } - - msleep(250); - - if (time_after(jiffies, warning_time + 10 * HZ)) { - printk(KERN_EMERG "unregister_netdevice: " - "waiting for %s to become free. Usage " - "count = %d\n", - dev->name, atomic_read(&dev->refcnt)); - warning_time = jiffies; - } - } -} - -/* The sequence is: - * - * rtnl_lock(); - * ... - * register_netdevice(x1); - * register_netdevice(x2); - * ... - * unregister_netdevice(y1); - * unregister_netdevice(y2); - * ... - * rtnl_unlock(); - * free_netdev(y1); - * free_netdev(y2); - * - * We are invoked by rtnl_unlock(). - * This allows us to deal with problems: - * 1) We can delete sysfs objects which invoke hotplug - * without deadlocking with linkwatch via keventd. - * 2) Since we run with the RTNL semaphore not held, we can sleep - * safely in order to wait for the netdev refcnt to drop to zero. - * - * We must not return until all unregister events added during - * the interval the lock was held have been completed. - */ -void netdev_run_todo(void) -{ - struct list_head list; - - /* Snapshot list, allow later requests */ - list_replace_init(&net_todo_list, &list); - - __rtnl_unlock(); - - while (!list_empty(&list)) { - struct net_device *dev - = list_entry(list.next, struct net_device, todo_list); - list_del(&dev->todo_list); - - if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { - printk(KERN_ERR "network todo '%s' but state %d\n", - dev->name, dev->reg_state); - dump_stack(); - continue; - } - - dev->reg_state = NETREG_UNREGISTERED; - - on_each_cpu(flush_backlog, dev, 1); - - netdev_wait_allrefs(dev); - - /* paranoia */ - BUG_ON(atomic_read(&dev->refcnt)); - WARN_ON(dev->ip_ptr); - WARN_ON(dev->ip6_ptr); - WARN_ON(dev->dn_ptr); - - if (dev->destructor) - dev->destructor(dev); - - /* Free network device */ - kobject_put(&dev->dev.kobj); - } -} - -/** - * dev_get_stats - get network device statistics - * @dev: device to get statistics from - * - * Get network statistics from device. The device driver may provide - * its own method by setting dev->netdev_ops->get_stats; otherwise - * the internal statistics structure is used. - */ -const struct net_device_stats *dev_get_stats(struct net_device *dev) - { - const struct net_device_ops *ops = dev->netdev_ops; - - if (ops->ndo_get_stats) - return ops->ndo_get_stats(dev); - else - return &dev->stats; -} -EXPORT_SYMBOL(dev_get_stats); - -static void netdev_init_one_queue(struct net_device *dev, - struct netdev_queue *queue, - void *_unused) -{ - queue->dev = dev; -} - -static void netdev_init_queues(struct net_device *dev) -{ - netdev_init_one_queue(dev, &dev->rx_queue, NULL); - netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); - spin_lock_init(&dev->tx_global_lock); -} - -/** - * alloc_netdev_mq - allocate network device - * @sizeof_priv: size of private data to allocate space for - * @name: device name format string - * @setup: callback to initialize device - * @queue_count: the number of subqueues to allocate - * - * Allocates a struct net_device with private data area for driver use - * and performs basic initialization. Also allocates subquue structs - * for each queue on the device at the end of the netdevice. - */ -struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, - void (*setup)(struct net_device *), unsigned int queue_count) -{ - struct netdev_queue *tx; - struct net_device *dev; - size_t alloc_size; - void *p; - - BUG_ON(strlen(name) >= sizeof(dev->name)); - - alloc_size = sizeof(struct net_device); - if (sizeof_priv) { - /* ensure 32-byte alignment of private area */ - alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; - alloc_size += sizeof_priv; - } - /* ensure 32-byte alignment of whole construct */ - alloc_size += NETDEV_ALIGN_CONST; - - p = kzalloc(alloc_size, GFP_KERNEL); - if (!p) { - printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n"); - return NULL; - } - - tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL); - if (!tx) { - printk(KERN_ERR "alloc_netdev: Unable to allocate " - "tx qdiscs.\n"); - kfree(p); - return NULL; - } - - dev = (struct net_device *) - (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); - dev->padded = (char *)dev - (char *)p; - dev_net_set(dev, &init_net); - - dev->_tx = tx; - dev->num_tx_queues = queue_count; - dev->real_num_tx_queues = queue_count; - - dev->gso_max_size = GSO_MAX_SIZE; - - netdev_init_queues(dev); - - INIT_LIST_HEAD(&dev->napi_list); - setup(dev); - strcpy(dev->name, name); - return dev; -} -EXPORT_SYMBOL(alloc_netdev_mq); - -/** - * free_netdev - free network device - * @dev: device - * - * This function does the last stage of destroying an allocated device - * interface. The reference to the device object is released. - * If this is the last reference then it will be freed. - */ -void free_netdev(struct net_device *dev) -{ - struct napi_struct *p, *n; - - release_net(dev_net(dev)); - - kfree(dev->_tx); - - list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) - netif_napi_del(p); - - /* Compatibility with error handling in drivers */ - if (dev->reg_state == NETREG_UNINITIALIZED) { - kfree((char *)dev - dev->padded); - return; - } - - BUG_ON(dev->reg_state != NETREG_UNREGISTERED); - dev->reg_state = NETREG_RELEASED; - - /* will free via device release */ - put_device(&dev->dev); -} - -/** - * synchronize_net - Synchronize with packet receive processing - * - * Wait for packets currently being received to be done. - * Does not block later packets from starting. - */ -void synchronize_net(void) -{ - might_sleep(); - synchronize_rcu(); -} - -/** - * unregister_netdevice - remove device from the kernel - * @dev: device - * - * This function shuts down a device interface and removes it - * from the kernel tables. - * - * Callers must hold the rtnl semaphore. You may want - * unregister_netdev() instead of this. - */ - -void unregister_netdevice(struct net_device *dev) -{ - ASSERT_RTNL(); - - rollback_registered(dev); - /* Finish processing unregister after unlock */ - net_set_todo(dev); -} - -/** - * unregister_netdev - remove device from the kernel - * @dev: device - * - * This function shuts down a device interface and removes it - * from the kernel tables. - * - * This is just a wrapper for unregister_netdevice that takes - * the rtnl semaphore. In general you want to use this and not - * unregister_netdevice. - */ -void unregister_netdev(struct net_device *dev) -{ - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); -} - -EXPORT_SYMBOL(unregister_netdev); - -/** - * dev_change_net_namespace - move device to different nethost namespace - * @dev: device - * @net: network namespace - * @pat: If not NULL name pattern to try if the current device name - * is already taken in the destination network namespace. - * - * This function shuts down a device interface and moves it - * to a new network namespace. On success 0 is returned, on - * a failure a netagive errno code is returned. - * - * Callers must hold the rtnl semaphore. - */ - -int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) -{ - char buf[IFNAMSIZ]; - const char *destname; - int err; - - ASSERT_RTNL(); - - /* Don't allow namespace local devices to be moved. */ - err = -EINVAL; - if (dev->features & NETIF_F_NETNS_LOCAL) - goto out; - -#ifdef CONFIG_SYSFS - /* Don't allow real devices to be moved when sysfs - * is enabled. - */ - err = -EINVAL; - if (dev->dev.parent) - goto out; -#endif - - /* Ensure the device has been registrered */ - err = -EINVAL; - if (dev->reg_state != NETREG_REGISTERED) - goto out; - - /* Get out if there is nothing todo */ - err = 0; - if (net_eq(dev_net(dev), net)) - goto out; - - /* Pick the destination device name, and ensure - * we can use it in the destination network namespace. - */ - err = -EEXIST; - destname = dev->name; - if (__dev_get_by_name(net, destname)) { - /* We get here if we can't use the current device name */ - if (!pat) - goto out; - if (!dev_valid_name(pat)) - goto out; - if (strchr(pat, '%')) { - if (__dev_alloc_name(net, pat, buf) < 0) - goto out; - destname = buf; - } else - destname = pat; - if (__dev_get_by_name(net, destname)) - goto out; - } - - /* - * And now a mini version of register_netdevice unregister_netdevice. - */ - - /* If device is running close it first. */ - dev_close(dev); - - /* And unlink it from device chain */ - err = -ENODEV; - unlist_netdevice(dev); - - synchronize_net(); - - /* Shutdown queueing discipline. */ - dev_shutdown(dev); - - /* Notify protocols, that we are about to destroy - this device. They should clean all the things. - */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - - /* - * Flush the unicast and multicast chains - */ - dev_addr_discard(dev); - - netdev_unregister_kobject(dev); - - /* Actually switch the network namespace */ - dev_net_set(dev, net); - - /* Assign the new device name */ - if (destname != dev->name) - strcpy(dev->name, destname); - - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { - int iflink = (dev->iflink == dev->ifindex); - dev->ifindex = dev_new_index(net); - if (iflink) - dev->iflink = dev->ifindex; - } - - /* Fixup kobjects */ - err = netdev_register_kobject(dev); - WARN_ON(err); - - /* Add the device back in the hashes */ - list_netdevice(dev); - - /* Notify protocols, that a new device appeared. */ - call_netdevice_notifiers(NETDEV_REGISTER, dev); - - synchronize_net(); - err = 0; -out: - return err; -} - -static int dev_cpu_callback(struct notifier_block *nfb, - unsigned long action, - void *ocpu) -{ - struct sk_buff **list_skb; - struct Qdisc **list_net; - struct sk_buff *skb; - unsigned int cpu, oldcpu = (unsigned long)ocpu; - struct softnet_data *sd, *oldsd; - - if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) - return NOTIFY_OK; - - local_irq_disable(); - cpu = smp_processor_id(); - sd = &per_cpu(softnet_data, cpu); - oldsd = &per_cpu(softnet_data, oldcpu); - - /* Find end of our completion_queue. */ - list_skb = &sd->completion_queue; - while (*list_skb) - list_skb = &(*list_skb)->next; - /* Append completion queue from offline CPU. */ - *list_skb = oldsd->completion_queue; - oldsd->completion_queue = NULL; - - /* Find end of our output_queue. */ - list_net = &sd->output_queue; - while (*list_net) - list_net = &(*list_net)->next_sched; - /* Append output queue from offline CPU. */ - *list_net = oldsd->output_queue; - oldsd->output_queue = NULL; - - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_enable(); - - /* Process offline CPU's input_pkt_queue */ - while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) - netif_rx(skb); - - return NOTIFY_OK; -} - - -/** - * netdev_increment_features - increment feature set by one - * @all: current feature set - * @one: new feature set - * @mask: mask feature set - * - * Computes a new feature set after adding a device with feature set - * @one to the master device with current feature set @all. Will not - * enable anything that is off in @mask. Returns the new feature set. - */ -unsigned long netdev_increment_features(unsigned long all, unsigned long one, - unsigned long mask) -{ - /* If device needs checksumming, downgrade to it. */ - if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) - all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM); - else if (mask & NETIF_F_ALL_CSUM) { - /* If one device supports v4/v6 checksumming, set for all. */ - if (one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) && - !(all & NETIF_F_GEN_CSUM)) { - all &= ~NETIF_F_ALL_CSUM; - all |= one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - } - - /* If one device supports hw checksumming, set for all. */ - if (one & NETIF_F_GEN_CSUM && !(all & NETIF_F_GEN_CSUM)) { - all &= ~NETIF_F_ALL_CSUM; - all |= NETIF_F_HW_CSUM; - } - } - - one |= NETIF_F_ALL_CSUM; - - one |= all & NETIF_F_ONE_FOR_ALL; - all &= one | NETIF_F_LLTX | NETIF_F_GSO; - all |= one & mask & NETIF_F_ONE_FOR_ALL; - - return all; -} -EXPORT_SYMBOL(netdev_increment_features); - -static struct hlist_head *netdev_create_hash(void) -{ - int i; - struct hlist_head *hash; - - hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL); - if (hash != NULL) - for (i = 0; i < NETDEV_HASHENTRIES; i++) - INIT_HLIST_HEAD(&hash[i]); - - return hash; -} - -/* Initialize per network namespace state */ -static int __net_init netdev_init(struct net *net) -{ - INIT_LIST_HEAD(&net->dev_base_head); - - net->dev_name_head = netdev_create_hash(); - if (net->dev_name_head == NULL) - goto err_name; - - net->dev_index_head = netdev_create_hash(); - if (net->dev_index_head == NULL) - goto err_idx; - - return 0; - -err_idx: - kfree(net->dev_name_head); -err_name: - return -ENOMEM; -} - -/** - * netdev_drivername - network driver for the device - * @dev: network device - * @buffer: buffer for resulting name - * @len: size of buffer - * - * Determine network driver for device. - */ -char *netdev_drivername(const struct net_device *dev, char *buffer, int len) -{ - const struct device_driver *driver; - const struct device *parent; - - if (len <= 0 || !buffer) - return buffer; - buffer[0] = 0; - - parent = dev->dev.parent; - - if (!parent) - return buffer; - - driver = parent->driver; - if (driver && driver->name) - strlcpy(buffer, driver->name, len); - return buffer; -} - -static void __net_exit netdev_exit(struct net *net) -{ - kfree(net->dev_name_head); - kfree(net->dev_index_head); -} - -static struct pernet_operations __net_initdata netdev_net_ops = { - .init = netdev_init, - .exit = netdev_exit, -}; - -static void __net_exit default_device_exit(struct net *net) -{ - struct net_device *dev; - /* - * Push all migratable of the network devices back to the - * initial network namespace - */ - rtnl_lock(); -restart: - for_each_netdev(net, dev) { - int err; - char fb_name[IFNAMSIZ]; - - /* Ignore unmoveable devices (i.e. loopback) */ - if (dev->features & NETIF_F_NETNS_LOCAL) - continue; - - /* Delete virtual devices */ - if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) { - dev->rtnl_link_ops->dellink(dev); - goto restart; - } - - /* Push remaing network devices to init_net */ - snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); - err = dev_change_net_namespace(dev, &init_net, fb_name); - if (err) { - printk(KERN_EMERG "%s: failed to move %s to init_net: %d\n", - __func__, dev->name, err); - BUG(); - } - goto restart; - } - rtnl_unlock(); -} - -static struct pernet_operations __net_initdata default_device_ops = { - .exit = default_device_exit, -}; - -/* - * Initialize the DEV module. At boot time this walks the device list and - * unhooks any devices that fail to initialise (normally hardware not - * present) and leaves us with a valid list of present and active devices. - * - */ - -/* - * This is called single threaded during boot, so no need - * to take the rtnl semaphore. - */ -static int __init net_dev_init(void) -{ - int i, rc = -ENOMEM; - - BUG_ON(!dev_boot_phase); - - if (dev_proc_init()) - goto out; - - if (netdev_kobject_init()) - goto out; - - INIT_LIST_HEAD(&ptype_all); - for (i = 0; i < PTYPE_HASH_SIZE; i++) - INIT_LIST_HEAD(&ptype_base[i]); - - if (register_pernet_subsys(&netdev_net_ops)) - goto out; - - /* - * Initialise the packet receive queues. - */ - - for_each_possible_cpu(i) { - struct softnet_data *queue; - - queue = &per_cpu(softnet_data, i); - skb_queue_head_init(&queue->input_pkt_queue); - queue->completion_queue = NULL; - INIT_LIST_HEAD(&queue->poll_list); - - queue->backlog.poll = process_backlog; - queue->backlog.weight = weight_p; - queue->backlog.gro_list = NULL; - } - - dev_boot_phase = 0; - - /* The loopback device is special if any other network devices - * is present in a network namespace the loopback device must - * be present. Since we now dynamically allocate and free the - * loopback device ensure this invariant is maintained by - * keeping the loopback device as the first device on the - * list of network devices. Ensuring the loopback devices - * is the first device that appears and the last network device - * that disappears. - */ - if (register_pernet_device(&loopback_net_ops)) - goto out; - - if (register_pernet_device(&default_device_ops)) - goto out; - - open_softirq(NET_TX_SOFTIRQ, net_tx_action); - open_softirq(NET_RX_SOFTIRQ, net_rx_action); - - hotcpu_notifier(dev_cpu_callback, 0); - dst_init(); - dev_mcast_init(); - rc = 0; -out: - return rc; -} - -subsys_initcall(net_dev_init); - -EXPORT_SYMBOL(__dev_get_by_index); -EXPORT_SYMBOL(__dev_get_by_name); -EXPORT_SYMBOL(__dev_remove_pack); -EXPORT_SYMBOL(dev_valid_name); -EXPORT_SYMBOL(dev_add_pack); -EXPORT_SYMBOL(dev_alloc_name); -EXPORT_SYMBOL(dev_close); -EXPORT_SYMBOL(dev_get_by_flags); -EXPORT_SYMBOL(dev_get_by_index); -EXPORT_SYMBOL(dev_get_by_name); -EXPORT_SYMBOL(dev_open); -EXPORT_SYMBOL(dev_queue_xmit); -EXPORT_SYMBOL(dev_remove_pack); -EXPORT_SYMBOL(dev_set_allmulti); -EXPORT_SYMBOL(dev_set_promiscuity); -EXPORT_SYMBOL(dev_change_flags); -EXPORT_SYMBOL(dev_set_mtu); -EXPORT_SYMBOL(dev_set_mac_address); -EXPORT_SYMBOL(free_netdev); -EXPORT_SYMBOL(netdev_boot_setup_check); -EXPORT_SYMBOL(netdev_set_master); -EXPORT_SYMBOL(netdev_state_change); -EXPORT_SYMBOL(netif_receive_skb); -EXPORT_SYMBOL(netif_rx); -EXPORT_SYMBOL(register_gifconf); -EXPORT_SYMBOL(register_netdevice); -EXPORT_SYMBOL(register_netdevice_notifier); -EXPORT_SYMBOL(skb_checksum_help); -EXPORT_SYMBOL(synchronize_net); -EXPORT_SYMBOL(unregister_netdevice); -EXPORT_SYMBOL(unregister_netdevice_notifier); -EXPORT_SYMBOL(net_enable_timestamp); -EXPORT_SYMBOL(net_disable_timestamp); -EXPORT_SYMBOL(dev_get_flags); - -#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -EXPORT_SYMBOL(br_handle_frame_hook); -EXPORT_SYMBOL(br_fdb_get_hook); -EXPORT_SYMBOL(br_fdb_put_hook); -#endif - -EXPORT_SYMBOL(dev_load); - -EXPORT_PER_CPU_SYMBOL(softnet_data); diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/dev_mcast.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/dev_mcast.c.svn-base deleted file mode 100644 index 9e2fa39f..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/dev_mcast.c.svn-base +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Linux NET3: Multicast List maintenance. - * - * Authors: - * Tim Kordas <tjk@nostromo.eeap.cwru.edu> - * Richard Underwood <richard@wuzz.demon.co.uk> - * - * Stir fried together from the IP multicast and CAP patches above - * Alan Cox <alan@lxorguk.ukuu.org.uk> - * - * Fixes: - * Alan Cox : Update the device on a real delete - * rather than any time but... - * Alan Cox : IFF_ALLMULTI support. - * Alan Cox : New format set_multicast_list() calls. - * Gleb Natapov : Remove dev_mc_lock. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/module.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <linux/bitops.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/socket.h> -#include <linux/sockios.h> -#include <linux/in.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/if_ether.h> -#include <linux/inet.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/init.h> -#include <net/net_namespace.h> -#include <net/ip.h> -#include <net/route.h> -#include <linux/skbuff.h> -#include <net/sock.h> -#include <net/arp.h> - - -/* - * Device multicast list maintenance. - * - * This is used both by IP and by the user level maintenance functions. - * Unlike BSD we maintain a usage count on a given multicast address so - * that a casual user application can add/delete multicasts used by - * protocols without doing damage to the protocols when it deletes the - * entries. It also helps IP as it tracks overlapping maps. - * - * Device mc lists are changed by bh at least if IPv6 is enabled, - * so that it must be bh protected. - * - * We block accesses to device mc filters with netif_tx_lock. - */ - -/* - * Delete a device level multicast - */ - -int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl) -{ - int err; - - netif_addr_lock_bh(dev); - err = __dev_addr_delete(&dev->mc_list, &dev->mc_count, - addr, alen, glbl); - if (!err) { - /* - * We have altered the list, so the card - * loaded filter is now wrong. Fix it - */ - - __dev_set_rx_mode(dev); - } - netif_addr_unlock_bh(dev); - return err; -} - -/* - * Add a device level multicast - */ - -int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) -{ - int err; - - netif_addr_lock_bh(dev); - err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} - -/** - * dev_mc_sync - Synchronize device's multicast list to another device - * @to: destination device - * @from: source device - * - * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_tx_lock_bh. - * - * This function is intended to be called from the dev->set_multicast_list - * or dev->set_rx_mode function of layered software devices. - */ -int dev_mc_sync(struct net_device *to, struct net_device *from) -{ - int err = 0; - - netif_addr_lock_bh(to); - err = __dev_addr_sync(&to->mc_list, &to->mc_count, - &from->mc_list, &from->mc_count); - if (!err) - __dev_set_rx_mode(to); - netif_addr_unlock_bh(to); - - return err; -} -EXPORT_SYMBOL(dev_mc_sync); - - -/** - * dev_mc_unsync - Remove synchronized addresses from the destination - * device - * @to: destination device - * @from: source device - * - * Remove all addresses that were added to the destination device by - * dev_mc_sync(). This function is intended to be called from the - * dev->stop function of layered software devices. - */ -void dev_mc_unsync(struct net_device *to, struct net_device *from) -{ - netif_addr_lock_bh(from); - netif_addr_lock(to); - - __dev_addr_unsync(&to->mc_list, &to->mc_count, - &from->mc_list, &from->mc_count); - __dev_set_rx_mode(to); - - netif_addr_unlock(to); - netif_addr_unlock_bh(from); -} -EXPORT_SYMBOL(dev_mc_unsync); - -#ifdef CONFIG_PROC_FS -static int dev_mc_seq_show(struct seq_file *seq, void *v) -{ - struct dev_addr_list *m; - struct net_device *dev = v; - - if (v == SEQ_START_TOKEN) - return 0; - - netif_addr_lock_bh(dev); - for (m = dev->mc_list; m; m = m->next) { - int i; - - seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex, - dev->name, m->dmi_users, m->dmi_gusers); - - for (i = 0; i < m->dmi_addrlen; i++) - seq_printf(seq, "%02x", m->dmi_addr[i]); - - seq_putc(seq, '\n'); - } - netif_addr_unlock_bh(dev); - return 0; -} - -static const struct seq_operations dev_mc_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = dev_mc_seq_show, -}; - -static int dev_mc_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &dev_mc_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations dev_mc_seq_fops = { - .owner = THIS_MODULE, - .open = dev_mc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -#endif - -static int __net_init dev_mc_net_init(struct net *net) -{ - if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops)) - return -ENOMEM; - return 0; -} - -static void __net_exit dev_mc_net_exit(struct net *net) -{ - proc_net_remove(net, "dev_mcast"); -} - -static struct pernet_operations __net_initdata dev_mc_net_ops = { - .init = dev_mc_net_init, - .exit = dev_mc_net_exit, -}; - -void __init dev_mcast_init(void) -{ - register_pernet_subsys(&dev_mc_net_ops); -} - -EXPORT_SYMBOL(dev_mc_add); -EXPORT_SYMBOL(dev_mc_delete); diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/ethtool.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/ethtool.c.svn-base deleted file mode 100644 index 947710a3..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/ethtool.c.svn-base +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * net/core/ethtool.c - Ethtool ioctl handler - * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx> - * - * This file is where we call all the ethtool_ops commands to get - * the information ethtool needs. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/capability.h> -#include <linux/errno.h> -#include <linux/ethtool.h> -#include <linux/netdevice.h> -#include <asm/uaccess.h> - -/* - * Some useful ethtool_ops methods that're device independent. - * If we find that all drivers want to do the same thing here, - * we can turn these into dev_() function calls. - */ - -u32 ethtool_op_get_link(struct net_device *dev) -{ - return netif_carrier_ok(dev) ? 1 : 0; -} - -u32 ethtool_op_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_ALL_CSUM) != 0; -} - -int ethtool_op_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - return 0; -} - -int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_HW_CSUM; - else - dev->features &= ~NETIF_F_HW_CSUM; - - return 0; -} - -int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - else - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - - return 0; -} - -u32 ethtool_op_get_sg(struct net_device *dev) -{ - return (dev->features & NETIF_F_SG) != 0; -} - -int ethtool_op_set_sg(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_SG; - else - dev->features &= ~NETIF_F_SG; - - return 0; -} - -u32 ethtool_op_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -int ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_TSO; - else - dev->features &= ~NETIF_F_TSO; - - return 0; -} - -u32 ethtool_op_get_ufo(struct net_device *dev) -{ - return (dev->features & NETIF_F_UFO) != 0; -} - -int ethtool_op_set_ufo(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_UFO; - else - dev->features &= ~NETIF_F_UFO; - return 0; -} - -/* the following list of flags are the same as their associated - * NETIF_F_xxx values in include/linux/netdevice.h - */ -static const u32 flags_dup_features = - ETH_FLAG_LRO; - -u32 ethtool_op_get_flags(struct net_device *dev) -{ - /* in the future, this function will probably contain additional - * handling for flags which are not so easily handled - * by a simple masking operation - */ - - return dev->features & flags_dup_features; -} - -int ethtool_op_set_flags(struct net_device *dev, u32 data) -{ - if (data & ETH_FLAG_LRO) - dev->features |= NETIF_F_LRO; - else - dev->features &= ~NETIF_F_LRO; - - return 0; -} - -/* Handlers for each ethtool command */ - -static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - int err; - - if (!dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return err; - - if (copy_to_user(useraddr, &cmd, sizeof(cmd))) - return -EFAULT; - return 0; -} - -static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_cmd cmd; - - if (!dev->ethtool_ops->set_settings) - return -EOPNOTSUPP; - - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; - - return dev->ethtool_ops->set_settings(dev, &cmd); -} - -static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_drvinfo info; - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (!ops->get_drvinfo) - return -EOPNOTSUPP; - - memset(&info, 0, sizeof(info)); - info.cmd = ETHTOOL_GDRVINFO; - ops->get_drvinfo(dev, &info); - - if (ops->get_sset_count) { - int rc; - - rc = ops->get_sset_count(dev, ETH_SS_TEST); - if (rc >= 0) - info.testinfo_len = rc; - rc = ops->get_sset_count(dev, ETH_SS_STATS); - if (rc >= 0) - info.n_stats = rc; - rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS); - if (rc >= 0) - info.n_priv_flags = rc; - } else { - /* code path for obsolete hooks */ - - if (ops->self_test_count) - info.testinfo_len = ops->self_test_count(dev); - if (ops->get_stats_count) - info.n_stats = ops->get_stats_count(dev); - } - if (ops->get_regs_len) - info.regdump_len = ops->get_regs_len(dev); - if (ops->get_eeprom_len) - info.eedump_len = ops->get_eeprom_len(dev); - - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int ethtool_set_rxhash(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_rxnfc cmd; - - if (!dev->ethtool_ops->set_rxhash) - return -EOPNOTSUPP; - - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; - - return dev->ethtool_ops->set_rxhash(dev, &cmd); -} - -static int ethtool_get_rxhash(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_rxnfc info; - - if (!dev->ethtool_ops->get_rxhash) - return -EOPNOTSUPP; - - if (copy_from_user(&info, useraddr, sizeof(info))) - return -EFAULT; - - dev->ethtool_ops->get_rxhash(dev, &info); - - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_regs regs; - const struct ethtool_ops *ops = dev->ethtool_ops; - void *regbuf; - int reglen, ret; - - if (!ops->get_regs || !ops->get_regs_len) - return -EOPNOTSUPP; - - if (copy_from_user(®s, useraddr, sizeof(regs))) - return -EFAULT; - - reglen = ops->get_regs_len(dev); - if (regs.len > reglen) - regs.len = reglen; - - regbuf = kmalloc(reglen, GFP_USER); - if (!regbuf) - return -ENOMEM; - - ops->get_regs(dev, ®s, regbuf); - - ret = -EFAULT; - if (copy_to_user(useraddr, ®s, sizeof(regs))) - goto out; - useraddr += offsetof(struct ethtool_regs, data); - if (copy_to_user(useraddr, regbuf, regs.len)) - goto out; - ret = 0; - - out: - kfree(regbuf); - return ret; -} - -static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; - - if (!dev->ethtool_ops->get_wol) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_wol(dev, &wol); - - if (copy_to_user(useraddr, &wol, sizeof(wol))) - return -EFAULT; - return 0; -} - -static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_wolinfo wol; - - if (!dev->ethtool_ops->set_wol) - return -EOPNOTSUPP; - - if (copy_from_user(&wol, useraddr, sizeof(wol))) - return -EFAULT; - - return dev->ethtool_ops->set_wol(dev, &wol); -} - -static int ethtool_nway_reset(struct net_device *dev) -{ - if (!dev->ethtool_ops->nway_reset) - return -EOPNOTSUPP; - - return dev->ethtool_ops->nway_reset(dev); -} - -static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_eeprom eeprom; - const struct ethtool_ops *ops = dev->ethtool_ops; - void __user *userbuf = useraddr + sizeof(eeprom); - u32 bytes_remaining; - u8 *data; - int ret = 0; - - if (!ops->get_eeprom || !ops->get_eeprom_len) - return -EOPNOTSUPP; - - if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) - return -EFAULT; - - /* Check for wrap and zero */ - if (eeprom.offset + eeprom.len <= eeprom.offset) - return -EINVAL; - - /* Check for exceeding total eeprom len */ - if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) - return -EINVAL; - - data = kmalloc(PAGE_SIZE, GFP_USER); - if (!data) - return -ENOMEM; - - bytes_remaining = eeprom.len; - while (bytes_remaining > 0) { - eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE); - - ret = ops->get_eeprom(dev, &eeprom, data); - if (ret) - break; - if (copy_to_user(userbuf, data, eeprom.len)) { - ret = -EFAULT; - break; - } - userbuf += eeprom.len; - eeprom.offset += eeprom.len; - bytes_remaining -= eeprom.len; - } - - eeprom.len = userbuf - (useraddr + sizeof(eeprom)); - eeprom.offset -= eeprom.len; - if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) - ret = -EFAULT; - - kfree(data); - return ret; -} - -static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_eeprom eeprom; - const struct ethtool_ops *ops = dev->ethtool_ops; - void __user *userbuf = useraddr + sizeof(eeprom); - u32 bytes_remaining; - u8 *data; - int ret = 0; - - if (!ops->set_eeprom || !ops->get_eeprom_len) - return -EOPNOTSUPP; - - if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) - return -EFAULT; - - /* Check for wrap and zero */ - if (eeprom.offset + eeprom.len <= eeprom.offset) - return -EINVAL; - - /* Check for exceeding total eeprom len */ - if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) - return -EINVAL; - - data = kmalloc(PAGE_SIZE, GFP_USER); - if (!data) - return -ENOMEM; - - bytes_remaining = eeprom.len; - while (bytes_remaining > 0) { - eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE); - - if (copy_from_user(data, userbuf, eeprom.len)) { - ret = -EFAULT; - break; - } - ret = ops->set_eeprom(dev, &eeprom, data); - if (ret) - break; - userbuf += eeprom.len; - eeprom.offset += eeprom.len; - bytes_remaining -= eeprom.len; - } - - kfree(data); - return ret; -} - -static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; - - if (!dev->ethtool_ops->get_coalesce) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_coalesce(dev, &coalesce); - - if (copy_to_user(useraddr, &coalesce, sizeof(coalesce))) - return -EFAULT; - return 0; -} - -static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_coalesce coalesce; - - if (!dev->ethtool_ops->set_coalesce) - return -EOPNOTSUPP; - - if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) - return -EFAULT; - - return dev->ethtool_ops->set_coalesce(dev, &coalesce); -} - -static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; - - if (!dev->ethtool_ops->get_ringparam) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_ringparam(dev, &ringparam); - - if (copy_to_user(useraddr, &ringparam, sizeof(ringparam))) - return -EFAULT; - return 0; -} - -static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_ringparam ringparam; - - if (!dev->ethtool_ops->set_ringparam) - return -EOPNOTSUPP; - - if (copy_from_user(&ringparam, useraddr, sizeof(ringparam))) - return -EFAULT; - - return dev->ethtool_ops->set_ringparam(dev, &ringparam); -} - -static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; - - if (!dev->ethtool_ops->get_pauseparam) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_pauseparam(dev, &pauseparam); - - if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam))) - return -EFAULT; - return 0; -} - -static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_pauseparam pauseparam; - - if (!dev->ethtool_ops->set_pauseparam) - return -EOPNOTSUPP; - - if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam))) - return -EFAULT; - - return dev->ethtool_ops->set_pauseparam(dev, &pauseparam); -} - -static int __ethtool_set_sg(struct net_device *dev, u32 data) -{ - int err; - - if (!data && dev->ethtool_ops->set_tso) { - err = dev->ethtool_ops->set_tso(dev, 0); - if (err) - return err; - } - - if (!data && dev->ethtool_ops->set_ufo) { - err = dev->ethtool_ops->set_ufo(dev, 0); - if (err) - return err; - } - return dev->ethtool_ops->set_sg(dev, data); -} - -static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - int err; - - if (!dev->ethtool_ops->set_tx_csum) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - if (!edata.data && dev->ethtool_ops->set_sg) { - err = __ethtool_set_sg(dev, 0); - if (err) - return err; - } - - return dev->ethtool_ops->set_tx_csum(dev, edata.data); -} - -static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (!dev->ethtool_ops->set_rx_csum) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - if (!edata.data && dev->ethtool_ops->set_sg) - dev->features &= ~NETIF_F_GRO; - - return dev->ethtool_ops->set_rx_csum(dev, edata.data); -} - -static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (!dev->ethtool_ops->set_sg) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - if (edata.data && - !(dev->features & NETIF_F_ALL_CSUM)) - return -EINVAL; - - return __ethtool_set_sg(dev, edata.data); -} - -static int ethtool_set_tso(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (!dev->ethtool_ops->set_tso) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - if (edata.data && !(dev->features & NETIF_F_SG)) - return -EINVAL; - - return dev->ethtool_ops->set_tso(dev, edata.data); -} - -static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (!dev->ethtool_ops->set_ufo) - return -EOPNOTSUPP; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - if (edata.data && !(dev->features & NETIF_F_SG)) - return -EINVAL; - if (edata.data && !(dev->features & NETIF_F_HW_CSUM)) - return -EINVAL; - return dev->ethtool_ops->set_ufo(dev, edata.data); -} - -static int ethtool_get_gso(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GGSO }; - - edata.data = dev->features & NETIF_F_GSO; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_gso(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - if (edata.data) - dev->features |= NETIF_F_GSO; - else - dev->features &= ~NETIF_F_GSO; - return 0; -} - -static int ethtool_get_gro(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { ETHTOOL_GGRO }; - - edata.data = dev->features & NETIF_F_GRO; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_gro(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - if (edata.data) { - if (!dev->ethtool_ops->get_rx_csum || - !dev->ethtool_ops->get_rx_csum(dev)) - return -EINVAL; - dev->features |= NETIF_F_GRO; - } else - dev->features &= ~NETIF_F_GRO; - - return 0; -} - -static int ethtool_self_test(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_test test; - const struct ethtool_ops *ops = dev->ethtool_ops; - u64 *data; - int ret, test_len; - - if (!ops->self_test) - return -EOPNOTSUPP; - if (!ops->get_sset_count && !ops->self_test_count) - return -EOPNOTSUPP; - - if (ops->get_sset_count) - test_len = ops->get_sset_count(dev, ETH_SS_TEST); - else - /* code path for obsolete hook */ - test_len = ops->self_test_count(dev); - if (test_len < 0) - return test_len; - WARN_ON(test_len == 0); - - if (copy_from_user(&test, useraddr, sizeof(test))) - return -EFAULT; - - test.len = test_len; - data = kmalloc(test_len * sizeof(u64), GFP_USER); - if (!data) - return -ENOMEM; - - ops->self_test(dev, &test, data); - - ret = -EFAULT; - if (copy_to_user(useraddr, &test, sizeof(test))) - goto out; - useraddr += sizeof(test); - if (copy_to_user(useraddr, data, test.len * sizeof(u64))) - goto out; - ret = 0; - - out: - kfree(data); - return ret; -} - -static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_gstrings gstrings; - const struct ethtool_ops *ops = dev->ethtool_ops; - u8 *data; - int ret; - - if (!ops->get_strings) - return -EOPNOTSUPP; - - if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) - return -EFAULT; - - if (ops->get_sset_count) { - ret = ops->get_sset_count(dev, gstrings.string_set); - if (ret < 0) - return ret; - - gstrings.len = ret; - } else { - /* code path for obsolete hooks */ - - switch (gstrings.string_set) { - case ETH_SS_TEST: - if (!ops->self_test_count) - return -EOPNOTSUPP; - gstrings.len = ops->self_test_count(dev); - break; - case ETH_SS_STATS: - if (!ops->get_stats_count) - return -EOPNOTSUPP; - gstrings.len = ops->get_stats_count(dev); - break; - default: - return -EINVAL; - } - } - - data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); - if (!data) - return -ENOMEM; - - ops->get_strings(dev, gstrings.string_set, data); - - ret = -EFAULT; - if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) - goto out; - useraddr += sizeof(gstrings); - if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) - goto out; - ret = 0; - - out: - kfree(data); - return ret; -} - -static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_value id; - - if (!dev->ethtool_ops->phys_id) - return -EOPNOTSUPP; - - if (copy_from_user(&id, useraddr, sizeof(id))) - return -EFAULT; - - return dev->ethtool_ops->phys_id(dev, id.data); -} - -static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_stats stats; - const struct ethtool_ops *ops = dev->ethtool_ops; - u64 *data; - int ret, n_stats; - - if (!ops->get_ethtool_stats) - return -EOPNOTSUPP; - if (!ops->get_sset_count && !ops->get_stats_count) - return -EOPNOTSUPP; - - if (ops->get_sset_count) - n_stats = ops->get_sset_count(dev, ETH_SS_STATS); - else - /* code path for obsolete hook */ - n_stats = ops->get_stats_count(dev); - if (n_stats < 0) - return n_stats; - WARN_ON(n_stats == 0); - - if (copy_from_user(&stats, useraddr, sizeof(stats))) - return -EFAULT; - - stats.n_stats = n_stats; - data = kmalloc(n_stats * sizeof(u64), GFP_USER); - if (!data) - return -ENOMEM; - - ops->get_ethtool_stats(dev, &stats, data); - - ret = -EFAULT; - if (copy_to_user(useraddr, &stats, sizeof(stats))) - goto out; - useraddr += sizeof(stats); - if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) - goto out; - ret = 0; - - out: - kfree(data); - return ret; -} - -static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_perm_addr epaddr; - - if (copy_from_user(&epaddr, useraddr, sizeof(epaddr))) - return -EFAULT; - - if (epaddr.size < dev->addr_len) - return -ETOOSMALL; - epaddr.size = dev->addr_len; - - if (copy_to_user(useraddr, &epaddr, sizeof(epaddr))) - return -EFAULT; - useraddr += sizeof(epaddr); - if (copy_to_user(useraddr, dev->perm_addr, epaddr.size)) - return -EFAULT; - return 0; -} - -static int ethtool_get_value(struct net_device *dev, char __user *useraddr, - u32 cmd, u32 (*actor)(struct net_device *)) -{ - struct ethtool_value edata = { cmd }; - - if (!actor) - return -EOPNOTSUPP; - - edata.data = actor(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr, - void (*actor)(struct net_device *, u32)) -{ - struct ethtool_value edata; - - if (!actor) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - actor(dev, edata.data); - return 0; -} - -static int ethtool_set_value(struct net_device *dev, char __user *useraddr, - int (*actor)(struct net_device *, u32)) -{ - struct ethtool_value edata; - - if (!actor) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - return actor(dev, edata.data); -} - -/* The main entry point in this file. Called from net/core/dev.c */ - -int dev_ethtool(struct net *net, struct ifreq *ifr) -{ - struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); - void __user *useraddr = ifr->ifr_data; - u32 ethcmd; - int rc; - unsigned long old_features; - - if (!dev || !netif_device_present(dev)) - return -ENODEV; - - if (!dev->ethtool_ops) - return -EOPNOTSUPP; - - if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) - return -EFAULT; - - /* Allow some commands to be done by anyone */ - switch(ethcmd) { - case ETHTOOL_GDRVINFO: - case ETHTOOL_GMSGLVL: - case ETHTOOL_GCOALESCE: - case ETHTOOL_GRINGPARAM: - case ETHTOOL_GPAUSEPARAM: - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - case ETHTOOL_GSG: - case ETHTOOL_GSTRINGS: - case ETHTOOL_GTSO: - case ETHTOOL_GPERMADDR: - case ETHTOOL_GUFO: - case ETHTOOL_GGSO: - case ETHTOOL_GFLAGS: - case ETHTOOL_GPFLAGS: - case ETHTOOL_GRXFH: - break; - default: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - } - - if (dev->ethtool_ops->begin) - if ((rc = dev->ethtool_ops->begin(dev)) < 0) - return rc; - - old_features = dev->features; - - switch (ethcmd) { - case ETHTOOL_GSET: - rc = ethtool_get_settings(dev, useraddr); - break; - case ETHTOOL_SSET: - rc = ethtool_set_settings(dev, useraddr); - break; - case ETHTOOL_GDRVINFO: - rc = ethtool_get_drvinfo(dev, useraddr); - break; - case ETHTOOL_GREGS: - rc = ethtool_get_regs(dev, useraddr); - break; - case ETHTOOL_GWOL: - rc = ethtool_get_wol(dev, useraddr); - break; - case ETHTOOL_SWOL: - rc = ethtool_set_wol(dev, useraddr); - break; - case ETHTOOL_GMSGLVL: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_msglevel); - break; - case ETHTOOL_SMSGLVL: - rc = ethtool_set_value_void(dev, useraddr, - dev->ethtool_ops->set_msglevel); - break; - case ETHTOOL_NWAY_RST: - rc = ethtool_nway_reset(dev); - break; - case ETHTOOL_GLINK: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_link); - break; - case ETHTOOL_GEEPROM: - rc = ethtool_get_eeprom(dev, useraddr); - break; - case ETHTOOL_SEEPROM: - rc = ethtool_set_eeprom(dev, useraddr); - break; - case ETHTOOL_GCOALESCE: - rc = ethtool_get_coalesce(dev, useraddr); - break; - case ETHTOOL_SCOALESCE: - rc = ethtool_set_coalesce(dev, useraddr); - break; - case ETHTOOL_GRINGPARAM: - rc = ethtool_get_ringparam(dev, useraddr); - break; - case ETHTOOL_SRINGPARAM: - rc = ethtool_set_ringparam(dev, useraddr); - break; - case ETHTOOL_GPAUSEPARAM: - rc = ethtool_get_pauseparam(dev, useraddr); - break; - case ETHTOOL_SPAUSEPARAM: - rc = ethtool_set_pauseparam(dev, useraddr); - break; - case ETHTOOL_GRXCSUM: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_rx_csum); - break; - case ETHTOOL_SRXCSUM: - rc = ethtool_set_rx_csum(dev, useraddr); - break; - case ETHTOOL_GTXCSUM: - rc = ethtool_get_value(dev, useraddr, ethcmd, - (dev->ethtool_ops->get_tx_csum ? - dev->ethtool_ops->get_tx_csum : - ethtool_op_get_tx_csum)); - break; - case ETHTOOL_STXCSUM: - rc = ethtool_set_tx_csum(dev, useraddr); - break; - case ETHTOOL_GSG: - rc = ethtool_get_value(dev, useraddr, ethcmd, - (dev->ethtool_ops->get_sg ? - dev->ethtool_ops->get_sg : - ethtool_op_get_sg)); - break; - case ETHTOOL_SSG: - rc = ethtool_set_sg(dev, useraddr); - break; - case ETHTOOL_GTSO: - rc = ethtool_get_value(dev, useraddr, ethcmd, - (dev->ethtool_ops->get_tso ? - dev->ethtool_ops->get_tso : - ethtool_op_get_tso)); - break; - case ETHTOOL_STSO: - rc = ethtool_set_tso(dev, useraddr); - break; - case ETHTOOL_TEST: - rc = ethtool_self_test(dev, useraddr); - break; - case ETHTOOL_GSTRINGS: - rc = ethtool_get_strings(dev, useraddr); - break; - case ETHTOOL_PHYS_ID: - rc = ethtool_phys_id(dev, useraddr); - break; - case ETHTOOL_GSTATS: - rc = ethtool_get_stats(dev, useraddr); - break; - case ETHTOOL_GPERMADDR: - rc = ethtool_get_perm_addr(dev, useraddr); - break; - case ETHTOOL_GUFO: - rc = ethtool_get_value(dev, useraddr, ethcmd, - (dev->ethtool_ops->get_ufo ? - dev->ethtool_ops->get_ufo : - ethtool_op_get_ufo)); - break; - case ETHTOOL_SUFO: - rc = ethtool_set_ufo(dev, useraddr); - break; - case ETHTOOL_GGSO: - rc = ethtool_get_gso(dev, useraddr); - break; - case ETHTOOL_SGSO: - rc = ethtool_set_gso(dev, useraddr); - break; - case ETHTOOL_GFLAGS: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_flags); - break; - case ETHTOOL_SFLAGS: - rc = ethtool_set_value(dev, useraddr, - dev->ethtool_ops->set_flags); - break; - case ETHTOOL_GPFLAGS: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_priv_flags); - break; - case ETHTOOL_SPFLAGS: - rc = ethtool_set_value(dev, useraddr, - dev->ethtool_ops->set_priv_flags); - break; - case ETHTOOL_GRXFH: - rc = ethtool_get_rxhash(dev, useraddr); - break; - case ETHTOOL_SRXFH: - rc = ethtool_set_rxhash(dev, useraddr); - break; - case ETHTOOL_GGRO: - rc = ethtool_get_gro(dev, useraddr); - break; - case ETHTOOL_SGRO: - rc = ethtool_set_gro(dev, useraddr); - break; - default: - rc = -EOPNOTSUPP; - } - - if (dev->ethtool_ops->complete) - dev->ethtool_ops->complete(dev); - - if (old_features != dev->features) - netdev_features_change(dev); - - return rc; -} - -EXPORT_SYMBOL(ethtool_op_get_link); -EXPORT_SYMBOL(ethtool_op_get_sg); -EXPORT_SYMBOL(ethtool_op_get_tso); -EXPORT_SYMBOL(ethtool_op_get_tx_csum); -EXPORT_SYMBOL(ethtool_op_set_sg); -EXPORT_SYMBOL(ethtool_op_set_tso); -EXPORT_SYMBOL(ethtool_op_set_tx_csum); -EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); -EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum); -EXPORT_SYMBOL(ethtool_op_set_ufo); -EXPORT_SYMBOL(ethtool_op_get_ufo); -EXPORT_SYMBOL(ethtool_op_set_flags); -EXPORT_SYMBOL(ethtool_op_get_flags); diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/filter.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/filter.c.svn-base deleted file mode 100644 index d1d779ca..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/filter.c.svn-base +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Linux Socket Filter - Kernel level socket filtering - * - * Author: - * Jay Schulist <jschlst@samba.org> - * - * Based on the design of: - * - The Berkeley Packet Filter - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Andi Kleen - Fix a few bad bugs and races. - * Kris Katterjohn - Added many additional checks in sk_chk_filter() - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/fcntl.h> -#include <linux/socket.h> -#include <linux/in.h> -#include <linux/inet.h> -#include <linux/netdevice.h> -#include <linux/if_packet.h> -#include <net/ip.h> -#include <net/protocol.h> -#include <net/netlink.h> -#include <linux/skbuff.h> -#include <net/sock.h> -#include <linux/errno.h> -#include <linux/timer.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> -#include <linux/filter.h> - -/* No hurry in this branch */ -static void *__load_pointer(struct sk_buff *skb, int k) -{ - u8 *ptr = NULL; - - if (k >= SKF_NET_OFF) - ptr = skb_network_header(skb) + k - SKF_NET_OFF; - else if (k >= SKF_LL_OFF) - ptr = skb_mac_header(skb) + k - SKF_LL_OFF; - - if (ptr >= skb->head && ptr < skb_tail_pointer(skb)) - return ptr; - return NULL; -} - -static inline void *load_pointer(struct sk_buff *skb, int k, - unsigned int size, void *buffer) -{ - if (k >= 0) - return skb_header_pointer(skb, k, size, buffer); - else { - if (k >= SKF_AD_OFF) - return NULL; - return __load_pointer(skb, k); - } -} - -/** - * sk_filter - run a packet through a socket filter - * @sk: sock associated with &sk_buff - * @skb: buffer to filter - * - * Run the filter code and then cut skb->data to correct size returned by - * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller - * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to sk_run_filter. It returns 0 if the packet should - * be accepted or -EPERM if the packet should be tossed. - * - */ -int sk_filter(struct sock *sk, struct sk_buff *skb) -{ - int err; - struct sk_filter *filter; - - err = security_sock_rcv_skb(sk, skb); - if (err) - return err; - - rcu_read_lock_bh(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - unsigned int pkt_len = sk_run_filter(skb, filter->insns, - filter->len); - err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; - } - rcu_read_unlock_bh(); - - return err; -} -EXPORT_SYMBOL(sk_filter); - -/** - * sk_run_filter - run a filter on a socket - * @skb: buffer to run the filter on - * @filter: filter to apply - * @flen: length of filter - * - * Decode and apply filter instructions to the skb->data. - * Return length to keep, 0 for none. skb is the data we are - * filtering, filter is the array of filter instructions, and - * len is the number of filter blocks in the array. - */ -unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) -{ - struct sock_filter *fentry; /* We walk down these */ - void *ptr; - u32 A = 0; /* Accumulator */ - u32 X = 0; /* Index Register */ - u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */ - u32 tmp; - int k; - int pc; - - /* - * Process array of filter instructions. - */ - for (pc = 0; pc < flen; pc++) { - fentry = &filter[pc]; - - switch (fentry->code) { - case BPF_ALU|BPF_ADD|BPF_X: - A += X; - continue; - case BPF_ALU|BPF_ADD|BPF_K: - A += fentry->k; - continue; - case BPF_ALU|BPF_SUB|BPF_X: - A -= X; - continue; - case BPF_ALU|BPF_SUB|BPF_K: - A -= fentry->k; - continue; - case BPF_ALU|BPF_MUL|BPF_X: - A *= X; - continue; - case BPF_ALU|BPF_MUL|BPF_K: - A *= fentry->k; - continue; - case BPF_ALU|BPF_DIV|BPF_X: - if (X == 0) - return 0; - A /= X; - continue; - case BPF_ALU|BPF_DIV|BPF_K: - A /= fentry->k; - continue; - case BPF_ALU|BPF_AND|BPF_X: - A &= X; - continue; - case BPF_ALU|BPF_AND|BPF_K: - A &= fentry->k; - continue; - case BPF_ALU|BPF_OR|BPF_X: - A |= X; - continue; - case BPF_ALU|BPF_OR|BPF_K: - A |= fentry->k; - continue; - case BPF_ALU|BPF_LSH|BPF_X: - A <<= X; - continue; - case BPF_ALU|BPF_LSH|BPF_K: - A <<= fentry->k; - continue; - case BPF_ALU|BPF_RSH|BPF_X: - A >>= X; - continue; - case BPF_ALU|BPF_RSH|BPF_K: - A >>= fentry->k; - continue; - case BPF_ALU|BPF_NEG: - A = -A; - continue; - case BPF_JMP|BPF_JA: - pc += fentry->k; - continue; - case BPF_JMP|BPF_JGT|BPF_K: - pc += (A > fentry->k) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JGE|BPF_K: - pc += (A >= fentry->k) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JEQ|BPF_K: - pc += (A == fentry->k) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JSET|BPF_K: - pc += (A & fentry->k) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JGT|BPF_X: - pc += (A > X) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JGE|BPF_X: - pc += (A >= X) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JEQ|BPF_X: - pc += (A == X) ? fentry->jt : fentry->jf; - continue; - case BPF_JMP|BPF_JSET|BPF_X: - pc += (A & X) ? fentry->jt : fentry->jf; - continue; - case BPF_LD|BPF_W|BPF_ABS: - k = fentry->k; -load_w: - ptr = load_pointer(skb, k, 4, &tmp); - if (ptr != NULL) { - A = get_unaligned_be32(ptr); - continue; - } - break; - case BPF_LD|BPF_H|BPF_ABS: - k = fentry->k; -load_h: - ptr = load_pointer(skb, k, 2, &tmp); - if (ptr != NULL) { - A = get_unaligned_be16(ptr); - continue; - } - break; - case BPF_LD|BPF_B|BPF_ABS: - k = fentry->k; -load_b: - ptr = load_pointer(skb, k, 1, &tmp); - if (ptr != NULL) { - A = *(u8 *)ptr; - continue; - } - break; - case BPF_LD|BPF_W|BPF_LEN: - A = skb->len; - continue; - case BPF_LDX|BPF_W|BPF_LEN: - X = skb->len; - continue; - case BPF_LD|BPF_W|BPF_IND: - k = X + fentry->k; - goto load_w; - case BPF_LD|BPF_H|BPF_IND: - k = X + fentry->k; - goto load_h; - case BPF_LD|BPF_B|BPF_IND: - k = X + fentry->k; - goto load_b; - case BPF_LDX|BPF_B|BPF_MSH: - ptr = load_pointer(skb, fentry->k, 1, &tmp); - if (ptr != NULL) { - X = (*(u8 *)ptr & 0xf) << 2; - continue; - } - return 0; - case BPF_LD|BPF_IMM: - A = fentry->k; - continue; - case BPF_LDX|BPF_IMM: - X = fentry->k; - continue; - case BPF_LD|BPF_MEM: - A = mem[fentry->k]; - continue; - case BPF_LDX|BPF_MEM: - X = mem[fentry->k]; - continue; - case BPF_MISC|BPF_TAX: - X = A; - continue; - case BPF_MISC|BPF_TXA: - A = X; - continue; - case BPF_RET|BPF_K: - return fentry->k; - case BPF_RET|BPF_A: - return A; - case BPF_ST: - mem[fentry->k] = A; - continue; - case BPF_STX: - mem[fentry->k] = X; - continue; - default: - WARN_ON(1); - return 0; - } - - /* - * Handle ancillary data, which are impossible - * (or very difficult) to get parsing packet contents. - */ - switch (k-SKF_AD_OFF) { - case SKF_AD_PROTOCOL: - A = ntohs(skb->protocol); - continue; - case SKF_AD_PKTTYPE: - A = skb->pkt_type; - continue; - case SKF_AD_IFINDEX: - A = skb->dev->ifindex; - continue; - case SKF_AD_NLATTR: { - struct nlattr *nla; - - if (skb_is_nonlinear(skb)) - return 0; - if (A > skb->len - sizeof(struct nlattr)) - return 0; - - nla = nla_find((struct nlattr *)&skb->data[A], - skb->len - A, X); - if (nla) - A = (void *)nla - (void *)skb->data; - else - A = 0; - continue; - } - case SKF_AD_NLATTR_NEST: { - struct nlattr *nla; - - if (skb_is_nonlinear(skb)) - return 0; - if (A > skb->len - sizeof(struct nlattr)) - return 0; - - nla = (struct nlattr *)&skb->data[A]; - if (nla->nla_len > A - skb->len) - return 0; - - nla = nla_find_nested(nla, X); - if (nla) - A = (void *)nla - (void *)skb->data; - else - A = 0; - continue; - } - default: - return 0; - } - } - - return 0; -} -EXPORT_SYMBOL(sk_run_filter); - -/** - * sk_chk_filter - verify socket filter code - * @filter: filter to verify - * @flen: length of filter - * - * Check the user's filter code. If we let some ugly - * filter code slip through kaboom! The filter must contain - * no references or jumps that are out of range, no illegal - * instructions, and must end with a RET instruction. - * - * All jumps are forward as they are not signed. - * - * Returns 0 if the rule set is legal or -EINVAL if not. - */ -int sk_chk_filter(struct sock_filter *filter, int flen) -{ - struct sock_filter *ftest; - int pc; - - if (flen == 0 || flen > BPF_MAXINSNS) - return -EINVAL; - - /* check the filter code now */ - for (pc = 0; pc < flen; pc++) { - ftest = &filter[pc]; - - /* Only allow valid instructions */ - switch (ftest->code) { - case BPF_ALU|BPF_ADD|BPF_K: - case BPF_ALU|BPF_ADD|BPF_X: - case BPF_ALU|BPF_SUB|BPF_K: - case BPF_ALU|BPF_SUB|BPF_X: - case BPF_ALU|BPF_MUL|BPF_K: - case BPF_ALU|BPF_MUL|BPF_X: - case BPF_ALU|BPF_DIV|BPF_X: - case BPF_ALU|BPF_AND|BPF_K: - case BPF_ALU|BPF_AND|BPF_X: - case BPF_ALU|BPF_OR|BPF_K: - case BPF_ALU|BPF_OR|BPF_X: - case BPF_ALU|BPF_LSH|BPF_K: - case BPF_ALU|BPF_LSH|BPF_X: - case BPF_ALU|BPF_RSH|BPF_K: - case BPF_ALU|BPF_RSH|BPF_X: - case BPF_ALU|BPF_NEG: - case BPF_LD|BPF_W|BPF_ABS: - case BPF_LD|BPF_H|BPF_ABS: - case BPF_LD|BPF_B|BPF_ABS: - case BPF_LD|BPF_W|BPF_LEN: - case BPF_LD|BPF_W|BPF_IND: - case BPF_LD|BPF_H|BPF_IND: - case BPF_LD|BPF_B|BPF_IND: - case BPF_LD|BPF_IMM: - case BPF_LDX|BPF_W|BPF_LEN: - case BPF_LDX|BPF_B|BPF_MSH: - case BPF_LDX|BPF_IMM: - case BPF_MISC|BPF_TAX: - case BPF_MISC|BPF_TXA: - case BPF_RET|BPF_K: - case BPF_RET|BPF_A: - break; - - /* Some instructions need special checks */ - - case BPF_ALU|BPF_DIV|BPF_K: - /* check for division by zero */ - if (ftest->k == 0) - return -EINVAL; - break; - - case BPF_LD|BPF_MEM: - case BPF_LDX|BPF_MEM: - case BPF_ST: - case BPF_STX: - /* check for invalid memory addresses */ - if (ftest->k >= BPF_MEMWORDS) - return -EINVAL; - break; - - case BPF_JMP|BPF_JA: - /* - * Note, the large ftest->k might cause loops. - * Compare this with conditional jumps below, - * where offsets are limited. --ANK (981016) - */ - if (ftest->k >= (unsigned)(flen-pc-1)) - return -EINVAL; - break; - - case BPF_JMP|BPF_JEQ|BPF_K: - case BPF_JMP|BPF_JEQ|BPF_X: - case BPF_JMP|BPF_JGE|BPF_K: - case BPF_JMP|BPF_JGE|BPF_X: - case BPF_JMP|BPF_JGT|BPF_K: - case BPF_JMP|BPF_JGT|BPF_X: - case BPF_JMP|BPF_JSET|BPF_K: - case BPF_JMP|BPF_JSET|BPF_X: - /* for conditionals both must be safe */ - if (pc + ftest->jt + 1 >= flen || - pc + ftest->jf + 1 >= flen) - return -EINVAL; - break; - - default: - return -EINVAL; - } - } - - return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL; -} -EXPORT_SYMBOL(sk_chk_filter); - -/** - * sk_filter_rcu_release: Release a socket filter by rcu_head - * @rcu: rcu_head that contains the sk_filter to free - */ -static void sk_filter_rcu_release(struct rcu_head *rcu) -{ - struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); - - sk_filter_release(fp); -} - -static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp) -{ - unsigned int size = sk_filter_len(fp); - - atomic_sub(size, &sk->sk_omem_alloc); - call_rcu_bh(&fp->rcu, sk_filter_rcu_release); -} - -/** - * sk_attach_filter - attach a socket filter - * @fprog: the filter program - * @sk: the socket to use - * - * Attach the user's filter code. We first run some sanity checks on - * it to make sure it does not explode on us later. If an error - * occurs or there is insufficient memory for the filter a negative - * errno code is returned. On success the return is zero. - */ -int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) -{ - struct sk_filter *fp, *old_fp; - unsigned int fsize = sizeof(struct sock_filter) * fprog->len; - int err; - - /* Make sure new filter is there and in the right amounts. */ - if (fprog->filter == NULL) - return -EINVAL; - - fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); - if (!fp) - return -ENOMEM; - if (copy_from_user(fp->insns, fprog->filter, fsize)) { - sock_kfree_s(sk, fp, fsize+sizeof(*fp)); - return -EFAULT; - } - - atomic_set(&fp->refcnt, 1); - fp->len = fprog->len; - - err = sk_chk_filter(fp->insns, fp->len); - if (err) { - sk_filter_uncharge(sk, fp); - return err; - } - - rcu_read_lock_bh(); - old_fp = rcu_dereference(sk->sk_filter); - rcu_assign_pointer(sk->sk_filter, fp); - rcu_read_unlock_bh(); - - if (old_fp) - sk_filter_delayed_uncharge(sk, old_fp); - return 0; -} - -int sk_detach_filter(struct sock *sk) -{ - int ret = -ENOENT; - struct sk_filter *filter; - - rcu_read_lock_bh(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - rcu_assign_pointer(sk->sk_filter, NULL); - sk_filter_delayed_uncharge(sk, filter); - ret = 0; - } - rcu_read_unlock_bh(); - return ret; -} diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/kmap_skb.h.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/kmap_skb.h.svn-base deleted file mode 100644 index 283c2b99..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/kmap_skb.h.svn-base +++ /dev/null @@ -1,19 +0,0 @@ -#include <linux/highmem.h> - -static inline void *kmap_skb_frag(const skb_frag_t *frag) -{ -#ifdef CONFIG_HIGHMEM - BUG_ON(in_irq()); - - local_bh_disable(); -#endif - return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ); -} - -static inline void kunmap_skb_frag(void *vaddr) -{ - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); -#ifdef CONFIG_HIGHMEM - local_bh_enable(); -#endif -} diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/neighbour.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/neighbour.c.svn-base deleted file mode 100644 index 278a142d..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/neighbour.c.svn-base +++ /dev/null @@ -1,2824 +0,0 @@ -/* - * Generic address resolution entity - * - * Authors: - * Pedro Roque <roque@di.fc.ul.pt> - * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. - * Harald Welte Add neighbour cache statistics like rtstat - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/socket.h> -#include <linux/netdevice.h> -#include <linux/proc_fs.h> -#ifdef CONFIG_SYSCTL -#include <linux/sysctl.h> -#endif -#include <linux/times.h> -#include <net/net_namespace.h> -#include <net/neighbour.h> -#include <net/dst.h> -#include <net/sock.h> -#include <net/netevent.h> -#include <net/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/random.h> -#include <linux/string.h> -#include <linux/log2.h> - -#define NEIGH_DEBUG 1 - -#define NEIGH_PRINTK(x...) printk(x) -#define NEIGH_NOPRINTK(x...) do { ; } while(0) -#define NEIGH_PRINTK0 NEIGH_PRINTK -#define NEIGH_PRINTK1 NEIGH_NOPRINTK -#define NEIGH_PRINTK2 NEIGH_NOPRINTK - -#if NEIGH_DEBUG >= 1 -#undef NEIGH_PRINTK1 -#define NEIGH_PRINTK1 NEIGH_PRINTK -#endif -#if NEIGH_DEBUG >= 2 -#undef NEIGH_PRINTK2 -#define NEIGH_PRINTK2 NEIGH_PRINTK -#endif - -#define PNEIGH_HASHMASK 0xF - -static void neigh_timer_handler(unsigned long arg); -static void __neigh_notify(struct neighbour *n, int type, int flags); -static void neigh_update_notify(struct neighbour *neigh); -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); - -static struct neigh_table *neigh_tables; -#ifdef CONFIG_PROC_FS -static const struct file_operations neigh_stat_seq_fops; -#endif - -/* - Neighbour hash table buckets are protected with rwlock tbl->lock. - - - All the scans/updates to hash buckets MUST be made under this lock. - - NOTHING clever should be made under this lock: no callbacks - to protocol backends, no attempts to send something to network. - It will result in deadlocks, if backend/driver wants to use neighbour - cache. - - If the entry requires some non-trivial actions, increase - its reference count and release table lock. - - Neighbour entries are protected: - - with reference count. - - with rwlock neigh->lock - - Reference count prevents destruction. - - neigh->lock mainly serializes ll address data and its validity state. - However, the same lock is used to protect another entry fields: - - timer - - resolution queue - - Again, nothing clever shall be made under neigh->lock, - the most complicated procedure, which we allow is dev->hard_header. - It is supposed, that dev->hard_header is simplistic and does - not make callbacks to neighbour tables. - - The last lock is neigh_tbl_lock. It is pure SMP lock, protecting - list of neighbour tables. This list is used only in process context, - */ - -static DEFINE_RWLOCK(neigh_tbl_lock); - -static int neigh_blackhole(struct sk_buff *skb) -{ - kfree_skb(skb); - return -ENETDOWN; -} - -static void neigh_cleanup_and_release(struct neighbour *neigh) -{ - if (neigh->parms->neigh_cleanup) - neigh->parms->neigh_cleanup(neigh); - - __neigh_notify(neigh, RTM_DELNEIGH, 0); - neigh_release(neigh); -} - -/* - * It is random distribution in the interval (1/2)*base...(3/2)*base. - * It corresponds to default IPv6 settings and is not overridable, - * because it is really reasonable choice. - */ - -unsigned long neigh_rand_reach_time(unsigned long base) -{ - return (base ? (net_random() % base) + (base >> 1) : 0); -} -EXPORT_SYMBOL(neigh_rand_reach_time); - - -static int neigh_forced_gc(struct neigh_table *tbl) -{ - int shrunk = 0; - int i; - - NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); - - write_lock_bh(&tbl->lock); - for (i = 0; i <= tbl->hash_mask; i++) { - struct neighbour *n, **np; - - np = &tbl->hash_buckets[i]; - while ((n = *np) != NULL) { - /* Neighbour record may be discarded if: - * - nobody refers to it. - * - it is not permanent - */ - write_lock(&n->lock); - if (atomic_read(&n->refcnt) == 1 && - !(n->nud_state & NUD_PERMANENT)) { - *np = n->next; - n->dead = 1; - shrunk = 1; - write_unlock(&n->lock); - neigh_cleanup_and_release(n); - continue; - } - write_unlock(&n->lock); - np = &n->next; - } - } - - tbl->last_flush = jiffies; - - write_unlock_bh(&tbl->lock); - - return shrunk; -} - -static void neigh_add_timer(struct neighbour *n, unsigned long when) -{ - neigh_hold(n); - if (unlikely(mod_timer(&n->timer, when))) { - printk("NEIGH: BUG, double timer add, state is %x\n", - n->nud_state); - dump_stack(); - } -} - -static int neigh_del_timer(struct neighbour *n) -{ - if ((n->nud_state & NUD_IN_TIMER) && - del_timer(&n->timer)) { - neigh_release(n); - return 1; - } - return 0; -} - -static void pneigh_queue_purge(struct sk_buff_head *list) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(list)) != NULL) { - dev_put(skb->dev); - kfree_skb(skb); - } -} - -static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) -{ - int i; - - for (i = 0; i <= tbl->hash_mask; i++) { - struct neighbour *n, **np = &tbl->hash_buckets[i]; - - while ((n = *np) != NULL) { - if (dev && n->dev != dev) { - np = &n->next; - continue; - } - *np = n->next; - write_lock(&n->lock); - neigh_del_timer(n); - n->dead = 1; - - if (atomic_read(&n->refcnt) != 1) { - /* The most unpleasant situation. - We must destroy neighbour entry, - but someone still uses it. - - The destroy will be delayed until - the last user releases us, but - we must kill timers etc. and move - it to safe state. - */ - skb_queue_purge(&n->arp_queue); - n->output = neigh_blackhole; - if (n->nud_state & NUD_VALID) - n->nud_state = NUD_NOARP; - else - n->nud_state = NUD_NONE; - NEIGH_PRINTK2("neigh %p is stray.\n", n); - } - write_unlock(&n->lock); - neigh_cleanup_and_release(n); - } - } -} - -void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) -{ - write_lock_bh(&tbl->lock); - neigh_flush_dev(tbl, dev); - write_unlock_bh(&tbl->lock); -} -EXPORT_SYMBOL(neigh_changeaddr); - -int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) -{ - write_lock_bh(&tbl->lock); - neigh_flush_dev(tbl, dev); - pneigh_ifdown(tbl, dev); - write_unlock_bh(&tbl->lock); - - del_timer_sync(&tbl->proxy_timer); - pneigh_queue_purge(&tbl->proxy_queue); - return 0; -} -EXPORT_SYMBOL(neigh_ifdown); - -static struct neighbour *neigh_alloc(struct neigh_table *tbl) -{ - struct neighbour *n = NULL; - unsigned long now = jiffies; - int entries; - - entries = atomic_inc_return(&tbl->entries) - 1; - if (entries >= tbl->gc_thresh3 || - (entries >= tbl->gc_thresh2 && - time_after(now, tbl->last_flush + 5 * HZ))) { - if (!neigh_forced_gc(tbl) && - entries >= tbl->gc_thresh3) - goto out_entries; - } - - n = kmem_cache_zalloc(tbl->kmem_cachep, GFP_ATOMIC); - if (!n) - goto out_entries; - - skb_queue_head_init(&n->arp_queue); - rwlock_init(&n->lock); - n->updated = n->used = now; - n->nud_state = NUD_NONE; - n->output = neigh_blackhole; - n->parms = neigh_parms_clone(&tbl->parms); - setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n); - - NEIGH_CACHE_STAT_INC(tbl, allocs); - n->tbl = tbl; - atomic_set(&n->refcnt, 1); - n->dead = 1; -out: - return n; - -out_entries: - atomic_dec(&tbl->entries); - goto out; -} - -static struct neighbour **neigh_hash_alloc(unsigned int entries) -{ - unsigned long size = entries * sizeof(struct neighbour *); - struct neighbour **ret; - - if (size <= PAGE_SIZE) { - ret = kzalloc(size, GFP_ATOMIC); - } else { - ret = (struct neighbour **) - __get_free_pages(GFP_ATOMIC|__GFP_ZERO, get_order(size)); - } - return ret; -} - -static void neigh_hash_free(struct neighbour **hash, unsigned int entries) -{ - unsigned long size = entries * sizeof(struct neighbour *); - - if (size <= PAGE_SIZE) - kfree(hash); - else - free_pages((unsigned long)hash, get_order(size)); -} - -static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries) -{ - struct neighbour **new_hash, **old_hash; - unsigned int i, new_hash_mask, old_entries; - - NEIGH_CACHE_STAT_INC(tbl, hash_grows); - - BUG_ON(!is_power_of_2(new_entries)); - new_hash = neigh_hash_alloc(new_entries); - if (!new_hash) - return; - - old_entries = tbl->hash_mask + 1; - new_hash_mask = new_entries - 1; - old_hash = tbl->hash_buckets; - - get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); - for (i = 0; i < old_entries; i++) { - struct neighbour *n, *next; - - for (n = old_hash[i]; n; n = next) { - unsigned int hash_val = tbl->hash(n->primary_key, n->dev); - - hash_val &= new_hash_mask; - next = n->next; - - n->next = new_hash[hash_val]; - new_hash[hash_val] = n; - } - } - tbl->hash_buckets = new_hash; - tbl->hash_mask = new_hash_mask; - - neigh_hash_free(old_hash, old_entries); -} - -struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, - struct net_device *dev) -{ - struct neighbour *n; - int key_len = tbl->key_len; - u32 hash_val; - - NEIGH_CACHE_STAT_INC(tbl, lookups); - - read_lock_bh(&tbl->lock); - hash_val = tbl->hash(pkey, dev); - for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { - if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { - neigh_hold(n); - NEIGH_CACHE_STAT_INC(tbl, hits); - break; - } - } - read_unlock_bh(&tbl->lock); - return n; -} -EXPORT_SYMBOL(neigh_lookup); - -struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, - const void *pkey) -{ - struct neighbour *n; - int key_len = tbl->key_len; - u32 hash_val; - - NEIGH_CACHE_STAT_INC(tbl, lookups); - - read_lock_bh(&tbl->lock); - hash_val = tbl->hash(pkey, NULL); - for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { - if (!memcmp(n->primary_key, pkey, key_len) && - net_eq(dev_net(n->dev), net)) { - neigh_hold(n); - NEIGH_CACHE_STAT_INC(tbl, hits); - break; - } - } - read_unlock_bh(&tbl->lock); - return n; -} -EXPORT_SYMBOL(neigh_lookup_nodev); - -struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, - struct net_device *dev) -{ - u32 hash_val; - int key_len = tbl->key_len; - int error; - struct neighbour *n1, *rc, *n = neigh_alloc(tbl); - - if (!n) { - rc = ERR_PTR(-ENOBUFS); - goto out; - } - - memcpy(n->primary_key, pkey, key_len); - n->dev = dev; - dev_hold(dev); - - /* Protocol specific setup. */ - if (tbl->constructor && (error = tbl->constructor(n)) < 0) { - rc = ERR_PTR(error); - goto out_neigh_release; - } - - /* Device specific setup. */ - if (n->parms->neigh_setup && - (error = n->parms->neigh_setup(n)) < 0) { - rc = ERR_PTR(error); - goto out_neigh_release; - } - - n->confirmed = jiffies - (n->parms->base_reachable_time << 1); - - write_lock_bh(&tbl->lock); - - if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1)) - neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1); - - hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; - - if (n->parms->dead) { - rc = ERR_PTR(-EINVAL); - goto out_tbl_unlock; - } - - for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) { - if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) { - neigh_hold(n1); - rc = n1; - goto out_tbl_unlock; - } - } - - n->next = tbl->hash_buckets[hash_val]; - tbl->hash_buckets[hash_val] = n; - n->dead = 0; - neigh_hold(n); - write_unlock_bh(&tbl->lock); - NEIGH_PRINTK2("neigh %p is created.\n", n); - rc = n; -out: - return rc; -out_tbl_unlock: - write_unlock_bh(&tbl->lock); -out_neigh_release: - neigh_release(n); - goto out; -} -EXPORT_SYMBOL(neigh_create); - -static u32 pneigh_hash(const void *pkey, int key_len) -{ - u32 hash_val = *(u32 *)(pkey + key_len - 4); - hash_val ^= (hash_val >> 16); - hash_val ^= hash_val >> 8; - hash_val ^= hash_val >> 4; - hash_val &= PNEIGH_HASHMASK; - return hash_val; -} - -static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n, - struct net *net, - const void *pkey, - int key_len, - struct net_device *dev) -{ - while (n) { - if (!memcmp(n->key, pkey, key_len) && - net_eq(pneigh_net(n), net) && - (n->dev == dev || !n->dev)) - return n; - n = n->next; - } - return NULL; -} - -struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, - struct net *net, const void *pkey, struct net_device *dev) -{ - int key_len = tbl->key_len; - u32 hash_val = pneigh_hash(pkey, key_len); - - return __pneigh_lookup_1(tbl->phash_buckets[hash_val], - net, pkey, key_len, dev); -} -EXPORT_SYMBOL_GPL(__pneigh_lookup); - -struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, - struct net *net, const void *pkey, - struct net_device *dev, int creat) -{ - struct pneigh_entry *n; - int key_len = tbl->key_len; - u32 hash_val = pneigh_hash(pkey, key_len); - - read_lock_bh(&tbl->lock); - n = __pneigh_lookup_1(tbl->phash_buckets[hash_val], - net, pkey, key_len, dev); - read_unlock_bh(&tbl->lock); - - if (n || !creat) - goto out; - - ASSERT_RTNL(); - - n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL); - if (!n) - goto out; - - write_pnet(&n->net, hold_net(net)); - memcpy(n->key, pkey, key_len); - n->dev = dev; - if (dev) - dev_hold(dev); - - if (tbl->pconstructor && tbl->pconstructor(n)) { - if (dev) - dev_put(dev); - release_net(net); - kfree(n); - n = NULL; - goto out; - } - - write_lock_bh(&tbl->lock); - n->next = tbl->phash_buckets[hash_val]; - tbl->phash_buckets[hash_val] = n; - write_unlock_bh(&tbl->lock); -out: - return n; -} -EXPORT_SYMBOL(pneigh_lookup); - - -int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, - struct net_device *dev) -{ - struct pneigh_entry *n, **np; - int key_len = tbl->key_len; - u32 hash_val = pneigh_hash(pkey, key_len); - - write_lock_bh(&tbl->lock); - for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; - np = &n->next) { - if (!memcmp(n->key, pkey, key_len) && n->dev == dev && - net_eq(pneigh_net(n), net)) { - *np = n->next; - write_unlock_bh(&tbl->lock); - if (tbl->pdestructor) - tbl->pdestructor(n); - if (n->dev) - dev_put(n->dev); - release_net(pneigh_net(n)); - kfree(n); - return 0; - } - } - write_unlock_bh(&tbl->lock); - return -ENOENT; -} - -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) -{ - struct pneigh_entry *n, **np; - u32 h; - - for (h = 0; h <= PNEIGH_HASHMASK; h++) { - np = &tbl->phash_buckets[h]; - while ((n = *np) != NULL) { - if (!dev || n->dev == dev) { - *np = n->next; - if (tbl->pdestructor) - tbl->pdestructor(n); - if (n->dev) - dev_put(n->dev); - release_net(pneigh_net(n)); - kfree(n); - continue; - } - np = &n->next; - } - } - return -ENOENT; -} - -static void neigh_parms_destroy(struct neigh_parms *parms); - -static inline void neigh_parms_put(struct neigh_parms *parms) -{ - if (atomic_dec_and_test(&parms->refcnt)) - neigh_parms_destroy(parms); -} - -/* - * neighbour must already be out of the table; - * - */ -void neigh_destroy(struct neighbour *neigh) -{ - struct hh_cache *hh; - - NEIGH_CACHE_STAT_INC(neigh->tbl, destroys); - - if (!neigh->dead) { - printk(KERN_WARNING - "Destroying alive neighbour %p\n", neigh); - dump_stack(); - return; - } - - if (neigh_del_timer(neigh)) - printk(KERN_WARNING "Impossible event.\n"); - - while ((hh = neigh->hh) != NULL) { - neigh->hh = hh->hh_next; - hh->hh_next = NULL; - - write_seqlock_bh(&hh->hh_lock); - hh->hh_output = neigh_blackhole; - write_sequnlock_bh(&hh->hh_lock); - if (atomic_dec_and_test(&hh->hh_refcnt)) - kfree(hh); - } - - skb_queue_purge(&neigh->arp_queue); - - dev_put(neigh->dev); - neigh_parms_put(neigh->parms); - - NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh); - - atomic_dec(&neigh->tbl->entries); - kmem_cache_free(neigh->tbl->kmem_cachep, neigh); -} -EXPORT_SYMBOL(neigh_destroy); - -/* Neighbour state is suspicious; - disable fast path. - - Called with write_locked neigh. - */ -static void neigh_suspect(struct neighbour *neigh) -{ - struct hh_cache *hh; - - NEIGH_PRINTK2("neigh %p is suspected.\n", neigh); - - neigh->output = neigh->ops->output; - - for (hh = neigh->hh; hh; hh = hh->hh_next) - hh->hh_output = neigh->ops->output; -} - -/* Neighbour state is OK; - enable fast path. - - Called with write_locked neigh. - */ -static void neigh_connect(struct neighbour *neigh) -{ - struct hh_cache *hh; - - NEIGH_PRINTK2("neigh %p is connected.\n", neigh); - - neigh->output = neigh->ops->connected_output; - - for (hh = neigh->hh; hh; hh = hh->hh_next) - hh->hh_output = neigh->ops->hh_output; -} - -static void neigh_periodic_timer(unsigned long arg) -{ - struct neigh_table *tbl = (struct neigh_table *)arg; - struct neighbour *n, **np; - unsigned long expire, now = jiffies; - - NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); - - write_lock(&tbl->lock); - - /* - * periodically recompute ReachableTime from random function - */ - - if (time_after(now, tbl->last_rand + 300 * HZ)) { - struct neigh_parms *p; - tbl->last_rand = now; - for (p = &tbl->parms; p; p = p->next) - p->reachable_time = - neigh_rand_reach_time(p->base_reachable_time); - } - - np = &tbl->hash_buckets[tbl->hash_chain_gc]; - tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask); - - while ((n = *np) != NULL) { - unsigned int state; - - write_lock(&n->lock); - - state = n->nud_state; - if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { - write_unlock(&n->lock); - goto next_elt; - } - - if (time_before(n->used, n->confirmed)) - n->used = n->confirmed; - - if (atomic_read(&n->refcnt) == 1 && - (state == NUD_FAILED || - time_after(now, n->used + n->parms->gc_staletime))) { - *np = n->next; - n->dead = 1; - write_unlock(&n->lock); - neigh_cleanup_and_release(n); - continue; - } - write_unlock(&n->lock); - -next_elt: - np = &n->next; - } - - /* Cycle through all hash buckets every base_reachable_time/2 ticks. - * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 - * base_reachable_time. - */ - expire = tbl->parms.base_reachable_time >> 1; - expire /= (tbl->hash_mask + 1); - if (!expire) - expire = 1; - - if (expire>HZ) - mod_timer(&tbl->gc_timer, round_jiffies(now + expire)); - else - mod_timer(&tbl->gc_timer, now + expire); - - write_unlock(&tbl->lock); -} - -static __inline__ int neigh_max_probes(struct neighbour *n) -{ - struct neigh_parms *p = n->parms; - return (n->nud_state & NUD_PROBE ? - p->ucast_probes : - p->ucast_probes + p->app_probes + p->mcast_probes); -} - -/* Called when a timer expires for a neighbour entry. */ - -static void neigh_timer_handler(unsigned long arg) -{ - unsigned long now, next; - struct neighbour *neigh = (struct neighbour *)arg; - unsigned state; - int notify = 0; - - write_lock(&neigh->lock); - - state = neigh->nud_state; - now = jiffies; - next = now + HZ; - - if (!(state & NUD_IN_TIMER)) { -#ifndef CONFIG_SMP - printk(KERN_WARNING "neigh: timer & !nud_in_timer\n"); -#endif - goto out; - } - - if (state & NUD_REACHABLE) { - if (time_before_eq(now, - neigh->confirmed + neigh->parms->reachable_time)) { - NEIGH_PRINTK2("neigh %p is still alive.\n", neigh); - next = neigh->confirmed + neigh->parms->reachable_time; - } else if (time_before_eq(now, - neigh->used + neigh->parms->delay_probe_time)) { - NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); - neigh->nud_state = NUD_DELAY; - neigh->updated = jiffies; - neigh_suspect(neigh); - next = now + neigh->parms->delay_probe_time; - } else { - NEIGH_PRINTK2("neigh %p is suspected.\n", neigh); - neigh->nud_state = NUD_STALE; - neigh->updated = jiffies; - neigh_suspect(neigh); - notify = 1; - } - } else if (state & NUD_DELAY) { - if (time_before_eq(now, - neigh->confirmed + neigh->parms->delay_probe_time)) { - NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh); - neigh->nud_state = NUD_REACHABLE; - neigh->updated = jiffies; - neigh_connect(neigh); - notify = 1; - next = neigh->confirmed + neigh->parms->reachable_time; - } else { - NEIGH_PRINTK2("neigh %p is probed.\n", neigh); - neigh->nud_state = NUD_PROBE; - neigh->updated = jiffies; - atomic_set(&neigh->probes, 0); - next = now + neigh->parms->retrans_time; - } - } else { - /* NUD_PROBE|NUD_INCOMPLETE */ - next = now + neigh->parms->retrans_time; - } - - if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && - atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { - struct sk_buff *skb; - - neigh->nud_state = NUD_FAILED; - neigh->updated = jiffies; - notify = 1; - NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); - NEIGH_PRINTK2("neigh %p is failed.\n", neigh); - - /* It is very thin place. report_unreachable is very complicated - routine. Particularly, it can hit the same neighbour entry! - - So that, we try to be accurate and avoid dead loop. --ANK - */ - while (neigh->nud_state == NUD_FAILED && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - write_unlock(&neigh->lock); - neigh->ops->error_report(neigh, skb); - write_lock(&neigh->lock); - } - skb_queue_purge(&neigh->arp_queue); - } - - if (neigh->nud_state & NUD_IN_TIMER) { - if (time_before(next, jiffies + HZ/2)) - next = jiffies + HZ/2; - if (!mod_timer(&neigh->timer, next)) - neigh_hold(neigh); - } - if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { - struct sk_buff *skb = skb_peek(&neigh->arp_queue); - /* keep skb alive even if arp_queue overflows */ - if (skb) - skb = skb_copy(skb, GFP_ATOMIC); - write_unlock(&neigh->lock); - neigh->ops->solicit(neigh, skb); - atomic_inc(&neigh->probes); - if (skb) - kfree_skb(skb); - } else { -out: - write_unlock(&neigh->lock); - } - - if (notify) - neigh_update_notify(neigh); - - neigh_release(neigh); -} - -int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) -{ - int rc; - unsigned long now; - - write_lock_bh(&neigh->lock); - - rc = 0; - if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE)) - goto out_unlock_bh; - - now = jiffies; - - if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { - if (neigh->parms->mcast_probes + neigh->parms->app_probes) { - atomic_set(&neigh->probes, neigh->parms->ucast_probes); - neigh->nud_state = NUD_INCOMPLETE; - neigh->updated = jiffies; - neigh_add_timer(neigh, now + 1); - } else { - neigh->nud_state = NUD_FAILED; - neigh->updated = jiffies; - write_unlock_bh(&neigh->lock); - - if (skb) - kfree_skb(skb); - return 1; - } - } else if (neigh->nud_state & NUD_STALE) { - NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); - neigh->nud_state = NUD_DELAY; - neigh->updated = jiffies; - neigh_add_timer(neigh, - jiffies + neigh->parms->delay_probe_time); - } - - if (neigh->nud_state == NUD_INCOMPLETE) { - if (skb) { - if (skb_queue_len(&neigh->arp_queue) >= - neigh->parms->queue_len) { - struct sk_buff *buff; - buff = __skb_dequeue(&neigh->arp_queue); - kfree_skb(buff); - NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards); - } - __skb_queue_tail(&neigh->arp_queue, skb); - } - rc = 1; - } -out_unlock_bh: - write_unlock_bh(&neigh->lock); - return rc; -} -EXPORT_SYMBOL(__neigh_event_send); - -static void neigh_update_hhs(struct neighbour *neigh) -{ - struct hh_cache *hh; - void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *) - = neigh->dev->header_ops->cache_update; - - if (update) { - for (hh = neigh->hh; hh; hh = hh->hh_next) { - write_seqlock_bh(&hh->hh_lock); - update(hh, neigh->dev, neigh->ha); - write_sequnlock_bh(&hh->hh_lock); - } - } -} - - - -/* Generic update routine. - -- lladdr is new lladdr or NULL, if it is not supplied. - -- new is new state. - -- flags - NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr, - if it is different. - NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected" - lladdr instead of overriding it - if it is different. - It also allows to retain current state - if lladdr is unchanged. - NEIGH_UPDATE_F_ADMIN means that the change is administrative. - - NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing - NTF_ROUTER flag. - NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as - a router. - - Caller MUST hold reference count on the entry. - */ - -int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, - u32 flags) -{ - u8 old; - int err; - int notify = 0; - struct net_device *dev; - int update_isrouter = 0; - - write_lock_bh(&neigh->lock); - - dev = neigh->dev; - old = neigh->nud_state; - err = -EPERM; - - if (!(flags & NEIGH_UPDATE_F_ADMIN) && - (old & (NUD_NOARP | NUD_PERMANENT))) - goto out; - - if (!(new & NUD_VALID)) { - neigh_del_timer(neigh); - if (old & NUD_CONNECTED) - neigh_suspect(neigh); - neigh->nud_state = new; - err = 0; - notify = old & NUD_VALID; - goto out; - } - - /* Compare new lladdr with cached one */ - if (!dev->addr_len) { - /* First case: device needs no address. */ - lladdr = neigh->ha; - } else if (lladdr) { - /* The second case: if something is already cached - and a new address is proposed: - - compare new & old - - if they are different, check override flag - */ - if ((old & NUD_VALID) && - !memcmp(lladdr, neigh->ha, dev->addr_len)) - lladdr = neigh->ha; - } else { - /* No address is supplied; if we know something, - use it, otherwise discard the request. - */ - err = -EINVAL; - if (!(old & NUD_VALID)) - goto out; - lladdr = neigh->ha; - } - - if (new & NUD_CONNECTED) - neigh->confirmed = jiffies; - neigh->updated = jiffies; - - /* If entry was valid and address is not changed, - do not change entry state, if new one is STALE. - */ - err = 0; - update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER; - if (old & NUD_VALID) { - if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) { - update_isrouter = 0; - if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) && - (old & NUD_CONNECTED)) { - lladdr = neigh->ha; - new = NUD_STALE; - } else - goto out; - } else { - if (lladdr == neigh->ha && new == NUD_STALE && - ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) || - (old & NUD_CONNECTED)) - ) - new = old; - } - } - - if (new != old) { - neigh_del_timer(neigh); - if (new & NUD_IN_TIMER) - neigh_add_timer(neigh, (jiffies + - ((new & NUD_REACHABLE) ? - neigh->parms->reachable_time : - 0))); - neigh->nud_state = new; - } - - if (lladdr != neigh->ha) { - memcpy(&neigh->ha, lladdr, dev->addr_len); - neigh_update_hhs(neigh); - if (!(new & NUD_CONNECTED)) - neigh->confirmed = jiffies - - (neigh->parms->base_reachable_time << 1); - notify = 1; - } - if (new == old) - goto out; - if (new & NUD_CONNECTED) - neigh_connect(neigh); - else - neigh_suspect(neigh); - if (!(old & NUD_VALID)) { - struct sk_buff *skb; - - /* Again: avoid dead loop if something went wrong */ - - while (neigh->nud_state & NUD_VALID && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - struct neighbour *n1 = neigh; - write_unlock_bh(&neigh->lock); - /* On shaper/eql skb->dst->neighbour != neigh :( */ - if (skb->dst && skb->dst->neighbour) - n1 = skb->dst->neighbour; - n1->output(skb); - write_lock_bh(&neigh->lock); - } - skb_queue_purge(&neigh->arp_queue); - } -out: - if (update_isrouter) { - neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ? - (neigh->flags | NTF_ROUTER) : - (neigh->flags & ~NTF_ROUTER); - } - write_unlock_bh(&neigh->lock); - - if (notify) - neigh_update_notify(neigh); - - return err; -} -EXPORT_SYMBOL(neigh_update); - -struct neighbour *neigh_event_ns(struct neigh_table *tbl, - u8 *lladdr, void *saddr, - struct net_device *dev) -{ - struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev, - lladdr || !dev->addr_len); - if (neigh) - neigh_update(neigh, lladdr, NUD_STALE, - NEIGH_UPDATE_F_OVERRIDE); - return neigh; -} -EXPORT_SYMBOL(neigh_event_ns); - -static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, - __be16 protocol) -{ - struct hh_cache *hh; - struct net_device *dev = dst->dev; - - for (hh = n->hh; hh; hh = hh->hh_next) - if (hh->hh_type == protocol) - break; - - if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { - seqlock_init(&hh->hh_lock); - hh->hh_type = protocol; - atomic_set(&hh->hh_refcnt, 0); - hh->hh_next = NULL; - - if (dev->header_ops->cache(n, hh)) { - kfree(hh); - hh = NULL; - } else { - atomic_inc(&hh->hh_refcnt); - hh->hh_next = n->hh; - n->hh = hh; - if (n->nud_state & NUD_CONNECTED) - hh->hh_output = n->ops->hh_output; - else - hh->hh_output = n->ops->output; - } - } - if (hh) { - atomic_inc(&hh->hh_refcnt); - dst->hh = hh; - } -} - -/* This function can be used in contexts, where only old dev_queue_xmit - worked, f.e. if you want to override normal output path (eql, shaper), - but resolution is not made yet. - */ - -int neigh_compat_output(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - - __skb_pull(skb, skb_network_offset(skb)); - - if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, - skb->len) < 0 && - dev->header_ops->rebuild(skb)) - return 0; - - return dev_queue_xmit(skb); -} -EXPORT_SYMBOL(neigh_compat_output); - -/* Slow and careful. */ - -int neigh_resolve_output(struct sk_buff *skb) -{ - struct dst_entry *dst = skb->dst; - struct neighbour *neigh; - int rc = 0; - - if (!dst || !(neigh = dst->neighbour)) - goto discard; - - __skb_pull(skb, skb_network_offset(skb)); - - if (!neigh_event_send(neigh, skb)) { - int err; - struct net_device *dev = neigh->dev; - if (dev->header_ops->cache && !dst->hh) { - write_lock_bh(&neigh->lock); - if (!dst->hh) - neigh_hh_init(neigh, dst, dst->ops->protocol); - err = dev_hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); - write_unlock_bh(&neigh->lock); - } else { - read_lock_bh(&neigh->lock); - err = dev_hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); - read_unlock_bh(&neigh->lock); - } - if (err >= 0) - rc = neigh->ops->queue_xmit(skb); - else - goto out_kfree_skb; - } -out: - return rc; -discard: - NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n", - dst, dst ? dst->neighbour : NULL); -out_kfree_skb: - rc = -EINVAL; - kfree_skb(skb); - goto out; -} -EXPORT_SYMBOL(neigh_resolve_output); - -/* As fast as possible without hh cache */ - -int neigh_connected_output(struct sk_buff *skb) -{ - int err; - struct dst_entry *dst = skb->dst; - struct neighbour *neigh = dst->neighbour; - struct net_device *dev = neigh->dev; - - __skb_pull(skb, skb_network_offset(skb)); - - read_lock_bh(&neigh->lock); - err = dev_hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); - read_unlock_bh(&neigh->lock); - if (err >= 0) - err = neigh->ops->queue_xmit(skb); - else { - err = -EINVAL; - kfree_skb(skb); - } - return err; -} -EXPORT_SYMBOL(neigh_connected_output); - -static void neigh_proxy_process(unsigned long arg) -{ - struct neigh_table *tbl = (struct neigh_table *)arg; - long sched_next = 0; - unsigned long now = jiffies; - struct sk_buff *skb, *n; - - spin_lock(&tbl->proxy_queue.lock); - - skb_queue_walk_safe(&tbl->proxy_queue, skb, n) { - long tdif = NEIGH_CB(skb)->sched_next - now; - - if (tdif <= 0) { - struct net_device *dev = skb->dev; - __skb_unlink(skb, &tbl->proxy_queue); - if (tbl->proxy_redo && netif_running(dev)) - tbl->proxy_redo(skb); - else - kfree_skb(skb); - - dev_put(dev); - } else if (!sched_next || tdif < sched_next) - sched_next = tdif; - } - del_timer(&tbl->proxy_timer); - if (sched_next) - mod_timer(&tbl->proxy_timer, jiffies + sched_next); - spin_unlock(&tbl->proxy_queue.lock); -} - -void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, - struct sk_buff *skb) -{ - unsigned long now = jiffies; - unsigned long sched_next = now + (net_random() % p->proxy_delay); - - if (tbl->proxy_queue.qlen > p->proxy_qlen) { - kfree_skb(skb); - return; - } - - NEIGH_CB(skb)->sched_next = sched_next; - NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED; - - spin_lock(&tbl->proxy_queue.lock); - if (del_timer(&tbl->proxy_timer)) { - if (time_before(tbl->proxy_timer.expires, sched_next)) - sched_next = tbl->proxy_timer.expires; - } - dst_release(skb->dst); - skb->dst = NULL; - dev_hold(skb->dev); - __skb_queue_tail(&tbl->proxy_queue, skb); - mod_timer(&tbl->proxy_timer, sched_next); - spin_unlock(&tbl->proxy_queue.lock); -} -EXPORT_SYMBOL(pneigh_enqueue); - -static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, - struct net *net, int ifindex) -{ - struct neigh_parms *p; - - for (p = &tbl->parms; p; p = p->next) { - if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) || - (!p->dev && !ifindex)) - return p; - } - - return NULL; -} - -struct neigh_parms *neigh_parms_alloc(struct net_device *dev, - struct neigh_table *tbl) -{ - struct neigh_parms *p, *ref; - struct net *net = dev_net(dev); - const struct net_device_ops *ops = dev->netdev_ops; - - ref = lookup_neigh_params(tbl, net, 0); - if (!ref) - return NULL; - - p = kmemdup(ref, sizeof(*p), GFP_KERNEL); - if (p) { - p->tbl = tbl; - atomic_set(&p->refcnt, 1); - p->reachable_time = - neigh_rand_reach_time(p->base_reachable_time); - - if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) { - kfree(p); - return NULL; - } - - dev_hold(dev); - p->dev = dev; - write_pnet(&p->net, hold_net(net)); - p->sysctl_table = NULL; - write_lock_bh(&tbl->lock); - p->next = tbl->parms.next; - tbl->parms.next = p; - write_unlock_bh(&tbl->lock); - } - return p; -} -EXPORT_SYMBOL(neigh_parms_alloc); - -static void neigh_rcu_free_parms(struct rcu_head *head) -{ - struct neigh_parms *parms = - container_of(head, struct neigh_parms, rcu_head); - - neigh_parms_put(parms); -} - -void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) -{ - struct neigh_parms **p; - - if (!parms || parms == &tbl->parms) - return; - write_lock_bh(&tbl->lock); - for (p = &tbl->parms.next; *p; p = &(*p)->next) { - if (*p == parms) { - *p = parms->next; - parms->dead = 1; - write_unlock_bh(&tbl->lock); - if (parms->dev) - dev_put(parms->dev); - call_rcu(&parms->rcu_head, neigh_rcu_free_parms); - return; - } - } - write_unlock_bh(&tbl->lock); - NEIGH_PRINTK1("neigh_parms_release: not found\n"); -} -EXPORT_SYMBOL(neigh_parms_release); - -static void neigh_parms_destroy(struct neigh_parms *parms) -{ - release_net(neigh_parms_net(parms)); - kfree(parms); -} - -static struct lock_class_key neigh_table_proxy_queue_class; - -void neigh_table_init_no_netlink(struct neigh_table *tbl) -{ - unsigned long now = jiffies; - unsigned long phsize; - - write_pnet(&tbl->parms.net, &init_net); - atomic_set(&tbl->parms.refcnt, 1); - tbl->parms.reachable_time = - neigh_rand_reach_time(tbl->parms.base_reachable_time); - - if (!tbl->kmem_cachep) - tbl->kmem_cachep = - kmem_cache_create(tbl->id, tbl->entry_size, 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL); - tbl->stats = alloc_percpu(struct neigh_statistics); - if (!tbl->stats) - panic("cannot create neighbour cache statistics"); - -#ifdef CONFIG_PROC_FS - if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat, - &neigh_stat_seq_fops, tbl)) - panic("cannot create neighbour proc dir entry"); -#endif - - tbl->hash_mask = 1; - tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1); - - phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *); - tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL); - - if (!tbl->hash_buckets || !tbl->phash_buckets) - panic("cannot allocate neighbour cache hashes"); - - get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); - - rwlock_init(&tbl->lock); - setup_timer(&tbl->gc_timer, neigh_periodic_timer, (unsigned long)tbl); - tbl->gc_timer.expires = now + 1; - add_timer(&tbl->gc_timer); - - setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); - skb_queue_head_init_class(&tbl->proxy_queue, - &neigh_table_proxy_queue_class); - - tbl->last_flush = now; - tbl->last_rand = now + tbl->parms.reachable_time * 20; -} -EXPORT_SYMBOL(neigh_table_init_no_netlink); - -void neigh_table_init(struct neigh_table *tbl) -{ - struct neigh_table *tmp; - - neigh_table_init_no_netlink(tbl); - write_lock(&neigh_tbl_lock); - for (tmp = neigh_tables; tmp; tmp = tmp->next) { - if (tmp->family == tbl->family) - break; - } - tbl->next = neigh_tables; - neigh_tables = tbl; - write_unlock(&neigh_tbl_lock); - - if (unlikely(tmp)) { - printk(KERN_ERR "NEIGH: Registering multiple tables for " - "family %d\n", tbl->family); - dump_stack(); - } -} -EXPORT_SYMBOL(neigh_table_init); - -int neigh_table_clear(struct neigh_table *tbl) -{ - struct neigh_table **tp; - - /* It is not clean... Fix it to unload IPv6 module safely */ - del_timer_sync(&tbl->gc_timer); - del_timer_sync(&tbl->proxy_timer); - pneigh_queue_purge(&tbl->proxy_queue); - neigh_ifdown(tbl, NULL); - if (atomic_read(&tbl->entries)) - printk(KERN_CRIT "neighbour leakage\n"); - write_lock(&neigh_tbl_lock); - for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { - if (*tp == tbl) { - *tp = tbl->next; - break; - } - } - write_unlock(&neigh_tbl_lock); - - neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1); - tbl->hash_buckets = NULL; - - kfree(tbl->phash_buckets); - tbl->phash_buckets = NULL; - - remove_proc_entry(tbl->id, init_net.proc_net_stat); - - free_percpu(tbl->stats); - tbl->stats = NULL; - - kmem_cache_destroy(tbl->kmem_cachep); - tbl->kmem_cachep = NULL; - - return 0; -} -EXPORT_SYMBOL(neigh_table_clear); - -static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - struct ndmsg *ndm; - struct nlattr *dst_attr; - struct neigh_table *tbl; - struct net_device *dev = NULL; - int err = -EINVAL; - - if (nlmsg_len(nlh) < sizeof(*ndm)) - goto out; - - dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST); - if (dst_attr == NULL) - goto out; - - ndm = nlmsg_data(nlh); - if (ndm->ndm_ifindex) { - dev = dev_get_by_index(net, ndm->ndm_ifindex); - if (dev == NULL) { - err = -ENODEV; - goto out; - } - } - - read_lock(&neigh_tbl_lock); - for (tbl = neigh_tables; tbl; tbl = tbl->next) { - struct neighbour *neigh; - - if (tbl->family != ndm->ndm_family) - continue; - read_unlock(&neigh_tbl_lock); - - if (nla_len(dst_attr) < tbl->key_len) - goto out_dev_put; - - if (ndm->ndm_flags & NTF_PROXY) { - err = pneigh_delete(tbl, net, nla_data(dst_attr), dev); - goto out_dev_put; - } - - if (dev == NULL) - goto out_dev_put; - - neigh = neigh_lookup(tbl, nla_data(dst_attr), dev); - if (neigh == NULL) { - err = -ENOENT; - goto out_dev_put; - } - - err = neigh_update(neigh, NULL, NUD_FAILED, - NEIGH_UPDATE_F_OVERRIDE | - NEIGH_UPDATE_F_ADMIN); - neigh_release(neigh); - goto out_dev_put; - } - read_unlock(&neigh_tbl_lock); - err = -EAFNOSUPPORT; - -out_dev_put: - if (dev) - dev_put(dev); -out: - return err; -} - -static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - struct ndmsg *ndm; - struct nlattr *tb[NDA_MAX+1]; - struct neigh_table *tbl; - struct net_device *dev = NULL; - int err; - - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); - if (err < 0) - goto out; - - err = -EINVAL; - if (tb[NDA_DST] == NULL) - goto out; - - ndm = nlmsg_data(nlh); - if (ndm->ndm_ifindex) { - dev = dev_get_by_index(net, ndm->ndm_ifindex); - if (dev == NULL) { - err = -ENODEV; - goto out; - } - - if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) - goto out_dev_put; - } - - read_lock(&neigh_tbl_lock); - for (tbl = neigh_tables; tbl; tbl = tbl->next) { - int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; - struct neighbour *neigh; - void *dst, *lladdr; - - if (tbl->family != ndm->ndm_family) - continue; - read_unlock(&neigh_tbl_lock); - - if (nla_len(tb[NDA_DST]) < tbl->key_len) - goto out_dev_put; - dst = nla_data(tb[NDA_DST]); - lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; - - if (ndm->ndm_flags & NTF_PROXY) { - struct pneigh_entry *pn; - - err = -ENOBUFS; - pn = pneigh_lookup(tbl, net, dst, dev, 1); - if (pn) { - pn->flags = ndm->ndm_flags; - err = 0; - } - goto out_dev_put; - } - - if (dev == NULL) - goto out_dev_put; - - neigh = neigh_lookup(tbl, dst, dev); - if (neigh == NULL) { - if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { - err = -ENOENT; - goto out_dev_put; - } - - neigh = __neigh_lookup_errno(tbl, dst, dev); - if (IS_ERR(neigh)) { - err = PTR_ERR(neigh); - goto out_dev_put; - } - } else { - if (nlh->nlmsg_flags & NLM_F_EXCL) { - err = -EEXIST; - neigh_release(neigh); - goto out_dev_put; - } - - if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) - flags &= ~NEIGH_UPDATE_F_OVERRIDE; - } - - err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); - neigh_release(neigh); - goto out_dev_put; - } - - read_unlock(&neigh_tbl_lock); - err = -EAFNOSUPPORT; - -out_dev_put: - if (dev) - dev_put(dev); -out: - return err; -} - -static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) -{ - struct nlattr *nest; - - nest = nla_nest_start(skb, NDTA_PARMS); - if (nest == NULL) - return -ENOBUFS; - - if (parms->dev) - NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex); - - NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)); - NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len); - NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen); - NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes); - NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes); - NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes); - NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time); - NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME, - parms->base_reachable_time); - NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime); - NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time); - NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time); - NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay); - NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay); - NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime); - - return nla_nest_end(skb, nest); - -nla_put_failure: - nla_nest_cancel(skb, nest); - return -EMSGSIZE; -} - -static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, - u32 pid, u32 seq, int type, int flags) -{ - struct nlmsghdr *nlh; - struct ndtmsg *ndtmsg; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndtmsg = nlmsg_data(nlh); - - read_lock_bh(&tbl->lock); - ndtmsg->ndtm_family = tbl->family; - ndtmsg->ndtm_pad1 = 0; - ndtmsg->ndtm_pad2 = 0; - - NLA_PUT_STRING(skb, NDTA_NAME, tbl->id); - NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval); - NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1); - NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2); - NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3); - - { - unsigned long now = jiffies; - unsigned int flush_delta = now - tbl->last_flush; - unsigned int rand_delta = now - tbl->last_rand; - - struct ndt_config ndc = { - .ndtc_key_len = tbl->key_len, - .ndtc_entry_size = tbl->entry_size, - .ndtc_entries = atomic_read(&tbl->entries), - .ndtc_last_flush = jiffies_to_msecs(flush_delta), - .ndtc_last_rand = jiffies_to_msecs(rand_delta), - .ndtc_hash_rnd = tbl->hash_rnd, - .ndtc_hash_mask = tbl->hash_mask, - .ndtc_hash_chain_gc = tbl->hash_chain_gc, - .ndtc_proxy_qlen = tbl->proxy_queue.qlen, - }; - - NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc); - } - - { - int cpu; - struct ndt_stats ndst; - - memset(&ndst, 0, sizeof(ndst)); - - for_each_possible_cpu(cpu) { - struct neigh_statistics *st; - - st = per_cpu_ptr(tbl->stats, cpu); - ndst.ndts_allocs += st->allocs; - ndst.ndts_destroys += st->destroys; - ndst.ndts_hash_grows += st->hash_grows; - ndst.ndts_res_failed += st->res_failed; - ndst.ndts_lookups += st->lookups; - ndst.ndts_hits += st->hits; - ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast; - ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast; - ndst.ndts_periodic_gc_runs += st->periodic_gc_runs; - ndst.ndts_forced_gc_runs += st->forced_gc_runs; - } - - NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst); - } - - BUG_ON(tbl->parms.dev); - if (neightbl_fill_parms(skb, &tbl->parms) < 0) - goto nla_put_failure; - - read_unlock_bh(&tbl->lock); - return nlmsg_end(skb, nlh); - -nla_put_failure: - read_unlock_bh(&tbl->lock); - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int neightbl_fill_param_info(struct sk_buff *skb, - struct neigh_table *tbl, - struct neigh_parms *parms, - u32 pid, u32 seq, int type, - unsigned int flags) -{ - struct ndtmsg *ndtmsg; - struct nlmsghdr *nlh; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndtmsg = nlmsg_data(nlh); - - read_lock_bh(&tbl->lock); - ndtmsg->ndtm_family = tbl->family; - ndtmsg->ndtm_pad1 = 0; - ndtmsg->ndtm_pad2 = 0; - - if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 || - neightbl_fill_parms(skb, parms) < 0) - goto errout; - - read_unlock_bh(&tbl->lock); - return nlmsg_end(skb, nlh); -errout: - read_unlock_bh(&tbl->lock); - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = { - [NDTA_NAME] = { .type = NLA_STRING }, - [NDTA_THRESH1] = { .type = NLA_U32 }, - [NDTA_THRESH2] = { .type = NLA_U32 }, - [NDTA_THRESH3] = { .type = NLA_U32 }, - [NDTA_GC_INTERVAL] = { .type = NLA_U64 }, - [NDTA_PARMS] = { .type = NLA_NESTED }, -}; - -static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { - [NDTPA_IFINDEX] = { .type = NLA_U32 }, - [NDTPA_QUEUE_LEN] = { .type = NLA_U32 }, - [NDTPA_PROXY_QLEN] = { .type = NLA_U32 }, - [NDTPA_APP_PROBES] = { .type = NLA_U32 }, - [NDTPA_UCAST_PROBES] = { .type = NLA_U32 }, - [NDTPA_MCAST_PROBES] = { .type = NLA_U32 }, - [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 }, - [NDTPA_GC_STALETIME] = { .type = NLA_U64 }, - [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 }, - [NDTPA_RETRANS_TIME] = { .type = NLA_U64 }, - [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 }, - [NDTPA_PROXY_DELAY] = { .type = NLA_U64 }, - [NDTPA_LOCKTIME] = { .type = NLA_U64 }, -}; - -static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - struct neigh_table *tbl; - struct ndtmsg *ndtmsg; - struct nlattr *tb[NDTA_MAX+1]; - int err; - - err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, - nl_neightbl_policy); - if (err < 0) - goto errout; - - if (tb[NDTA_NAME] == NULL) { - err = -EINVAL; - goto errout; - } - - ndtmsg = nlmsg_data(nlh); - read_lock(&neigh_tbl_lock); - for (tbl = neigh_tables; tbl; tbl = tbl->next) { - if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) - continue; - - if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) - break; - } - - if (tbl == NULL) { - err = -ENOENT; - goto errout_locked; - } - - /* - * We acquire tbl->lock to be nice to the periodic timers and - * make sure they always see a consistent set of values. - */ - write_lock_bh(&tbl->lock); - - if (tb[NDTA_PARMS]) { - struct nlattr *tbp[NDTPA_MAX+1]; - struct neigh_parms *p; - int i, ifindex = 0; - - err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], - nl_ntbl_parm_policy); - if (err < 0) - goto errout_tbl_lock; - - if (tbp[NDTPA_IFINDEX]) - ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); - - p = lookup_neigh_params(tbl, net, ifindex); - if (p == NULL) { - err = -ENOENT; - goto errout_tbl_lock; - } - - for (i = 1; i <= NDTPA_MAX; i++) { - if (tbp[i] == NULL) - continue; - - switch (i) { - case NDTPA_QUEUE_LEN: - p->queue_len = nla_get_u32(tbp[i]); - break; - case NDTPA_PROXY_QLEN: - p->proxy_qlen = nla_get_u32(tbp[i]); - break; - case NDTPA_APP_PROBES: - p->app_probes = nla_get_u32(tbp[i]); - break; - case NDTPA_UCAST_PROBES: - p->ucast_probes = nla_get_u32(tbp[i]); - break; - case NDTPA_MCAST_PROBES: - p->mcast_probes = nla_get_u32(tbp[i]); - break; - case NDTPA_BASE_REACHABLE_TIME: - p->base_reachable_time = nla_get_msecs(tbp[i]); - break; - case NDTPA_GC_STALETIME: - p->gc_staletime = nla_get_msecs(tbp[i]); - break; - case NDTPA_DELAY_PROBE_TIME: - p->delay_probe_time = nla_get_msecs(tbp[i]); - break; - case NDTPA_RETRANS_TIME: - p->retrans_time = nla_get_msecs(tbp[i]); - break; - case NDTPA_ANYCAST_DELAY: - p->anycast_delay = nla_get_msecs(tbp[i]); - break; - case NDTPA_PROXY_DELAY: - p->proxy_delay = nla_get_msecs(tbp[i]); - break; - case NDTPA_LOCKTIME: - p->locktime = nla_get_msecs(tbp[i]); - break; - } - } - } - - if (tb[NDTA_THRESH1]) - tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]); - - if (tb[NDTA_THRESH2]) - tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]); - - if (tb[NDTA_THRESH3]) - tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]); - - if (tb[NDTA_GC_INTERVAL]) - tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]); - - err = 0; - -errout_tbl_lock: - write_unlock_bh(&tbl->lock); -errout_locked: - read_unlock(&neigh_tbl_lock); -errout: - return err; -} - -static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int family, tidx, nidx = 0; - int tbl_skip = cb->args[0]; - int neigh_skip = cb->args[1]; - struct neigh_table *tbl; - - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; - - read_lock(&neigh_tbl_lock); - for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) { - struct neigh_parms *p; - - if (tidx < tbl_skip || (family && tbl->family != family)) - continue; - - if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL, - NLM_F_MULTI) <= 0) - break; - - for (nidx = 0, p = tbl->parms.next; p; p = p->next) { - if (!net_eq(neigh_parms_net(p), net)) - continue; - - if (nidx < neigh_skip) - goto next; - - if (neightbl_fill_param_info(skb, tbl, p, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGHTBL, - NLM_F_MULTI) <= 0) - goto out; - next: - nidx++; - } - - neigh_skip = 0; - } -out: - read_unlock(&neigh_tbl_lock); - cb->args[0] = tidx; - cb->args[1] = nidx; - - return skb->len; -} - -static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh, - u32 pid, u32 seq, int type, unsigned int flags) -{ - unsigned long now = jiffies; - struct nda_cacheinfo ci; - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = neigh->ops->family; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = neigh->flags; - ndm->ndm_type = neigh->type; - ndm->ndm_ifindex = neigh->dev->ifindex; - - NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key); - - read_lock_bh(&neigh->lock); - ndm->ndm_state = neigh->nud_state; - if ((neigh->nud_state & NUD_VALID) && - nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) { - read_unlock_bh(&neigh->lock); - goto nla_put_failure; - } - - ci.ndm_used = jiffies_to_clock_t(now - neigh->used); - ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed); - ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated); - ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1; - read_unlock_bh(&neigh->lock); - - NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes)); - NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci); - - return nlmsg_end(skb, nlh); - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static void neigh_update_notify(struct neighbour *neigh) -{ - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); - __neigh_notify(neigh, RTM_NEWNEIGH, 0); -} - -static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net * net = sock_net(skb->sk); - struct neighbour *n; - int rc, h, s_h = cb->args[1]; - int idx, s_idx = idx = cb->args[2]; - - read_lock_bh(&tbl->lock); - for (h = 0; h <= tbl->hash_mask; h++) { - if (h < s_h) - continue; - if (h > s_h) - s_idx = 0; - for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) { - if (dev_net(n->dev) != net) - continue; - if (idx < s_idx) - goto next; - if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGH, - NLM_F_MULTI) <= 0) { - read_unlock_bh(&tbl->lock); - rc = -1; - goto out; - } - next: - idx++; - } - } - read_unlock_bh(&tbl->lock); - rc = skb->len; -out: - cb->args[1] = h; - cb->args[2] = idx; - return rc; -} - -static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct neigh_table *tbl; - int t, family, s_t; - - read_lock(&neigh_tbl_lock); - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; - s_t = cb->args[0]; - - for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { - if (t < s_t || (family && tbl->family != family)) - continue; - if (t > s_t) - memset(&cb->args[1], 0, sizeof(cb->args) - - sizeof(cb->args[0])); - if (neigh_dump_table(tbl, skb, cb) < 0) - break; - } - read_unlock(&neigh_tbl_lock); - - cb->args[0] = t; - return skb->len; -} - -void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie) -{ - int chain; - - read_lock_bh(&tbl->lock); - for (chain = 0; chain <= tbl->hash_mask; chain++) { - struct neighbour *n; - - for (n = tbl->hash_buckets[chain]; n; n = n->next) - cb(n, cookie); - } - read_unlock_bh(&tbl->lock); -} -EXPORT_SYMBOL(neigh_for_each); - -/* The tbl->lock must be held as a writer and BH disabled. */ -void __neigh_for_each_release(struct neigh_table *tbl, - int (*cb)(struct neighbour *)) -{ - int chain; - - for (chain = 0; chain <= tbl->hash_mask; chain++) { - struct neighbour *n, **np; - - np = &tbl->hash_buckets[chain]; - while ((n = *np) != NULL) { - int release; - - write_lock(&n->lock); - release = cb(n); - if (release) { - *np = n->next; - n->dead = 1; - } else - np = &n->next; - write_unlock(&n->lock); - if (release) - neigh_cleanup_and_release(n); - } - } -} -EXPORT_SYMBOL(__neigh_for_each_release); - -#ifdef CONFIG_PROC_FS - -static struct neighbour *neigh_get_first(struct seq_file *seq) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_table *tbl = state->tbl; - struct neighbour *n = NULL; - int bucket = state->bucket; - - state->flags &= ~NEIGH_SEQ_IS_PNEIGH; - for (bucket = 0; bucket <= tbl->hash_mask; bucket++) { - n = tbl->hash_buckets[bucket]; - - while (n) { - if (!net_eq(dev_net(n->dev), net)) - goto next; - if (state->neigh_sub_iter) { - loff_t fakep = 0; - void *v; - - v = state->neigh_sub_iter(state, n, &fakep); - if (!v) - goto next; - } - if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) - break; - if (n->nud_state & ~NUD_NOARP) - break; - next: - n = n->next; - } - - if (n) - break; - } - state->bucket = bucket; - - return n; -} - -static struct neighbour *neigh_get_next(struct seq_file *seq, - struct neighbour *n, - loff_t *pos) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_table *tbl = state->tbl; - - if (state->neigh_sub_iter) { - void *v = state->neigh_sub_iter(state, n, pos); - if (v) - return n; - } - n = n->next; - - while (1) { - while (n) { - if (!net_eq(dev_net(n->dev), net)) - goto next; - if (state->neigh_sub_iter) { - void *v = state->neigh_sub_iter(state, n, pos); - if (v) - return n; - goto next; - } - if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) - break; - - if (n->nud_state & ~NUD_NOARP) - break; - next: - n = n->next; - } - - if (n) - break; - - if (++state->bucket > tbl->hash_mask) - break; - - n = tbl->hash_buckets[state->bucket]; - } - - if (n && pos) - --(*pos); - return n; -} - -static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct neighbour *n = neigh_get_first(seq); - - if (n) { - --(*pos); - while (*pos) { - n = neigh_get_next(seq, n, pos); - if (!n) - break; - } - } - return *pos ? NULL : n; -} - -static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_table *tbl = state->tbl; - struct pneigh_entry *pn = NULL; - int bucket = state->bucket; - - state->flags |= NEIGH_SEQ_IS_PNEIGH; - for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { - pn = tbl->phash_buckets[bucket]; - while (pn && !net_eq(pneigh_net(pn), net)) - pn = pn->next; - if (pn) - break; - } - state->bucket = bucket; - - return pn; -} - -static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, - struct pneigh_entry *pn, - loff_t *pos) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_table *tbl = state->tbl; - - pn = pn->next; - while (!pn) { - if (++state->bucket > PNEIGH_HASHMASK) - break; - pn = tbl->phash_buckets[state->bucket]; - while (pn && !net_eq(pneigh_net(pn), net)) - pn = pn->next; - if (pn) - break; - } - - if (pn && pos) - --(*pos); - - return pn; -} - -static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct pneigh_entry *pn = pneigh_get_first(seq); - - if (pn) { - --(*pos); - while (*pos) { - pn = pneigh_get_next(seq, pn, pos); - if (!pn) - break; - } - } - return *pos ? NULL : pn; -} - -static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos) -{ - struct neigh_seq_state *state = seq->private; - void *rc; - loff_t idxpos = *pos; - - rc = neigh_get_idx(seq, &idxpos); - if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY)) - rc = pneigh_get_idx(seq, &idxpos); - - return rc; -} - -void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags) - __acquires(tbl->lock) -{ - struct neigh_seq_state *state = seq->private; - - state->tbl = tbl; - state->bucket = 0; - state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH); - - read_lock_bh(&tbl->lock); - - return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN; -} -EXPORT_SYMBOL(neigh_seq_start); - -void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct neigh_seq_state *state; - void *rc; - - if (v == SEQ_START_TOKEN) { - rc = neigh_get_first(seq); - goto out; - } - - state = seq->private; - if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) { - rc = neigh_get_next(seq, v, NULL); - if (rc) - goto out; - if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY)) - rc = pneigh_get_first(seq); - } else { - BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY); - rc = pneigh_get_next(seq, v, NULL); - } -out: - ++(*pos); - return rc; -} -EXPORT_SYMBOL(neigh_seq_next); - -void neigh_seq_stop(struct seq_file *seq, void *v) - __releases(tbl->lock) -{ - struct neigh_seq_state *state = seq->private; - struct neigh_table *tbl = state->tbl; - - read_unlock_bh(&tbl->lock); -} -EXPORT_SYMBOL(neigh_seq_stop); - -/* statistics via seq_file */ - -static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct proc_dir_entry *pde = seq->private; - struct neigh_table *tbl = pde->data; - int cpu; - - if (*pos == 0) - return SEQ_START_TOKEN; - - for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) { - if (!cpu_possible(cpu)) - continue; - *pos = cpu+1; - return per_cpu_ptr(tbl->stats, cpu); - } - return NULL; -} - -static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct proc_dir_entry *pde = seq->private; - struct neigh_table *tbl = pde->data; - int cpu; - - for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { - if (!cpu_possible(cpu)) - continue; - *pos = cpu+1; - return per_cpu_ptr(tbl->stats, cpu); - } - return NULL; -} - -static void neigh_stat_seq_stop(struct seq_file *seq, void *v) -{ - -} - -static int neigh_stat_seq_show(struct seq_file *seq, void *v) -{ - struct proc_dir_entry *pde = seq->private; - struct neigh_table *tbl = pde->data; - struct neigh_statistics *st = v; - - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards\n"); - return 0; - } - - seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " - "%08lx %08lx %08lx %08lx %08lx\n", - atomic_read(&tbl->entries), - - st->allocs, - st->destroys, - st->hash_grows, - - st->lookups, - st->hits, - - st->res_failed, - - st->rcv_probes_mcast, - st->rcv_probes_ucast, - - st->periodic_gc_runs, - st->forced_gc_runs, - st->unres_discards - ); - - return 0; -} - -static const struct seq_operations neigh_stat_seq_ops = { - .start = neigh_stat_seq_start, - .next = neigh_stat_seq_next, - .stop = neigh_stat_seq_stop, - .show = neigh_stat_seq_show, -}; - -static int neigh_stat_seq_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &neigh_stat_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE(inode); - } - return ret; -}; - -static const struct file_operations neigh_stat_seq_fops = { - .owner = THIS_MODULE, - .open = neigh_stat_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -#endif /* CONFIG_PROC_FS */ - -static inline size_t neigh_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct ndmsg)) - + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ - + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ - + nla_total_size(sizeof(struct nda_cacheinfo)) - + nla_total_size(4); /* NDA_PROBES */ -} - -static void __neigh_notify(struct neighbour *n, int type, int flags) -{ - struct net *net = dev_net(n->dev); - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC); - if (skb == NULL) - goto errout; - - err = neigh_fill_info(skb, n, 0, 0, type, flags); - if (err < 0) { - /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); -} - -#ifdef CONFIG_ARPD -void neigh_app_ns(struct neighbour *n) -{ - __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST); -} -EXPORT_SYMBOL(neigh_app_ns); -#endif /* CONFIG_ARPD */ - -#ifdef CONFIG_SYSCTL - -static struct neigh_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table neigh_vars[__NET_NEIGH_MAX]; - char *dev_name; -} neigh_sysctl_template __read_mostly = { - .neigh_vars = { - { - .ctl_name = NET_NEIGH_MCAST_SOLICIT, - .procname = "mcast_solicit", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .ctl_name = NET_NEIGH_UCAST_SOLICIT, - .procname = "ucast_solicit", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .ctl_name = NET_NEIGH_APP_SOLICIT, - .procname = "app_solicit", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "retrans_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - { - .ctl_name = NET_NEIGH_REACHABLE_TIME, - .procname = "base_reachable_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - .strategy = sysctl_jiffies, - }, - { - .ctl_name = NET_NEIGH_DELAY_PROBE_TIME, - .procname = "delay_first_probe_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - .strategy = sysctl_jiffies, - }, - { - .ctl_name = NET_NEIGH_GC_STALE_TIME, - .procname = "gc_stale_time", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - .strategy = sysctl_jiffies, - }, - { - .ctl_name = NET_NEIGH_UNRES_QLEN, - .procname = "unres_qlen", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .ctl_name = NET_NEIGH_PROXY_QLEN, - .procname = "proxy_qlen", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "anycast_delay", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - { - .procname = "proxy_delay", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - { - .procname = "locktime", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_userhz_jiffies, - }, - { - .ctl_name = NET_NEIGH_RETRANS_TIME_MS, - .procname = "retrans_time_ms", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - .strategy = sysctl_ms_jiffies, - }, - { - .ctl_name = NET_NEIGH_REACHABLE_TIME_MS, - .procname = "base_reachable_time_ms", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - .strategy = sysctl_ms_jiffies, - }, - { - .ctl_name = NET_NEIGH_GC_INTERVAL, - .procname = "gc_interval", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - .strategy = sysctl_jiffies, - }, - { - .ctl_name = NET_NEIGH_GC_THRESH1, - .procname = "gc_thresh1", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .ctl_name = NET_NEIGH_GC_THRESH2, - .procname = "gc_thresh2", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .ctl_name = NET_NEIGH_GC_THRESH3, - .procname = "gc_thresh3", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - {}, - }, -}; - -int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, - int p_id, int pdev_id, char *p_name, - proc_handler *handler, ctl_handler *strategy) -{ - struct neigh_sysctl_table *t; - const char *dev_name_source = NULL; - -#define NEIGH_CTL_PATH_ROOT 0 -#define NEIGH_CTL_PATH_PROTO 1 -#define NEIGH_CTL_PATH_NEIGH 2 -#define NEIGH_CTL_PATH_DEV 3 - - struct ctl_path neigh_path[] = { - { .procname = "net", .ctl_name = CTL_NET, }, - { .procname = "proto", .ctl_name = 0, }, - { .procname = "neigh", .ctl_name = 0, }, - { .procname = "default", .ctl_name = NET_PROTO_CONF_DEFAULT, }, - { }, - }; - - t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); - if (!t) - goto err; - - t->neigh_vars[0].data = &p->mcast_probes; - t->neigh_vars[1].data = &p->ucast_probes; - t->neigh_vars[2].data = &p->app_probes; - t->neigh_vars[3].data = &p->retrans_time; - t->neigh_vars[4].data = &p->base_reachable_time; - t->neigh_vars[5].data = &p->delay_probe_time; - t->neigh_vars[6].data = &p->gc_staletime; - t->neigh_vars[7].data = &p->queue_len; - t->neigh_vars[8].data = &p->proxy_qlen; - t->neigh_vars[9].data = &p->anycast_delay; - t->neigh_vars[10].data = &p->proxy_delay; - t->neigh_vars[11].data = &p->locktime; - t->neigh_vars[12].data = &p->retrans_time; - t->neigh_vars[13].data = &p->base_reachable_time; - - if (dev) { - dev_name_source = dev->name; - neigh_path[NEIGH_CTL_PATH_DEV].ctl_name = dev->ifindex; - /* Terminate the table early */ - memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14])); - } else { - dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname; - t->neigh_vars[14].data = (int *)(p + 1); - t->neigh_vars[15].data = (int *)(p + 1) + 1; - t->neigh_vars[16].data = (int *)(p + 1) + 2; - t->neigh_vars[17].data = (int *)(p + 1) + 3; - } - - - if (handler || strategy) { - /* RetransTime */ - t->neigh_vars[3].proc_handler = handler; - t->neigh_vars[3].strategy = strategy; - t->neigh_vars[3].extra1 = dev; - if (!strategy) - t->neigh_vars[3].ctl_name = CTL_UNNUMBERED; - /* ReachableTime */ - t->neigh_vars[4].proc_handler = handler; - t->neigh_vars[4].strategy = strategy; - t->neigh_vars[4].extra1 = dev; - if (!strategy) - t->neigh_vars[4].ctl_name = CTL_UNNUMBERED; - /* RetransTime (in milliseconds)*/ - t->neigh_vars[12].proc_handler = handler; - t->neigh_vars[12].strategy = strategy; - t->neigh_vars[12].extra1 = dev; - if (!strategy) - t->neigh_vars[12].ctl_name = CTL_UNNUMBERED; - /* ReachableTime (in milliseconds) */ - t->neigh_vars[13].proc_handler = handler; - t->neigh_vars[13].strategy = strategy; - t->neigh_vars[13].extra1 = dev; - if (!strategy) - t->neigh_vars[13].ctl_name = CTL_UNNUMBERED; - } - - t->dev_name = kstrdup(dev_name_source, GFP_KERNEL); - if (!t->dev_name) - goto free; - - neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name; - neigh_path[NEIGH_CTL_PATH_NEIGH].ctl_name = pdev_id; - neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name; - neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id; - - t->sysctl_header = - register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars); - if (!t->sysctl_header) - goto free_procname; - - p->sysctl_table = t; - return 0; - -free_procname: - kfree(t->dev_name); -free: - kfree(t); -err: - return -ENOBUFS; -} -EXPORT_SYMBOL(neigh_sysctl_register); - -void neigh_sysctl_unregister(struct neigh_parms *p) -{ - if (p->sysctl_table) { - struct neigh_sysctl_table *t = p->sysctl_table; - p->sysctl_table = NULL; - unregister_sysctl_table(t->sysctl_header); - kfree(t->dev_name); - kfree(t); - } -} -EXPORT_SYMBOL(neigh_sysctl_unregister); - -#endif /* CONFIG_SYSCTL */ - -static int __init neigh_init(void) -{ - rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL); - rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL); - rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info); - - rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info); - rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL); - - return 0; -} - -subsys_initcall(neigh_init); - diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/net-sysfs.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/net-sysfs.c.svn-base deleted file mode 100644 index 484f5875..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/net-sysfs.c.svn-base +++ /dev/null @@ -1,540 +0,0 @@ -/* - * net-sysfs.c - network device class and attributes - * - * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/capability.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <net/sock.h> -#include <linux/rtnetlink.h> -#include <linux/wireless.h> -#include <net/iw_handler.h> - -#include "net-sysfs.h" - -#ifdef CONFIG_SYSFS -static const char fmt_hex[] = "%#x\n"; -static const char fmt_long_hex[] = "%#lx\n"; -static const char fmt_dec[] = "%d\n"; -static const char fmt_ulong[] = "%lu\n"; - -static inline int dev_isalive(const struct net_device *dev) -{ - return dev->reg_state <= NETREG_REGISTERED; -} - -/* use same locking rules as GIF* ioctl's */ -static ssize_t netdev_show(const struct device *dev, - struct device_attribute *attr, char *buf, - ssize_t (*format)(const struct net_device *, char *)) -{ - struct net_device *net = to_net_dev(dev); - ssize_t ret = -EINVAL; - - read_lock(&dev_base_lock); - if (dev_isalive(net)) - ret = (*format)(net, buf); - read_unlock(&dev_base_lock); - - return ret; -} - -/* generate a show function for simple field */ -#define NETDEVICE_SHOW(field, format_string) \ -static ssize_t format_##field(const struct net_device *net, char *buf) \ -{ \ - return sprintf(buf, format_string, net->field); \ -} \ -static ssize_t show_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return netdev_show(dev, attr, buf, format_##field); \ -} - - -/* use same locking and permission rules as SIF* ioctl's */ -static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len, - int (*set)(struct net_device *, unsigned long)) -{ - struct net_device *net = to_net_dev(dev); - char *endp; - unsigned long new; - int ret = -EINVAL; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - new = simple_strtoul(buf, &endp, 0); - if (endp == buf) - goto err; - - if (!rtnl_trylock()) - return -ERESTARTSYS; - - if (dev_isalive(net)) { - if ((ret = (*set)(net, new)) == 0) - ret = len; - } - rtnl_unlock(); - err: - return ret; -} - -NETDEVICE_SHOW(dev_id, fmt_hex); -NETDEVICE_SHOW(addr_len, fmt_dec); -NETDEVICE_SHOW(iflink, fmt_dec); -NETDEVICE_SHOW(ifindex, fmt_dec); -NETDEVICE_SHOW(features, fmt_long_hex); -NETDEVICE_SHOW(type, fmt_dec); -NETDEVICE_SHOW(link_mode, fmt_dec); - -/* use same locking rules as GIFHWADDR ioctl's */ -static ssize_t show_address(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct net_device *net = to_net_dev(dev); - ssize_t ret = -EINVAL; - - read_lock(&dev_base_lock); - if (dev_isalive(net)) - ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len); - read_unlock(&dev_base_lock); - return ret; -} - -static ssize_t show_broadcast(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *net = to_net_dev(dev); - if (dev_isalive(net)) - return sysfs_format_mac(buf, net->broadcast, net->addr_len); - return -EINVAL; -} - -static ssize_t show_carrier(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - if (netif_running(netdev)) { - return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); - } - return -EINVAL; -} - -static ssize_t show_dormant(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - - if (netif_running(netdev)) - return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); - - return -EINVAL; -} - -static const char *operstates[] = { - "unknown", - "notpresent", /* currently unused */ - "down", - "lowerlayerdown", - "testing", /* currently unused */ - "dormant", - "up" -}; - -static ssize_t show_operstate(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct net_device *netdev = to_net_dev(dev); - unsigned char operstate; - - read_lock(&dev_base_lock); - operstate = netdev->operstate; - if (!netif_running(netdev)) - operstate = IF_OPER_DOWN; - read_unlock(&dev_base_lock); - - if (operstate >= ARRAY_SIZE(operstates)) - return -EINVAL; /* should not happen */ - - return sprintf(buf, "%s\n", operstates[operstate]); -} - -/* read-write attributes */ -NETDEVICE_SHOW(mtu, fmt_dec); - -static int change_mtu(struct net_device *net, unsigned long new_mtu) -{ - return dev_set_mtu(net, (int) new_mtu); -} - -static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_mtu); -} - -NETDEVICE_SHOW(flags, fmt_hex); - -static int change_flags(struct net_device *net, unsigned long new_flags) -{ - return dev_change_flags(net, (unsigned) new_flags); -} - -static ssize_t store_flags(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_flags); -} - -NETDEVICE_SHOW(tx_queue_len, fmt_ulong); - -static int change_tx_queue_len(struct net_device *net, unsigned long new_len) -{ - net->tx_queue_len = new_len; - return 0; -} - -static ssize_t store_tx_queue_len(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_tx_queue_len); -} - -static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct net_device *netdev = to_net_dev(dev); - size_t count = len; - ssize_t ret; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* ignore trailing newline */ - if (len > 0 && buf[len - 1] == '\n') - --count; - - rtnl_lock(); - ret = dev_set_alias(netdev, buf, count); - rtnl_unlock(); - - return ret < 0 ? ret : len; -} - -static ssize_t show_ifalias(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct net_device *netdev = to_net_dev(dev); - ssize_t ret = 0; - - rtnl_lock(); - if (netdev->ifalias) - ret = sprintf(buf, "%s\n", netdev->ifalias); - rtnl_unlock(); - return ret; -} - -static struct device_attribute net_class_attributes[] = { - __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), - __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), - __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), - __ATTR(iflink, S_IRUGO, show_iflink, NULL), - __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), - __ATTR(features, S_IRUGO, show_features, NULL), - __ATTR(type, S_IRUGO, show_type, NULL), - __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), - __ATTR(address, S_IRUGO, show_address, NULL), - __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), - __ATTR(carrier, S_IRUGO, show_carrier, NULL), - __ATTR(dormant, S_IRUGO, show_dormant, NULL), - __ATTR(operstate, S_IRUGO, show_operstate, NULL), - __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), - __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), - __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, - store_tx_queue_len), - {} -}; - -/* Show a given an attribute in the statistics group */ -static ssize_t netstat_show(const struct device *d, - struct device_attribute *attr, char *buf, - unsigned long offset) -{ - struct net_device *dev = to_net_dev(d); - ssize_t ret = -EINVAL; - - WARN_ON(offset > sizeof(struct net_device_stats) || - offset % sizeof(unsigned long) != 0); - - read_lock(&dev_base_lock); - if (dev_isalive(dev)) { - const struct net_device_stats *stats = dev_get_stats(dev); - ret = sprintf(buf, fmt_ulong, - *(unsigned long *)(((u8 *) stats) + offset)); - } - read_unlock(&dev_base_lock); - return ret; -} - -/* generate a read-only statistics attribute */ -#define NETSTAT_ENTRY(name) \ -static ssize_t show_##name(struct device *d, \ - struct device_attribute *attr, char *buf) \ -{ \ - return netstat_show(d, attr, buf, \ - offsetof(struct net_device_stats, name)); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) - -NETSTAT_ENTRY(rx_packets); -NETSTAT_ENTRY(tx_packets); -NETSTAT_ENTRY(rx_bytes); -NETSTAT_ENTRY(tx_bytes); -NETSTAT_ENTRY(rx_errors); -NETSTAT_ENTRY(tx_errors); -NETSTAT_ENTRY(rx_dropped); -NETSTAT_ENTRY(tx_dropped); -NETSTAT_ENTRY(multicast); -NETSTAT_ENTRY(collisions); -NETSTAT_ENTRY(rx_length_errors); -NETSTAT_ENTRY(rx_over_errors); -NETSTAT_ENTRY(rx_crc_errors); -NETSTAT_ENTRY(rx_frame_errors); -NETSTAT_ENTRY(rx_fifo_errors); -NETSTAT_ENTRY(rx_missed_errors); -NETSTAT_ENTRY(tx_aborted_errors); -NETSTAT_ENTRY(tx_carrier_errors); -NETSTAT_ENTRY(tx_fifo_errors); -NETSTAT_ENTRY(tx_heartbeat_errors); -NETSTAT_ENTRY(tx_window_errors); -NETSTAT_ENTRY(rx_compressed); -NETSTAT_ENTRY(tx_compressed); - -static struct attribute *netstat_attrs[] = { - &dev_attr_rx_packets.attr, - &dev_attr_tx_packets.attr, - &dev_attr_rx_bytes.attr, - &dev_attr_tx_bytes.attr, - &dev_attr_rx_errors.attr, - &dev_attr_tx_errors.attr, - &dev_attr_rx_dropped.attr, - &dev_attr_tx_dropped.attr, - &dev_attr_multicast.attr, - &dev_attr_collisions.attr, - &dev_attr_rx_length_errors.attr, - &dev_attr_rx_over_errors.attr, - &dev_attr_rx_crc_errors.attr, - &dev_attr_rx_frame_errors.attr, - &dev_attr_rx_fifo_errors.attr, - &dev_attr_rx_missed_errors.attr, - &dev_attr_tx_aborted_errors.attr, - &dev_attr_tx_carrier_errors.attr, - &dev_attr_tx_fifo_errors.attr, - &dev_attr_tx_heartbeat_errors.attr, - &dev_attr_tx_window_errors.attr, - &dev_attr_rx_compressed.attr, - &dev_attr_tx_compressed.attr, - NULL -}; - - -static struct attribute_group netstat_group = { - .name = "statistics", - .attrs = netstat_attrs, -}; - -#ifdef CONFIG_WIRELESS_EXT_SYSFS -/* helper function that does all the locking etc for wireless stats */ -static ssize_t wireless_show(struct device *d, char *buf, - ssize_t (*format)(const struct iw_statistics *, - char *)) -{ - struct net_device *dev = to_net_dev(d); - const struct iw_statistics *iw = NULL; - ssize_t ret = -EINVAL; - - read_lock(&dev_base_lock); - if (dev_isalive(dev)) { - if (dev->wireless_handlers && - dev->wireless_handlers->get_wireless_stats) - iw = dev->wireless_handlers->get_wireless_stats(dev); - if (iw != NULL) - ret = (*format)(iw, buf); - } - read_unlock(&dev_base_lock); - - return ret; -} - -/* show function template for wireless fields */ -#define WIRELESS_SHOW(name, field, format_string) \ -static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ -{ \ - return sprintf(buf, format_string, iw->field); \ -} \ -static ssize_t show_iw_##name(struct device *d, \ - struct device_attribute *attr, char *buf) \ -{ \ - return wireless_show(d, buf, format_iw_##name); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) - -WIRELESS_SHOW(status, status, fmt_hex); -WIRELESS_SHOW(link, qual.qual, fmt_dec); -WIRELESS_SHOW(level, qual.level, fmt_dec); -WIRELESS_SHOW(noise, qual.noise, fmt_dec); -WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); -WIRELESS_SHOW(crypt, discard.code, fmt_dec); -WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); -WIRELESS_SHOW(misc, discard.misc, fmt_dec); -WIRELESS_SHOW(retries, discard.retries, fmt_dec); -WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); - -static struct attribute *wireless_attrs[] = { - &dev_attr_status.attr, - &dev_attr_link.attr, - &dev_attr_level.attr, - &dev_attr_noise.attr, - &dev_attr_nwid.attr, - &dev_attr_crypt.attr, - &dev_attr_fragment.attr, - &dev_attr_retries.attr, - &dev_attr_misc.attr, - &dev_attr_beacon.attr, - NULL -}; - -static struct attribute_group wireless_group = { - .name = "wireless", - .attrs = wireless_attrs, -}; -#endif - -#endif /* CONFIG_SYSFS */ - -#ifdef CONFIG_HOTPLUG -static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) -{ - struct net_device *dev = to_net_dev(d); - int retval; - - if (!net_eq(dev_net(dev), &init_net)) - return 0; - - /* pass interface to uevent. */ - retval = add_uevent_var(env, "INTERFACE=%s", dev->name); - if (retval) - goto exit; - - /* pass ifindex to uevent. - * ifindex is useful as it won't change (interface name may change) - * and is what RtNetlink uses natively. */ - retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); - -exit: - return retval; -} -#endif - -/* - * netdev_release -- destroy and free a dead device. - * Called when last reference to device kobject is gone. - */ -static void netdev_release(struct device *d) -{ - struct net_device *dev = to_net_dev(d); - - BUG_ON(dev->reg_state != NETREG_RELEASED); - - kfree(dev->ifalias); - kfree((char *)dev - dev->padded); -} - -static struct class net_class = { - .name = "net", - .dev_release = netdev_release, -#ifdef CONFIG_SYSFS - .dev_attrs = net_class_attributes, -#endif /* CONFIG_SYSFS */ -#ifdef CONFIG_HOTPLUG - .dev_uevent = netdev_uevent, -#endif -}; - -/* Delete sysfs entries but hold kobject reference until after all - * netdev references are gone. - */ -void netdev_unregister_kobject(struct net_device * net) -{ - struct device *dev = &(net->dev); - - kobject_get(&dev->kobj); - - if (dev_net(net) != &init_net) - return; - - device_del(dev); -} - -/* Create sysfs entries for network device. */ -int netdev_register_kobject(struct net_device *net) -{ - struct device *dev = &(net->dev); - struct attribute_group **groups = net->sysfs_groups; - - dev->class = &net_class; - dev->platform_data = net; - dev->groups = groups; - - BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); - dev_set_name(dev, net->name); - -#ifdef CONFIG_SYSFS - *groups++ = &netstat_group; - -#ifdef CONFIG_WIRELESS_EXT_SYSFS - if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) - *groups++ = &wireless_group; -#endif -#endif /* CONFIG_SYSFS */ - - if (dev_net(net) != &init_net) - return 0; - - return device_add(dev); -} - -int netdev_class_create_file(struct class_attribute *class_attr) -{ - return class_create_file(&net_class, class_attr); -} - -void netdev_class_remove_file(struct class_attribute *class_attr) -{ - class_remove_file(&net_class, class_attr); -} - -EXPORT_SYMBOL(netdev_class_create_file); -EXPORT_SYMBOL(netdev_class_remove_file); - -void netdev_initialize_kobject(struct net_device *net) -{ - struct device *device = &(net->dev); - device_initialize(device); -} - -int netdev_kobject_init(void) -{ - return class_register(&net_class); -} diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/net-sysfs.h.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/net-sysfs.h.svn-base deleted file mode 100644 index 14e75242..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/net-sysfs.h.svn-base +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __NET_SYSFS_H__ -#define __NET_SYSFS_H__ - -int netdev_kobject_init(void); -int netdev_register_kobject(struct net_device *); -void netdev_unregister_kobject(struct net_device *); -void netdev_initialize_kobject(struct net_device *); -#endif diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/netevent.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/netevent.c.svn-base deleted file mode 100644 index 95f81de8..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/netevent.c.svn-base +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Network event notifiers - * - * Authors: - * Tom Tucker <tom@opengridcomputing.com> - * Steve Wise <swise@opengridcomputing.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - */ - -#include <linux/rtnetlink.h> -#include <linux/notifier.h> -#include <net/netevent.h> - -static ATOMIC_NOTIFIER_HEAD(netevent_notif_chain); - -/** - * register_netevent_notifier - register a netevent notifier block - * @nb: notifier - * - * Register a notifier to be called when a netevent occurs. - * The notifier passed is linked into the kernel structures and must - * not be reused until it has been unregistered. A negative errno code - * is returned on a failure. - */ -int register_netevent_notifier(struct notifier_block *nb) -{ - int err; - - err = atomic_notifier_chain_register(&netevent_notif_chain, nb); - return err; -} - -/** - * netevent_unregister_notifier - unregister a netevent notifier block - * @nb: notifier - * - * Unregister a notifier previously registered by - * register_neigh_notifier(). The notifier is unlinked into the - * kernel structures and may then be reused. A negative errno code - * is returned on a failure. - */ - -int unregister_netevent_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&netevent_notif_chain, nb); -} - -/** - * call_netevent_notifiers - call all netevent notifier blocks - * @val: value passed unmodified to notifier function - * @v: pointer passed unmodified to notifier function - * - * Call all neighbour notifier blocks. Parameters and return value - * are as for notifier_call_chain(). - */ - -int call_netevent_notifiers(unsigned long val, void *v) -{ - return atomic_notifier_call_chain(&netevent_notif_chain, val, v); -} - -EXPORT_SYMBOL_GPL(register_netevent_notifier); -EXPORT_SYMBOL_GPL(unregister_netevent_notifier); -EXPORT_SYMBOL_GPL(call_netevent_notifiers); diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/rtnetlink.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/rtnetlink.c.svn-base deleted file mode 100644 index 790dd205..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/rtnetlink.c.svn-base +++ /dev/null @@ -1,1430 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Routing netlink socket interface: protocol independent part. - * - * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * Vitaly E. Lavrov RTA_OK arithmetics was wrong. - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/socket.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/string.h> -#include <linux/sockios.h> -#include <linux/net.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/capability.h> -#include <linux/skbuff.h> -#include <linux/init.h> -#include <linux/security.h> -#include <linux/mutex.h> -#include <linux/if_addr.h> -#include <linux/nsproxy.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/string.h> - -#include <linux/inet.h> -#include <linux/netdevice.h> -#include <net/ip.h> -#include <net/protocol.h> -#include <net/arp.h> -#include <net/route.h> -#include <net/udp.h> -#include <net/sock.h> -#include <net/pkt_sched.h> -#include <net/fib_rules.h> -#include <net/rtnetlink.h> - -struct rtnl_link -{ - rtnl_doit_func doit; - rtnl_dumpit_func dumpit; -}; - -static DEFINE_MUTEX(rtnl_mutex); - -void rtnl_lock(void) -{ - mutex_lock(&rtnl_mutex); -} - -void __rtnl_unlock(void) -{ - mutex_unlock(&rtnl_mutex); -} - -void rtnl_unlock(void) -{ - /* This fellow will unlock it for us. */ - netdev_run_todo(); -} - -int rtnl_trylock(void) -{ - return mutex_trylock(&rtnl_mutex); -} - -int rtnl_is_locked(void) -{ - return mutex_is_locked(&rtnl_mutex); -} - -static struct rtnl_link *rtnl_msg_handlers[NPROTO]; - -static inline int rtm_msgindex(int msgtype) -{ - int msgindex = msgtype - RTM_BASE; - - /* - * msgindex < 0 implies someone tried to register a netlink - * control code. msgindex >= RTM_NR_MSGTYPES may indicate that - * the message type has not been added to linux/rtnetlink.h - */ - BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES); - - return msgindex; -} - -static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex) -{ - struct rtnl_link *tab; - - tab = rtnl_msg_handlers[protocol]; - if (tab == NULL || tab[msgindex].doit == NULL) - tab = rtnl_msg_handlers[PF_UNSPEC]; - - return tab ? tab[msgindex].doit : NULL; -} - -static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex) -{ - struct rtnl_link *tab; - - tab = rtnl_msg_handlers[protocol]; - if (tab == NULL || tab[msgindex].dumpit == NULL) - tab = rtnl_msg_handlers[PF_UNSPEC]; - - return tab ? tab[msgindex].dumpit : NULL; -} - -/** - * __rtnl_register - Register a rtnetlink message type - * @protocol: Protocol family or PF_UNSPEC - * @msgtype: rtnetlink message type - * @doit: Function pointer called for each request message - * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message - * - * Registers the specified function pointers (at least one of them has - * to be non-NULL) to be called whenever a request message for the - * specified protocol family and message type is received. - * - * The special protocol family PF_UNSPEC may be used to define fallback - * function pointers for the case when no entry for the specific protocol - * family exists. - * - * Returns 0 on success or a negative error code. - */ -int __rtnl_register(int protocol, int msgtype, - rtnl_doit_func doit, rtnl_dumpit_func dumpit) -{ - struct rtnl_link *tab; - int msgindex; - - BUG_ON(protocol < 0 || protocol >= NPROTO); - msgindex = rtm_msgindex(msgtype); - - tab = rtnl_msg_handlers[protocol]; - if (tab == NULL) { - tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL); - if (tab == NULL) - return -ENOBUFS; - - rtnl_msg_handlers[protocol] = tab; - } - - if (doit) - tab[msgindex].doit = doit; - - if (dumpit) - tab[msgindex].dumpit = dumpit; - - return 0; -} - -EXPORT_SYMBOL_GPL(__rtnl_register); - -/** - * rtnl_register - Register a rtnetlink message type - * - * Identical to __rtnl_register() but panics on failure. This is useful - * as failure of this function is very unlikely, it can only happen due - * to lack of memory when allocating the chain to store all message - * handlers for a protocol. Meant for use in init functions where lack - * of memory implies no sense in continueing. - */ -void rtnl_register(int protocol, int msgtype, - rtnl_doit_func doit, rtnl_dumpit_func dumpit) -{ - if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0) - panic("Unable to register rtnetlink message handler, " - "protocol = %d, message type = %d\n", - protocol, msgtype); -} - -EXPORT_SYMBOL_GPL(rtnl_register); - -/** - * rtnl_unregister - Unregister a rtnetlink message type - * @protocol: Protocol family or PF_UNSPEC - * @msgtype: rtnetlink message type - * - * Returns 0 on success or a negative error code. - */ -int rtnl_unregister(int protocol, int msgtype) -{ - int msgindex; - - BUG_ON(protocol < 0 || protocol >= NPROTO); - msgindex = rtm_msgindex(msgtype); - - if (rtnl_msg_handlers[protocol] == NULL) - return -ENOENT; - - rtnl_msg_handlers[protocol][msgindex].doit = NULL; - rtnl_msg_handlers[protocol][msgindex].dumpit = NULL; - - return 0; -} - -EXPORT_SYMBOL_GPL(rtnl_unregister); - -/** - * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol - * @protocol : Protocol family or PF_UNSPEC - * - * Identical to calling rtnl_unregster() for all registered message types - * of a certain protocol family. - */ -void rtnl_unregister_all(int protocol) -{ - BUG_ON(protocol < 0 || protocol >= NPROTO); - - kfree(rtnl_msg_handlers[protocol]); - rtnl_msg_handlers[protocol] = NULL; -} - -EXPORT_SYMBOL_GPL(rtnl_unregister_all); - -static LIST_HEAD(link_ops); - -/** - * __rtnl_link_register - Register rtnl_link_ops with rtnetlink. - * @ops: struct rtnl_link_ops * to register - * - * The caller must hold the rtnl_mutex. This function should be used - * by drivers that create devices during module initialization. It - * must be called before registering the devices. - * - * Returns 0 on success or a negative error code. - */ -int __rtnl_link_register(struct rtnl_link_ops *ops) -{ - if (!ops->dellink) - ops->dellink = unregister_netdevice; - - list_add_tail(&ops->list, &link_ops); - return 0; -} - -EXPORT_SYMBOL_GPL(__rtnl_link_register); - -/** - * rtnl_link_register - Register rtnl_link_ops with rtnetlink. - * @ops: struct rtnl_link_ops * to register - * - * Returns 0 on success or a negative error code. - */ -int rtnl_link_register(struct rtnl_link_ops *ops) -{ - int err; - - rtnl_lock(); - err = __rtnl_link_register(ops); - rtnl_unlock(); - return err; -} - -EXPORT_SYMBOL_GPL(rtnl_link_register); - -static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) -{ - struct net_device *dev; -restart: - for_each_netdev(net, dev) { - if (dev->rtnl_link_ops == ops) { - ops->dellink(dev); - goto restart; - } - } -} - -void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) -{ - rtnl_lock(); - __rtnl_kill_links(net, ops); - rtnl_unlock(); -} -EXPORT_SYMBOL_GPL(rtnl_kill_links); - -/** - * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. - * @ops: struct rtnl_link_ops * to unregister - * - * The caller must hold the rtnl_mutex. - */ -void __rtnl_link_unregister(struct rtnl_link_ops *ops) -{ - struct net *net; - - for_each_net(net) { - __rtnl_kill_links(net, ops); - } - list_del(&ops->list); -} - -EXPORT_SYMBOL_GPL(__rtnl_link_unregister); - -/** - * rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. - * @ops: struct rtnl_link_ops * to unregister - */ -void rtnl_link_unregister(struct rtnl_link_ops *ops) -{ - rtnl_lock(); - __rtnl_link_unregister(ops); - rtnl_unlock(); -} - -EXPORT_SYMBOL_GPL(rtnl_link_unregister); - -static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind) -{ - const struct rtnl_link_ops *ops; - - list_for_each_entry(ops, &link_ops, list) { - if (!strcmp(ops->kind, kind)) - return ops; - } - return NULL; -} - -static size_t rtnl_link_get_size(const struct net_device *dev) -{ - const struct rtnl_link_ops *ops = dev->rtnl_link_ops; - size_t size; - - if (!ops) - return 0; - - size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */ - nlmsg_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */ - - if (ops->get_size) - /* IFLA_INFO_DATA + nested data */ - size += nlmsg_total_size(sizeof(struct nlattr)) + - ops->get_size(dev); - - if (ops->get_xstats_size) - size += ops->get_xstats_size(dev); /* IFLA_INFO_XSTATS */ - - return size; -} - -static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) -{ - const struct rtnl_link_ops *ops = dev->rtnl_link_ops; - struct nlattr *linkinfo, *data; - int err = -EMSGSIZE; - - linkinfo = nla_nest_start(skb, IFLA_LINKINFO); - if (linkinfo == NULL) - goto out; - - if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) - goto err_cancel_link; - if (ops->fill_xstats) { - err = ops->fill_xstats(skb, dev); - if (err < 0) - goto err_cancel_link; - } - if (ops->fill_info) { - data = nla_nest_start(skb, IFLA_INFO_DATA); - if (data == NULL) - goto err_cancel_link; - err = ops->fill_info(skb, dev); - if (err < 0) - goto err_cancel_data; - nla_nest_end(skb, data); - } - - nla_nest_end(skb, linkinfo); - return 0; - -err_cancel_data: - nla_nest_cancel(skb, data); -err_cancel_link: - nla_nest_cancel(skb, linkinfo); -out: - return err; -} - -static const int rtm_min[RTM_NR_FAMILIES] = -{ - [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), - [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), - [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), - [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)), - [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)), - [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), - [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), - [RTM_FAM(RTM_NEWACTION)] = NLMSG_LENGTH(sizeof(struct tcamsg)), - [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), - [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), -}; - -static const int rta_max[RTM_NR_FAMILIES] = -{ - [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX, - [RTM_FAM(RTM_NEWADDR)] = IFA_MAX, - [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX, - [RTM_FAM(RTM_NEWRULE)] = FRA_MAX, - [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX, - [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, - [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, - [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, -}; - -void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) -{ - struct rtattr *rta; - int size = RTA_LENGTH(attrlen); - - rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size)); - rta->rta_type = attrtype; - rta->rta_len = size; - memcpy(RTA_DATA(rta), data, attrlen); - memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size); -} - -int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo) -{ - struct sock *rtnl = net->rtnl; - int err = 0; - - NETLINK_CB(skb).dst_group = group; - if (echo) - atomic_inc(&skb->users); - netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL); - if (echo) - err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); - return err; -} - -int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid) -{ - struct sock *rtnl = net->rtnl; - - return nlmsg_unicast(rtnl, skb, pid); -} - -int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, - struct nlmsghdr *nlh, gfp_t flags) -{ - struct sock *rtnl = net->rtnl; - int report = 0; - - if (nlh) - report = nlmsg_report(nlh); - - return nlmsg_notify(rtnl, skb, pid, group, report, flags); -} - -void rtnl_set_sk_err(struct net *net, u32 group, int error) -{ - struct sock *rtnl = net->rtnl; - - netlink_set_err(rtnl, 0, group, error); -} - -int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) -{ - struct nlattr *mx; - int i, valid = 0; - - mx = nla_nest_start(skb, RTA_METRICS); - if (mx == NULL) - return -ENOBUFS; - - for (i = 0; i < RTAX_MAX; i++) { - if (metrics[i]) { - valid++; - NLA_PUT_U32(skb, i+1, metrics[i]); - } - } - - if (!valid) { - nla_nest_cancel(skb, mx); - return 0; - } - - return nla_nest_end(skb, mx); - -nla_put_failure: - nla_nest_cancel(skb, mx); - return -EMSGSIZE; -} - -int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, - u32 ts, u32 tsage, long expires, u32 error) -{ - struct rta_cacheinfo ci = { - .rta_lastuse = jiffies_to_clock_t(jiffies - dst->lastuse), - .rta_used = dst->__use, - .rta_clntref = atomic_read(&(dst->__refcnt)), - .rta_error = error, - .rta_id = id, - .rta_ts = ts, - .rta_tsage = tsage, - }; - - if (expires) - ci.rta_expires = jiffies_to_clock_t(expires); - - return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); -} - -EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); - -static void set_operstate(struct net_device *dev, unsigned char transition) -{ - unsigned char operstate = dev->operstate; - - switch(transition) { - case IF_OPER_UP: - if ((operstate == IF_OPER_DORMANT || - operstate == IF_OPER_UNKNOWN) && - !netif_dormant(dev)) - operstate = IF_OPER_UP; - break; - - case IF_OPER_DORMANT: - if (operstate == IF_OPER_UP || - operstate == IF_OPER_UNKNOWN) - operstate = IF_OPER_DORMANT; - break; - } - - if (dev->operstate != operstate) { - write_lock_bh(&dev_base_lock); - dev->operstate = operstate; - write_unlock_bh(&dev_base_lock); - netdev_state_change(dev); - } -} - -static void copy_rtnl_link_stats(struct rtnl_link_stats *a, - const struct net_device_stats *b) -{ - a->rx_packets = b->rx_packets; - a->tx_packets = b->tx_packets; - a->rx_bytes = b->rx_bytes; - a->tx_bytes = b->tx_bytes; - a->rx_errors = b->rx_errors; - a->tx_errors = b->tx_errors; - a->rx_dropped = b->rx_dropped; - a->tx_dropped = b->tx_dropped; - - a->multicast = b->multicast; - a->collisions = b->collisions; - - a->rx_length_errors = b->rx_length_errors; - a->rx_over_errors = b->rx_over_errors; - a->rx_crc_errors = b->rx_crc_errors; - a->rx_frame_errors = b->rx_frame_errors; - a->rx_fifo_errors = b->rx_fifo_errors; - a->rx_missed_errors = b->rx_missed_errors; - - a->tx_aborted_errors = b->tx_aborted_errors; - a->tx_carrier_errors = b->tx_carrier_errors; - a->tx_fifo_errors = b->tx_fifo_errors; - a->tx_heartbeat_errors = b->tx_heartbeat_errors; - a->tx_window_errors = b->tx_window_errors; - - a->rx_compressed = b->rx_compressed; - a->tx_compressed = b->tx_compressed; -}; - -static inline size_t if_nlmsg_size(const struct net_device *dev) -{ - return NLMSG_ALIGN(sizeof(struct ifinfomsg)) - + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ - + nla_total_size(IFALIASZ) /* IFLA_IFALIAS */ - + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */ - + nla_total_size(sizeof(struct rtnl_link_ifmap)) - + nla_total_size(sizeof(struct rtnl_link_stats)) - + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ - + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */ - + nla_total_size(4) /* IFLA_TXQLEN */ - + nla_total_size(4) /* IFLA_WEIGHT */ - + nla_total_size(4) /* IFLA_MTU */ - + nla_total_size(4) /* IFLA_LINK */ - + nla_total_size(4) /* IFLA_MASTER */ - + nla_total_size(1) /* IFLA_OPERSTATE */ - + nla_total_size(1) /* IFLA_LINKMODE */ - + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ -} - -static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, - int type, u32 pid, u32 seq, u32 change, - unsigned int flags) -{ - struct netdev_queue *txq; - struct ifinfomsg *ifm; - struct nlmsghdr *nlh; - const struct net_device_stats *stats; - struct nlattr *attr; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ifm = nlmsg_data(nlh); - ifm->ifi_family = AF_UNSPEC; - ifm->__ifi_pad = 0; - ifm->ifi_type = dev->type; - ifm->ifi_index = dev->ifindex; - ifm->ifi_flags = dev_get_flags(dev); - ifm->ifi_change = change; - - NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); - NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len); - NLA_PUT_U8(skb, IFLA_OPERSTATE, - netif_running(dev) ? dev->operstate : IF_OPER_DOWN); - NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); - NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); - - if (dev->ifindex != dev->iflink) - NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); - - if (dev->master) - NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); - - txq = netdev_get_tx_queue(dev, 0); - if (txq->qdisc_sleeping) - NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id); - - if (dev->ifalias) - NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias); - - if (1) { - struct rtnl_link_ifmap map = { - .mem_start = dev->mem_start, - .mem_end = dev->mem_end, - .base_addr = dev->base_addr, - .irq = dev->irq, - .dma = dev->dma, - .port = dev->if_port, - }; - NLA_PUT(skb, IFLA_MAP, sizeof(map), &map); - } - - if (dev->addr_len) { - NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); - NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); - } - - attr = nla_reserve(skb, IFLA_STATS, - sizeof(struct rtnl_link_stats)); - if (attr == NULL) - goto nla_put_failure; - - stats = dev_get_stats(dev); - copy_rtnl_link_stats(nla_data(attr), stats); - - if (dev->rtnl_link_ops) { - if (rtnl_link_fill(skb, dev) < 0) - goto nla_put_failure; - } - - return nlmsg_end(skb, nlh); - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int idx; - int s_idx = cb->args[0]; - struct net_device *dev; - - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx) - goto cont; - if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0) - break; -cont: - idx++; - } - cb->args[0] = idx; - - return skb->len; -} - -const struct nla_policy ifla_policy[IFLA_MAX+1] = { - [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, - [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, - [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, - [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, - [IFLA_MTU] = { .type = NLA_U32 }, - [IFLA_LINK] = { .type = NLA_U32 }, - [IFLA_TXQLEN] = { .type = NLA_U32 }, - [IFLA_WEIGHT] = { .type = NLA_U32 }, - [IFLA_OPERSTATE] = { .type = NLA_U8 }, - [IFLA_LINKMODE] = { .type = NLA_U8 }, - [IFLA_LINKINFO] = { .type = NLA_NESTED }, - [IFLA_NET_NS_PID] = { .type = NLA_U32 }, - [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, -}; - -static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { - [IFLA_INFO_KIND] = { .type = NLA_STRING }, - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, -}; - -static struct net *get_net_ns_by_pid(pid_t pid) -{ - struct task_struct *tsk; - struct net *net; - - /* Lookup the network namespace */ - net = ERR_PTR(-ESRCH); - rcu_read_lock(); - tsk = find_task_by_vpid(pid); - if (tsk) { - struct nsproxy *nsproxy; - nsproxy = task_nsproxy(tsk); - if (nsproxy) - net = get_net(nsproxy->net_ns); - } - rcu_read_unlock(); - return net; -} - -static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) -{ - if (dev) { - if (tb[IFLA_ADDRESS] && - nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) - return -EINVAL; - - if (tb[IFLA_BROADCAST] && - nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) - return -EINVAL; - } - - return 0; -} - -static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, - struct nlattr **tb, char *ifname, int modified) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int send_addr_notify = 0; - int err; - - if (tb[IFLA_NET_NS_PID]) { - struct net *net; - net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); - if (IS_ERR(net)) { - err = PTR_ERR(net); - goto errout; - } - err = dev_change_net_namespace(dev, net, ifname); - put_net(net); - if (err) - goto errout; - modified = 1; - } - - if (tb[IFLA_MAP]) { - struct rtnl_link_ifmap *u_map; - struct ifmap k_map; - - if (!ops->ndo_set_config) { - err = -EOPNOTSUPP; - goto errout; - } - - if (!netif_device_present(dev)) { - err = -ENODEV; - goto errout; - } - - u_map = nla_data(tb[IFLA_MAP]); - k_map.mem_start = (unsigned long) u_map->mem_start; - k_map.mem_end = (unsigned long) u_map->mem_end; - k_map.base_addr = (unsigned short) u_map->base_addr; - k_map.irq = (unsigned char) u_map->irq; - k_map.dma = (unsigned char) u_map->dma; - k_map.port = (unsigned char) u_map->port; - - err = ops->ndo_set_config(dev, &k_map); - if (err < 0) - goto errout; - - modified = 1; - } - - if (tb[IFLA_ADDRESS]) { - struct sockaddr *sa; - int len; - - if (!ops->ndo_set_mac_address) { - err = -EOPNOTSUPP; - goto errout; - } - - if (!netif_device_present(dev)) { - err = -ENODEV; - goto errout; - } - - len = sizeof(sa_family_t) + dev->addr_len; - sa = kmalloc(len, GFP_KERNEL); - if (!sa) { - err = -ENOMEM; - goto errout; - } - sa->sa_family = dev->type; - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), - dev->addr_len); - err = ops->ndo_set_mac_address(dev, sa); - kfree(sa); - if (err) - goto errout; - send_addr_notify = 1; - modified = 1; - } - - if (tb[IFLA_MTU]) { - err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU])); - if (err < 0) - goto errout; - modified = 1; - } - - /* - * Interface selected by interface index but interface - * name provided implies that a name change has been - * requested. - */ - if (ifm->ifi_index > 0 && ifname[0]) { - err = dev_change_name(dev, ifname); - if (err < 0) - goto errout; - modified = 1; - } - - if (tb[IFLA_IFALIAS]) { - err = dev_set_alias(dev, nla_data(tb[IFLA_IFALIAS]), - nla_len(tb[IFLA_IFALIAS])); - if (err < 0) - goto errout; - modified = 1; - } - - if (tb[IFLA_BROADCAST]) { - nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); - send_addr_notify = 1; - } - - if (ifm->ifi_flags || ifm->ifi_change) { - unsigned int flags = ifm->ifi_flags; - - /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ - if (ifm->ifi_change) - flags = (flags & ifm->ifi_change) | - (dev->flags & ~ifm->ifi_change); - err = dev_change_flags(dev, flags); - if (err < 0) - goto errout; - } - - if (tb[IFLA_TXQLEN]) - dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - - if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); - - if (tb[IFLA_LINKMODE]) { - write_lock_bh(&dev_base_lock); - dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); - write_unlock_bh(&dev_base_lock); - } - - err = 0; - -errout: - if (err < 0 && modified && net_ratelimit()) - printk(KERN_WARNING "A link change request failed with " - "some changes comitted already. Interface %s may " - "have been left with an inconsistent configuration, " - "please check.\n", dev->name); - - if (send_addr_notify) - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return err; -} - -static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - struct ifinfomsg *ifm; - struct net_device *dev; - int err; - struct nlattr *tb[IFLA_MAX+1]; - char ifname[IFNAMSIZ]; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - goto errout; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - else - ifname[0] = '\0'; - - err = -EINVAL; - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = dev_get_by_index(net, ifm->ifi_index); - else if (tb[IFLA_IFNAME]) - dev = dev_get_by_name(net, ifname); - else - goto errout; - - if (dev == NULL) { - err = -ENODEV; - goto errout; - } - - if ((err = validate_linkmsg(dev, tb)) < 0) - goto errout_dev; - - err = do_setlink(dev, ifm, tb, ifname, 0); -errout_dev: - dev_put(dev); -errout: - return err; -} - -static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - const struct rtnl_link_ops *ops; - struct net_device *dev; - struct ifinfomsg *ifm; - char ifname[IFNAMSIZ]; - struct nlattr *tb[IFLA_MAX+1]; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - return err; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = __dev_get_by_index(net, ifm->ifi_index); - else if (tb[IFLA_IFNAME]) - dev = __dev_get_by_name(net, ifname); - else - return -EINVAL; - - if (!dev) - return -ENODEV; - - ops = dev->rtnl_link_ops; - if (!ops) - return -EOPNOTSUPP; - - ops->dellink(dev); - return 0; -} - -struct net_device *rtnl_create_link(struct net *net, char *ifname, - const struct rtnl_link_ops *ops, struct nlattr *tb[]) -{ - int err; - struct net_device *dev; - - err = -ENOMEM; - dev = alloc_netdev(ops->priv_size, ifname, ops->setup); - if (!dev) - goto err; - - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_free; - } - - dev_net_set(dev, net); - dev->rtnl_link_ops = ops; - - if (tb[IFLA_MTU]) - dev->mtu = nla_get_u32(tb[IFLA_MTU]); - if (tb[IFLA_ADDRESS]) - memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), - nla_len(tb[IFLA_ADDRESS])); - if (tb[IFLA_BROADCAST]) - memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), - nla_len(tb[IFLA_BROADCAST])); - if (tb[IFLA_TXQLEN]) - dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); - if (tb[IFLA_LINKMODE]) - dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); - - return dev; - -err_free: - free_netdev(dev); -err: - return ERR_PTR(err); -} - -static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - const struct rtnl_link_ops *ops; - struct net_device *dev; - struct ifinfomsg *ifm; - char kind[MODULE_NAME_LEN]; - char ifname[IFNAMSIZ]; - struct nlattr *tb[IFLA_MAX+1]; - struct nlattr *linkinfo[IFLA_INFO_MAX+1]; - int err; - -#ifdef CONFIG_MODULES -replay: -#endif - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - return err; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - else - ifname[0] = '\0'; - - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = __dev_get_by_index(net, ifm->ifi_index); - else if (ifname[0]) - dev = __dev_get_by_name(net, ifname); - else - dev = NULL; - - if ((err = validate_linkmsg(dev, tb)) < 0) - return err; - - if (tb[IFLA_LINKINFO]) { - err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, - tb[IFLA_LINKINFO], ifla_info_policy); - if (err < 0) - return err; - } else - memset(linkinfo, 0, sizeof(linkinfo)); - - if (linkinfo[IFLA_INFO_KIND]) { - nla_strlcpy(kind, linkinfo[IFLA_INFO_KIND], sizeof(kind)); - ops = rtnl_link_ops_get(kind); - } else { - kind[0] = '\0'; - ops = NULL; - } - - if (1) { - struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; - - if (ops) { - if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { - err = nla_parse_nested(attr, ops->maxtype, - linkinfo[IFLA_INFO_DATA], - ops->policy); - if (err < 0) - return err; - data = attr; - } - if (ops->validate) { - err = ops->validate(tb, data); - if (err < 0) - return err; - } - } - - if (dev) { - int modified = 0; - - if (nlh->nlmsg_flags & NLM_F_EXCL) - return -EEXIST; - if (nlh->nlmsg_flags & NLM_F_REPLACE) - return -EOPNOTSUPP; - - if (linkinfo[IFLA_INFO_DATA]) { - if (!ops || ops != dev->rtnl_link_ops || - !ops->changelink) - return -EOPNOTSUPP; - - err = ops->changelink(dev, tb, data); - if (err < 0) - return err; - modified = 1; - } - - return do_setlink(dev, ifm, tb, ifname, modified); - } - - if (!(nlh->nlmsg_flags & NLM_F_CREATE)) - return -ENODEV; - - if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change) - return -EOPNOTSUPP; - if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) - return -EOPNOTSUPP; - - if (!ops) { -#ifdef CONFIG_MODULES - if (kind[0]) { - __rtnl_unlock(); - request_module("rtnl-link-%s", kind); - rtnl_lock(); - ops = rtnl_link_ops_get(kind); - if (ops) - goto replay; - } -#endif - return -EOPNOTSUPP; - } - - if (!ifname[0]) - snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); - - dev = rtnl_create_link(net, ifname, ops, tb); - - if (IS_ERR(dev)) - err = PTR_ERR(dev); - else if (ops->newlink) - err = ops->newlink(dev, tb, data); - else - err = register_netdevice(dev); - - if (err < 0 && !IS_ERR(dev)) - free_netdev(dev); - return err; - } -} - -static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) -{ - struct net *net = sock_net(skb->sk); - struct ifinfomsg *ifm; - struct nlattr *tb[IFLA_MAX+1]; - struct net_device *dev = NULL; - struct sk_buff *nskb; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - return err; - - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) { - dev = dev_get_by_index(net, ifm->ifi_index); - if (dev == NULL) - return -ENODEV; - } else - return -EINVAL; - - nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); - if (nskb == NULL) { - err = -ENOBUFS; - goto errout; - } - - err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid, - nlh->nlmsg_seq, 0, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in if_nlmsg_size */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(nskb); - goto errout; - } - err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); -errout: - dev_put(dev); - - return err; -} - -static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) -{ - int idx; - int s_idx = cb->family; - - if (s_idx == 0) - s_idx = 1; - for (idx=1; idx<NPROTO; idx++) { - int type = cb->nlh->nlmsg_type-RTM_BASE; - if (idx < s_idx || idx == PF_PACKET) - continue; - if (rtnl_msg_handlers[idx] == NULL || - rtnl_msg_handlers[idx][type].dumpit == NULL) - continue; - if (idx > s_idx) - memset(&cb->args[0], 0, sizeof(cb->args)); - if (rtnl_msg_handlers[idx][type].dumpit(skb, cb)) - break; - } - cb->family = idx; - - return skb->len; -} - -void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) -{ - struct net *net = dev_net(dev); - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); - if (skb == NULL) - goto errout; - - err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in if_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_LINK, err); -} - -/* Protected by RTNL sempahore. */ -static struct rtattr **rta_buf; -static int rtattr_max; - -/* Process one rtnetlink message. */ - -static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - rtnl_doit_func doit; - int sz_idx, kind; - int min_len; - int family; - int type; - int err; - - type = nlh->nlmsg_type; - if (type > RTM_MAX) - return -EOPNOTSUPP; - - type -= RTM_BASE; - - /* All the messages must have at least 1 byte length */ - if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) - return 0; - - family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; - if (family >= NPROTO) - return -EAFNOSUPPORT; - - sz_idx = type>>2; - kind = type&3; - - if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) - return -EPERM; - - if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { - struct sock *rtnl; - rtnl_dumpit_func dumpit; - - dumpit = rtnl_get_dumpit(family, type); - if (dumpit == NULL) - return -EOPNOTSUPP; - - __rtnl_unlock(); - rtnl = net->rtnl; - err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); - rtnl_lock(); - return err; - } - - memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); - - min_len = rtm_min[sz_idx]; - if (nlh->nlmsg_len < min_len) - return -EINVAL; - - if (nlh->nlmsg_len > min_len) { - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); - - while (RTA_OK(attr, attrlen)) { - unsigned flavor = attr->rta_type; - if (flavor) { - if (flavor > rta_max[sz_idx]) - return -EINVAL; - rta_buf[flavor-1] = attr; - } - attr = RTA_NEXT(attr, attrlen); - } - } - - doit = rtnl_get_doit(family, type); - if (doit == NULL) - return -EOPNOTSUPP; - - return doit(skb, nlh, (void *)&rta_buf[0]); -} - -static void rtnetlink_rcv(struct sk_buff *skb) -{ - rtnl_lock(); - netlink_rcv_skb(skb, &rtnetlink_rcv_msg); - rtnl_unlock(); -} - -static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct net_device *dev = ptr; - - switch (event) { - case NETDEV_UNREGISTER: - rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); - break; - case NETDEV_REGISTER: - rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); - break; - case NETDEV_UP: - case NETDEV_DOWN: - rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); - break; - case NETDEV_CHANGE: - case NETDEV_GOING_DOWN: - break; - default: - rtmsg_ifinfo(RTM_NEWLINK, dev, 0); - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block rtnetlink_dev_notifier = { - .notifier_call = rtnetlink_event, -}; - - -static int rtnetlink_net_init(struct net *net) -{ - struct sock *sk; - sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, - rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); - if (!sk) - return -ENOMEM; - net->rtnl = sk; - return 0; -} - -static void rtnetlink_net_exit(struct net *net) -{ - netlink_kernel_release(net->rtnl); - net->rtnl = NULL; -} - -static struct pernet_operations rtnetlink_net_ops = { - .init = rtnetlink_net_init, - .exit = rtnetlink_net_exit, -}; - -void __init rtnetlink_init(void) -{ - int i; - - rtattr_max = 0; - for (i = 0; i < ARRAY_SIZE(rta_max); i++) - if (rta_max[i] > rtattr_max) - rtattr_max = rta_max[i]; - rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL); - if (!rta_buf) - panic("rtnetlink_init: cannot allocate rta_buf\n"); - - if (register_pernet_subsys(&rtnetlink_net_ops)) - panic("rtnetlink_init: cannot initialize rtnetlink\n"); - - netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); - register_netdevice_notifier(&rtnetlink_dev_notifier); - - rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo); - rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL); - rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL); - rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL); - - rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all); - rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); -} - -EXPORT_SYMBOL(__rta_fill); -EXPORT_SYMBOL(rtnetlink_put_metrics); -EXPORT_SYMBOL(rtnl_lock); -EXPORT_SYMBOL(rtnl_trylock); -EXPORT_SYMBOL(rtnl_unlock); -EXPORT_SYMBOL(rtnl_is_locked); -EXPORT_SYMBOL(rtnl_unicast); -EXPORT_SYMBOL(rtnl_notify); -EXPORT_SYMBOL(rtnl_set_sk_err); -EXPORT_SYMBOL(rtnl_create_link); -EXPORT_SYMBOL(ifla_policy); diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/skb_dma_map.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/skb_dma_map.c.svn-base deleted file mode 100644 index 86234923..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/skb_dma_map.c.svn-base +++ /dev/null @@ -1,66 +0,0 @@ -/* skb_dma_map.c: DMA mapping helpers for socket buffers. - * - * Copyright (C) David S. Miller <davem@davemloft.net> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/skbuff.h> - -int skb_dma_map(struct device *dev, struct sk_buff *skb, - enum dma_data_direction dir) -{ - struct skb_shared_info *sp = skb_shinfo(skb); - dma_addr_t map; - int i; - - map = dma_map_single(dev, skb->data, - skb_headlen(skb), dir); - if (dma_mapping_error(dev, map)) - goto out_err; - - sp->dma_maps[0] = map; - for (i = 0; i < sp->nr_frags; i++) { - skb_frag_t *fp = &sp->frags[i]; - - map = dma_map_page(dev, fp->page, fp->page_offset, - fp->size, dir); - if (dma_mapping_error(dev, map)) - goto unwind; - sp->dma_maps[i + 1] = map; - } - sp->num_dma_maps = i + 1; - - return 0; - -unwind: - while (--i >= 0) { - skb_frag_t *fp = &sp->frags[i]; - - dma_unmap_page(dev, sp->dma_maps[i + 1], - fp->size, dir); - } - dma_unmap_single(dev, sp->dma_maps[0], - skb_headlen(skb), dir); -out_err: - return -ENOMEM; -} -EXPORT_SYMBOL(skb_dma_map); - -void skb_dma_unmap(struct device *dev, struct sk_buff *skb, - enum dma_data_direction dir) -{ - struct skb_shared_info *sp = skb_shinfo(skb); - int i; - - dma_unmap_single(dev, sp->dma_maps[0], - skb_headlen(skb), dir); - for (i = 0; i < sp->nr_frags; i++) { - skb_frag_t *fp = &sp->frags[i]; - - dma_unmap_page(dev, sp->dma_maps[i + 1], - fp->size, dir); - } -} -EXPORT_SYMBOL(skb_dma_unmap); diff --git a/libdde_linux26/contrib/net/core/.svn/text-base/sock.c.svn-base b/libdde_linux26/contrib/net/core/.svn/text-base/sock.c.svn-base deleted file mode 100644 index 5f97caa1..00000000 --- a/libdde_linux26/contrib/net/core/.svn/text-base/sock.c.svn-base +++ /dev/null @@ -1,2297 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic socket support routines. Memory allocators, socket lock/release - * handler for protocols to use and generic option handler. - * - * - * Authors: Ross Biro - * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> - * Florian La Roche, <flla@stud.uni-sb.de> - * Alan Cox, <A.Cox@swansea.ac.uk> - * - * Fixes: - * Alan Cox : Numerous verify_area() problems - * Alan Cox : Connecting on a connecting socket - * now returns an error for tcp. - * Alan Cox : sock->protocol is set correctly. - * and is not sometimes left as 0. - * Alan Cox : connect handles icmp errors on a - * connect properly. Unfortunately there - * is a restart syscall nasty there. I - * can't match BSD without hacking the C - * library. Ideas urgently sought! - * Alan Cox : Disallow bind() to addresses that are - * not ours - especially broadcast ones!! - * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost) - * Alan Cox : sock_wfree/sock_rfree don't destroy sockets, - * instead they leave that for the DESTROY timer. - * Alan Cox : Clean up error flag in accept - * Alan Cox : TCP ack handling is buggy, the DESTROY timer - * was buggy. Put a remove_sock() in the handler - * for memory when we hit 0. Also altered the timer - * code. The ACK stuff can wait and needs major - * TCP layer surgery. - * Alan Cox : Fixed TCP ack bug, removed remove sock - * and fixed timer/inet_bh race. - * Alan Cox : Added zapped flag for TCP - * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code - * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb - * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources - * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing. - * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so... - * Rick Sladkey : Relaxed UDP rules for matching packets. - * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support - * Pauline Middelink : identd support - * Alan Cox : Fixed connect() taking signals I think. - * Alan Cox : SO_LINGER supported - * Alan Cox : Error reporting fixes - * Anonymous : inet_create tidied up (sk->reuse setting) - * Alan Cox : inet sockets don't set sk->type! - * Alan Cox : Split socket option code - * Alan Cox : Callbacks - * Alan Cox : Nagle flag for Charles & Johannes stuff - * Alex : Removed restriction on inet fioctl - * Alan Cox : Splitting INET from NET core - * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt() - * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code - * Alan Cox : Split IP from generic code - * Alan Cox : New kfree_skbmem() - * Alan Cox : Make SO_DEBUG superuser only. - * Alan Cox : Allow anyone to clear SO_DEBUG - * (compatibility fix) - * Alan Cox : Added optimistic memory grabbing for AF_UNIX throughput. - * Alan Cox : Allocator for a socket is settable. - * Alan Cox : SO_ERROR includes soft errors. - * Alan Cox : Allow NULL arguments on some SO_ opts - * Alan Cox : Generic socket allocation to make hooks - * easier (suggested by Craig Metz). - * Michael Pall : SO_ERROR returns positive errno again - * Steve Whitehouse: Added default destructor to free - * protocol private data. - * Steve Whitehouse: Added various other default routines - * common to several socket families. - * Chris Evans : Call suser() check last on F_SETOWN - * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER. - * Andi Kleen : Add sock_kmalloc()/sock_kfree_s() - * Andi Kleen : Fix write_space callback - * Chris Evans : Security fixes - signedness again - * Arnaldo C. Melo : cleanups, use skb_queue_purge - * - * To Fix: - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/capability.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/socket.h> -#include <linux/in.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/string.h> -#include <linux/sockios.h> -#include <linux/net.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/poll.h> -#include <linux/tcp.h> -#include <linux/init.h> -#include <linux/highmem.h> - -#include <asm/uaccess.h> -#include <asm/system.h> - -#include <linux/netdevice.h> -#include <net/protocol.h> -#include <linux/skbuff.h> -#include <net/net_namespace.h> -#include <net/request_sock.h> -#include <net/sock.h> -#include <net/xfrm.h> -#include <linux/ipsec.h> - -#include <linux/filter.h> - -#ifdef CONFIG_INET -#include <net/tcp.h> -#endif - -/* - * Each address family might have different locking rules, so we have - * one slock key per address family: - */ -static struct lock_class_key af_family_keys[AF_MAX]; -static struct lock_class_key af_family_slock_keys[AF_MAX]; - -/* - * Make lock validator output more readable. (we pre-construct these - * strings build-time, so that runtime initialization of socket - * locks is fast): - */ -static const char *af_family_key_strings[AF_MAX+1] = { - "sk_lock-AF_UNSPEC", "sk_lock-AF_UNIX" , "sk_lock-AF_INET" , - "sk_lock-AF_AX25" , "sk_lock-AF_IPX" , "sk_lock-AF_APPLETALK", - "sk_lock-AF_NETROM", "sk_lock-AF_BRIDGE" , "sk_lock-AF_ATMPVC" , - "sk_lock-AF_X25" , "sk_lock-AF_INET6" , "sk_lock-AF_ROSE" , - "sk_lock-AF_DECnet", "sk_lock-AF_NETBEUI" , "sk_lock-AF_SECURITY" , - "sk_lock-AF_KEY" , "sk_lock-AF_NETLINK" , "sk_lock-AF_PACKET" , - "sk_lock-AF_ASH" , "sk_lock-AF_ECONET" , "sk_lock-AF_ATMSVC" , - "sk_lock-21" , "sk_lock-AF_SNA" , "sk_lock-AF_IRDA" , - "sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE" , "sk_lock-AF_LLC" , - "sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" , - "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , - "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , - "sk_lock-AF_MAX" -}; -static const char *af_family_slock_key_strings[AF_MAX+1] = { - "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , - "slock-AF_AX25" , "slock-AF_IPX" , "slock-AF_APPLETALK", - "slock-AF_NETROM", "slock-AF_BRIDGE" , "slock-AF_ATMPVC" , - "slock-AF_X25" , "slock-AF_INET6" , "slock-AF_ROSE" , - "slock-AF_DECnet", "slock-AF_NETBEUI" , "slock-AF_SECURITY" , - "slock-AF_KEY" , "slock-AF_NETLINK" , "slock-AF_PACKET" , - "slock-AF_ASH" , "slock-AF_ECONET" , "slock-AF_ATMSVC" , - "slock-21" , "slock-AF_SNA" , "slock-AF_IRDA" , - "slock-AF_PPPOX" , "slock-AF_WANPIPE" , "slock-AF_LLC" , - "slock-27" , "slock-28" , "slock-AF_CAN" , - "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , - "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , - "slock-AF_MAX" -}; -static const char *af_family_clock_key_strings[AF_MAX+1] = { - "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , - "clock-AF_AX25" , "clock-AF_IPX" , "clock-AF_APPLETALK", - "clock-AF_NETROM", "clock-AF_BRIDGE" , "clock-AF_ATMPVC" , - "clock-AF_X25" , "clock-AF_INET6" , "clock-AF_ROSE" , - "clock-AF_DECnet", "clock-AF_NETBEUI" , "clock-AF_SECURITY" , - "clock-AF_KEY" , "clock-AF_NETLINK" , "clock-AF_PACKET" , - "clock-AF_ASH" , "clock-AF_ECONET" , "clock-AF_ATMSVC" , - "clock-21" , "clock-AF_SNA" , "clock-AF_IRDA" , - "clock-AF_PPPOX" , "clock-AF_WANPIPE" , "clock-AF_LLC" , - "clock-27" , "clock-28" , "clock-AF_CAN" , - "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , - "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , - "clock-AF_MAX" -}; - -/* - * sk_callback_lock locking rules are per-address-family, - * so split the lock classes by using a per-AF key: - */ -static struct lock_class_key af_callback_keys[AF_MAX]; - -/* Take into consideration the size of the struct sk_buff overhead in the - * determination of these values, since that is non-constant across - * platforms. This makes socket queueing behavior and performance - * not depend upon such differences. - */ -#define _SK_MEM_PACKETS 256 -#define _SK_MEM_OVERHEAD (sizeof(struct sk_buff) + 256) -#define SK_WMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) -#define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) - -/* Run time adjustable parameters. */ -__u32 sysctl_wmem_max __read_mostly = SK_WMEM_MAX; -__u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX; -__u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX; -__u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; - -/* Maximal space eaten by iovec or ancilliary data plus some space */ -int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); - -static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) -{ - struct timeval tv; - - if (optlen < sizeof(tv)) - return -EINVAL; - if (copy_from_user(&tv, optval, sizeof(tv))) - return -EFAULT; - if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC) - return -EDOM; - - if (tv.tv_sec < 0) { - static int warned __read_mostly; - - *timeo_p = 0; - if (warned < 10 && net_ratelimit()) { - warned++; - printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) " - "tries to set negative timeout\n", - current->comm, task_pid_nr(current)); - } - return 0; - } - *timeo_p = MAX_SCHEDULE_TIMEOUT; - if (tv.tv_sec == 0 && tv.tv_usec == 0) - return 0; - if (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT/HZ - 1)) - *timeo_p = tv.tv_sec*HZ + (tv.tv_usec+(1000000/HZ-1))/(1000000/HZ); - return 0; -} - -static void sock_warn_obsolete_bsdism(const char *name) -{ - static int warned; - static char warncomm[TASK_COMM_LEN]; - if (strcmp(warncomm, current->comm) && warned < 5) { - strcpy(warncomm, current->comm); - printk(KERN_WARNING "process `%s' is using obsolete " - "%s SO_BSDCOMPAT\n", warncomm, name); - warned++; - } -} - -static void sock_disable_timestamp(struct sock *sk) -{ - if (sock_flag(sk, SOCK_TIMESTAMP)) { - sock_reset_flag(sk, SOCK_TIMESTAMP); - net_disable_timestamp(); - } -} - - -int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - int err = 0; - int skb_len; - - /* Cast sk->rcvbuf to unsigned... It's pointless, but reduces - number of warnings when compiling with -W --ANK - */ - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) { - err = -ENOMEM; - goto out; - } - - err = sk_filter(sk, skb); - if (err) - goto out; - - if (!sk_rmem_schedule(sk, skb->truesize)) { - err = -ENOBUFS; - goto out; - } - - skb->dev = NULL; - skb_set_owner_r(skb, sk); - - /* Cache the SKB length before we tack it onto the receive - * queue. Once it is added it no longer belongs to us and - * may be freed by other threads of control pulling packets - * from the queue. - */ - skb_len = skb->len; - - skb_queue_tail(&sk->sk_receive_queue, skb); - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk, skb_len); -out: - return err; -} -EXPORT_SYMBOL(sock_queue_rcv_skb); - -int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested) -{ - int rc = NET_RX_SUCCESS; - - if (sk_filter(sk, skb)) - goto discard_and_relse; - - skb->dev = NULL; - - if (nested) - bh_lock_sock_nested(sk); - else - bh_lock_sock(sk); - if (!sock_owned_by_user(sk)) { - /* - * trylock + unlock semantics: - */ - mutex_acquire(&sk->sk_lock.dep_map, 0, 1, _RET_IP_); - - rc = sk_backlog_rcv(sk, skb); - - mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); - } else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); -out: - sock_put(sk); - return rc; -discard_and_relse: - kfree_skb(skb); - goto out; -} -EXPORT_SYMBOL(sk_receive_skb); - -struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) -{ - struct dst_entry *dst = sk->sk_dst_cache; - - if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { - sk->sk_dst_cache = NULL; - dst_release(dst); - return NULL; - } - - return dst; -} -EXPORT_SYMBOL(__sk_dst_check); - -struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie) -{ - struct dst_entry *dst = sk_dst_get(sk); - - if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { - sk_dst_reset(sk); - dst_release(dst); - return NULL; - } - - return dst; -} -EXPORT_SYMBOL(sk_dst_check); - -static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) -{ - int ret = -ENOPROTOOPT; -#ifdef CONFIG_NETDEVICES - struct net *net = sock_net(sk); - char devname[IFNAMSIZ]; - int index; - - /* Sorry... */ - ret = -EPERM; - if (!capable(CAP_NET_RAW)) - goto out; - - ret = -EINVAL; - if (optlen < 0) - goto out; - - /* Bind this socket to a particular device like "eth0", - * as specified in the passed interface name. If the - * name is "" or the option length is zero the socket - * is not bound. - */ - if (optlen > IFNAMSIZ - 1) - optlen = IFNAMSIZ - 1; - memset(devname, 0, sizeof(devname)); - - ret = -EFAULT; - if (copy_from_user(devname, optval, optlen)) - goto out; - - if (devname[0] == '\0') { - index = 0; - } else { - struct net_device *dev = dev_get_by_name(net, devname); - - ret = -ENODEV; - if (!dev) - goto out; - - index = dev->ifindex; - dev_put(dev); - } - - lock_sock(sk); - sk->sk_bound_dev_if = index; - sk_dst_reset(sk); - release_sock(sk); - - ret = 0; - -out: -#endif - - return ret; -} - -static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) -{ - if (valbool) - sock_set_flag(sk, bit); - else - sock_reset_flag(sk, bit); -} - -/* - * This is meant for all protocols to use and covers goings on - * at the socket level. Everything here is generic. - */ - -int sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) -{ - struct sock *sk=sock->sk; - int val; - int valbool; - struct linger ling; - int ret = 0; - - /* - * Options without arguments - */ - - if (optname == SO_BINDTODEVICE) - return sock_bindtodevice(sk, optval, optlen); - - if (optlen < sizeof(int)) - return -EINVAL; - - if (get_user(val, (int __user *)optval)) - return -EFAULT; - - valbool = val?1:0; - - lock_sock(sk); - - switch(optname) { - case SO_DEBUG: - if (val && !capable(CAP_NET_ADMIN)) { - ret = -EACCES; - } else - sock_valbool_flag(sk, SOCK_DBG, valbool); - break; - case SO_REUSEADDR: - sk->sk_reuse = valbool; - break; - case SO_TYPE: - case SO_ERROR: - ret = -ENOPROTOOPT; - break; - case SO_DONTROUTE: - sock_valbool_flag(sk, SOCK_LOCALROUTE, valbool); - break; - case SO_BROADCAST: - sock_valbool_flag(sk, SOCK_BROADCAST, valbool); - break; - case SO_SNDBUF: - /* Don't error on this BSD doesn't and if you think - about it this is right. Otherwise apps have to - play 'guess the biggest size' games. RCVBUF/SNDBUF - are treated in BSD as hints */ - - if (val > sysctl_wmem_max) - val = sysctl_wmem_max; -set_sndbuf: - sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - if ((val * 2) < SOCK_MIN_SNDBUF) - sk->sk_sndbuf = SOCK_MIN_SNDBUF; - else - sk->sk_sndbuf = val * 2; - - /* - * Wake up sending tasks if we - * upped the value. - */ - sk->sk_write_space(sk); - break; - - case SO_SNDBUFFORCE: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - goto set_sndbuf; - - case SO_RCVBUF: - /* Don't error on this BSD doesn't and if you think - about it this is right. Otherwise apps have to - play 'guess the biggest size' games. RCVBUF/SNDBUF - are treated in BSD as hints */ - - if (val > sysctl_rmem_max) - val = sysctl_rmem_max; -set_rcvbuf: - sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - /* - * We double it on the way in to account for - * "struct sk_buff" etc. overhead. Applications - * assume that the SO_RCVBUF setting they make will - * allow that much actual data to be received on that - * socket. - * - * Applications are unaware that "struct sk_buff" and - * other overheads allocate from the receive buffer - * during socket buffer allocation. - * - * And after considering the possible alternatives, - * returning the value we actually used in getsockopt - * is the most desirable behavior. - */ - if ((val * 2) < SOCK_MIN_RCVBUF) - sk->sk_rcvbuf = SOCK_MIN_RCVBUF; - else - sk->sk_rcvbuf = val * 2; - break; - - case SO_RCVBUFFORCE: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - goto set_rcvbuf; - - case SO_KEEPALIVE: -#ifdef CONFIG_INET - if (sk->sk_protocol == IPPROTO_TCP) - tcp_set_keepalive(sk, valbool); -#endif - sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool); - break; - - case SO_OOBINLINE: - sock_valbool_flag(sk, SOCK_URGINLINE, valbool); - break; - - case SO_NO_CHECK: - sk->sk_no_check = valbool; - break; - - case SO_PRIORITY: - if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN)) - sk->sk_priority = val; - else - ret = -EPERM; - break; - - case SO_LINGER: - if (optlen < sizeof(ling)) { - ret = -EINVAL; /* 1003.1g */ - break; - } - if (copy_from_user(&ling,optval,sizeof(ling))) { - ret = -EFAULT; - break; - } - if (!ling.l_onoff) - sock_reset_flag(sk, SOCK_LINGER); - else { -#if (BITS_PER_LONG == 32) - if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) - sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; - else -#endif - sk->sk_lingertime = (unsigned int)ling.l_linger * HZ; - sock_set_flag(sk, SOCK_LINGER); - } - break; - - case SO_BSDCOMPAT: - sock_warn_obsolete_bsdism("setsockopt"); - break; - - case SO_PASSCRED: - if (valbool) - set_bit(SOCK_PASSCRED, &sock->flags); - else - clear_bit(SOCK_PASSCRED, &sock->flags); - break; - - case SO_TIMESTAMP: - case SO_TIMESTAMPNS: - if (valbool) { - if (optname == SO_TIMESTAMP) - sock_reset_flag(sk, SOCK_RCVTSTAMPNS); - else - sock_set_flag(sk, SOCK_RCVTSTAMPNS); - sock_set_flag(sk, SOCK_RCVTSTAMP); - sock_enable_timestamp(sk); - } else { - sock_reset_flag(sk, SOCK_RCVTSTAMP); - sock_reset_flag(sk, SOCK_RCVTSTAMPNS); - } - break; - - case SO_RCVLOWAT: - if (val < 0) - val = INT_MAX; - sk->sk_rcvlowat = val ? : 1; - break; - - case SO_RCVTIMEO: - ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen); - break; - - case SO_SNDTIMEO: - ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen); - break; - - case SO_ATTACH_FILTER: - ret = -EINVAL; - if (optlen == sizeof(struct sock_fprog)) { - struct sock_fprog fprog; - - ret = -EFAULT; - if (copy_from_user(&fprog, optval, sizeof(fprog))) - break; - - ret = sk_attach_filter(&fprog, sk); - } - break; - - case SO_DETACH_FILTER: - ret = sk_detach_filter(sk); - break; - - case SO_PASSSEC: - if (valbool) - set_bit(SOCK_PASSSEC, &sock->flags); - else - clear_bit(SOCK_PASSSEC, &sock->flags); - break; - case SO_MARK: - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else { - sk->sk_mark = val; - } - break; - - /* We implement the SO_SNDLOWAT etc to - not be settable (1003.1g 5.3) */ - default: - ret = -ENOPROTOOPT; - break; - } - release_sock(sk); - return ret; -} - - -int sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - - union { - int val; - struct linger ling; - struct timeval tm; - } v; - - unsigned int lv = sizeof(int); - int len; - - if (get_user(len, optlen)) - return -EFAULT; - if (len < 0) - return -EINVAL; - - memset(&v, 0, sizeof(v)); - - switch(optname) { - case SO_DEBUG: - v.val = sock_flag(sk, SOCK_DBG); - break; - - case SO_DONTROUTE: - v.val = sock_flag(sk, SOCK_LOCALROUTE); - break; - - case SO_BROADCAST: - v.val = !!sock_flag(sk, SOCK_BROADCAST); - break; - - case SO_SNDBUF: - v.val = sk->sk_sndbuf; - break; - - case SO_RCVBUF: - v.val = sk->sk_rcvbuf; - break; - - case SO_REUSEADDR: - v.val = sk->sk_reuse; - break; - - case SO_KEEPALIVE: - v.val = !!sock_flag(sk, SOCK_KEEPOPEN); - break; - - case SO_TYPE: - v.val = sk->sk_type; - break; - - case SO_ERROR: - v.val = -sock_error(sk); - if (v.val==0) - v.val = xchg(&sk->sk_err_soft, 0); - break; - - case SO_OOBINLINE: - v.val = !!sock_flag(sk, SOCK_URGINLINE); - break; - - case SO_NO_CHECK: - v.val = sk->sk_no_check; - break; - - case SO_PRIORITY: - v.val = sk->sk_priority; - break; - - case SO_LINGER: - lv = sizeof(v.ling); - v.ling.l_onoff = !!sock_flag(sk, SOCK_LINGER); - v.ling.l_linger = sk->sk_lingertime / HZ; - break; - - case SO_BSDCOMPAT: - sock_warn_obsolete_bsdism("getsockopt"); - break; - - case SO_TIMESTAMP: - v.val = sock_flag(sk, SOCK_RCVTSTAMP) && - !sock_flag(sk, SOCK_RCVTSTAMPNS); - break; - - case SO_TIMESTAMPNS: - v.val = sock_flag(sk, SOCK_RCVTSTAMPNS); - break; - - case SO_RCVTIMEO: - lv=sizeof(struct timeval); - if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) { - v.tm.tv_sec = 0; - v.tm.tv_usec = 0; - } else { - v.tm.tv_sec = sk->sk_rcvtimeo / HZ; - v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * 1000000) / HZ; - } - break; - - case SO_SNDTIMEO: - lv=sizeof(struct timeval); - if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) { - v.tm.tv_sec = 0; - v.tm.tv_usec = 0; - } else { - v.tm.tv_sec = sk->sk_sndtimeo / HZ; - v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * 1000000) / HZ; - } - break; - - case SO_RCVLOWAT: - v.val = sk->sk_rcvlowat; - break; - - case SO_SNDLOWAT: - v.val=1; - break; - - case SO_PASSCRED: - v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0; - break; - - case SO_PEERCRED: - if (len > sizeof(sk->sk_peercred)) - len = sizeof(sk->sk_peercred); - if (copy_to_user(optval, &sk->sk_peercred, len)) - return -EFAULT; - goto lenout; - - case SO_PEERNAME: - { - char address[128]; - - if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2)) - return -ENOTCONN; - if (lv < len) - return -EINVAL; - if (copy_to_user(optval, address, len)) - return -EFAULT; - goto lenout; - } - - /* Dubious BSD thing... Probably nobody even uses it, but - * the UNIX standard wants it for whatever reason... -DaveM - */ - case SO_ACCEPTCONN: - v.val = sk->sk_state == TCP_LISTEN; - break; - - case SO_PASSSEC: - v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0; - break; - - case SO_PEERSEC: - return security_socket_getpeersec_stream(sock, optval, optlen, len); - - case SO_MARK: - v.val = sk->sk_mark; - break; - - default: - return -ENOPROTOOPT; - } - - if (len > lv) - len = lv; - if (copy_to_user(optval, &v, len)) - return -EFAULT; -lenout: - if (put_user(len, optlen)) - return -EFAULT; - return 0; -} - -/* - * Initialize an sk_lock. - * - * (We also register the sk_lock with the lock validator.) - */ -static inline void sock_lock_init(struct sock *sk) -{ - sock_lock_init_class_and_name(sk, - af_family_slock_key_strings[sk->sk_family], - af_family_slock_keys + sk->sk_family, - af_family_key_strings[sk->sk_family], - af_family_keys + sk->sk_family); -} - -static void sock_copy(struct sock *nsk, const struct sock *osk) -{ -#ifdef CONFIG_SECURITY_NETWORK - void *sptr = nsk->sk_security; -#endif - - memcpy(nsk, osk, osk->sk_prot->obj_size); -#ifdef CONFIG_SECURITY_NETWORK - nsk->sk_security = sptr; - security_sk_clone(osk, nsk); -#endif -} - -static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, - int family) -{ - struct sock *sk; - struct kmem_cache *slab; - - slab = prot->slab; - if (slab != NULL) - sk = kmem_cache_alloc(slab, priority); - else - sk = kmalloc(prot->obj_size, priority); - - if (sk != NULL) { - if (security_sk_alloc(sk, family, priority)) - goto out_free; - - if (!try_module_get(prot->owner)) - goto out_free_sec; - } - - return sk; - -out_free_sec: - security_sk_free(sk); -out_free: - if (slab != NULL) - kmem_cache_free(slab, sk); - else - kfree(sk); - return NULL; -} - -static void sk_prot_free(struct proto *prot, struct sock *sk) -{ - struct kmem_cache *slab; - struct module *owner; - - owner = prot->owner; - slab = prot->slab; - - security_sk_free(sk); - if (slab != NULL) - kmem_cache_free(slab, sk); - else - kfree(sk); - module_put(owner); -} - -/** - * sk_alloc - All socket objects are allocated here - * @net: the applicable net namespace - * @family: protocol family - * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) - * @prot: struct proto associated with this new sock instance - */ -struct sock *sk_alloc(struct net *net, int family, gfp_t priority, - struct proto *prot) -{ - struct sock *sk; - - sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family); - if (sk) { - sk->sk_family = family; - /* - * See comment in struct sock definition to understand - * why we need sk_prot_creator -acme - */ - sk->sk_prot = sk->sk_prot_creator = prot; - sock_lock_init(sk); - sock_net_set(sk, get_net(net)); - } - - return sk; -} - -void sk_free(struct sock *sk) -{ - struct sk_filter *filter; - - if (sk->sk_destruct) - sk->sk_destruct(sk); - - filter = rcu_dereference(sk->sk_filter); - if (filter) { - sk_filter_uncharge(sk, filter); - rcu_assign_pointer(sk->sk_filter, NULL); - } - - sock_disable_timestamp(sk); - - if (atomic_read(&sk->sk_omem_alloc)) - printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", - __func__, atomic_read(&sk->sk_omem_alloc)); - - put_net(sock_net(sk)); - sk_prot_free(sk->sk_prot_creator, sk); -} - -/* - * Last sock_put should drop referrence to sk->sk_net. It has already - * been dropped in sk_change_net. Taking referrence to stopping namespace - * is not an option. - * Take referrence to a socket to remove it from hash _alive_ and after that - * destroy it in the context of init_net. - */ -void sk_release_kernel(struct sock *sk) -{ - if (sk == NULL || sk->sk_socket == NULL) - return; - - sock_hold(sk); - sock_release(sk->sk_socket); - release_net(sock_net(sk)); - sock_net_set(sk, get_net(&init_net)); - sock_put(sk); -} -EXPORT_SYMBOL(sk_release_kernel); - -struct sock *sk_clone(const struct sock *sk, const gfp_t priority) -{ - struct sock *newsk; - - newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family); - if (newsk != NULL) { - struct sk_filter *filter; - - sock_copy(newsk, sk); - - /* SANITY */ - get_net(sock_net(newsk)); - sk_node_init(&newsk->sk_node); - sock_lock_init(newsk); - bh_lock_sock(newsk); - newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; - - atomic_set(&newsk->sk_rmem_alloc, 0); - atomic_set(&newsk->sk_wmem_alloc, 0); - atomic_set(&newsk->sk_omem_alloc, 0); - skb_queue_head_init(&newsk->sk_receive_queue); - skb_queue_head_init(&newsk->sk_write_queue); -#ifdef CONFIG_NET_DMA - skb_queue_head_init(&newsk->sk_async_wait_queue); -#endif - - rwlock_init(&newsk->sk_dst_lock); - rwlock_init(&newsk->sk_callback_lock); - lockdep_set_class_and_name(&newsk->sk_callback_lock, - af_callback_keys + newsk->sk_family, - af_family_clock_key_strings[newsk->sk_family]); - - newsk->sk_dst_cache = NULL; - newsk->sk_wmem_queued = 0; - newsk->sk_forward_alloc = 0; - newsk->sk_send_head = NULL; - newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; - - sock_reset_flag(newsk, SOCK_DONE); - skb_queue_head_init(&newsk->sk_error_queue); - - filter = newsk->sk_filter; - if (filter != NULL) - sk_filter_charge(newsk, filter); - - if (unlikely(xfrm_sk_clone_policy(newsk))) { - /* It is still raw copy of parent, so invalidate - * destructor and make plain sk_free() */ - newsk->sk_destruct = NULL; - sk_free(newsk); - newsk = NULL; - goto out; - } - - newsk->sk_err = 0; - newsk->sk_priority = 0; - atomic_set(&newsk->sk_refcnt, 2); - - /* - * Increment the counter in the same struct proto as the master - * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that - * is the same as sk->sk_prot->socks, as this field was copied - * with memcpy). - * - * This _changes_ the previous behaviour, where - * tcp_create_openreq_child always was incrementing the - * equivalent to tcp_prot->socks (inet_sock_nr), so this have - * to be taken into account in all callers. -acme - */ - sk_refcnt_debug_inc(newsk); - sk_set_socket(newsk, NULL); - newsk->sk_sleep = NULL; - - if (newsk->sk_prot->sockets_allocated) - percpu_counter_inc(newsk->sk_prot->sockets_allocated); - } -out: - return newsk; -} - -EXPORT_SYMBOL_GPL(sk_clone); - -void sk_setup_caps(struct sock *sk, struct dst_entry *dst) -{ - __sk_dst_set(sk, dst); - sk->sk_route_caps = dst->dev->features; - if (sk->sk_route_caps & NETIF_F_GSO) - sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; - if (sk_can_gso(sk)) { - if (dst->header_len) { - sk->sk_route_caps &= ~NETIF_F_GSO_MASK; - } else { - sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; - sk->sk_gso_max_size = dst->dev->gso_max_size; - } - } -} -EXPORT_SYMBOL_GPL(sk_setup_caps); - -void __init sk_init(void) -{ - if (num_physpages <= 4096) { - sysctl_wmem_max = 32767; - sysctl_rmem_max = 32767; - sysctl_wmem_default = 32767; - sysctl_rmem_default = 32767; - } else if (num_physpages >= 131072) { - sysctl_wmem_max = 131071; - sysctl_rmem_max = 131071; - } -} - -/* - * Simple resource managers for sockets. - */ - - -/* - * Write buffer destructor automatically called from kfree_skb. - */ -void sock_wfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - /* In case it might be waiting for more memory. */ - atomic_sub(skb->truesize, &sk->sk_wmem_alloc); - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) - sk->sk_write_space(sk); - sock_put(sk); -} - -/* - * Read buffer destructor automatically called from kfree_skb. - */ -void sock_rfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - atomic_sub(skb->truesize, &sk->sk_rmem_alloc); - sk_mem_uncharge(skb->sk, skb->truesize); -} - - -int sock_i_uid(struct sock *sk) -{ - int uid; - - read_lock(&sk->sk_callback_lock); - uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0; - read_unlock(&sk->sk_callback_lock); - return uid; -} - -unsigned long sock_i_ino(struct sock *sk) -{ - unsigned long ino; - - read_lock(&sk->sk_callback_lock); - ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; - read_unlock(&sk->sk_callback_lock); - return ino; -} - -/* - * Allocate a skb from the socket's send buffer. - */ -struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, - gfp_t priority) -{ - if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { - struct sk_buff * skb = alloc_skb(size, priority); - if (skb) { - skb_set_owner_w(skb, sk); - return skb; - } - } - return NULL; -} - -/* - * Allocate a skb from the socket's receive buffer. - */ -struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, - gfp_t priority) -{ - if (force || atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) { - struct sk_buff *skb = alloc_skb(size, priority); - if (skb) { - skb_set_owner_r(skb, sk); - return skb; - } - } - return NULL; -} - -/* - * Allocate a memory block from the socket's option memory buffer. - */ -void *sock_kmalloc(struct sock *sk, int size, gfp_t priority) -{ - if ((unsigned)size <= sysctl_optmem_max && - atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) { - void *mem; - /* First do the add, to avoid the race if kmalloc - * might sleep. - */ - atomic_add(size, &sk->sk_omem_alloc); - mem = kmalloc(size, priority); - if (mem) - return mem; - atomic_sub(size, &sk->sk_omem_alloc); - } - return NULL; -} - -/* - * Free an option memory block. - */ -void sock_kfree_s(struct sock *sk, void *mem, int size) -{ - kfree(mem); - atomic_sub(size, &sk->sk_omem_alloc); -} - -/* It is almost wait_for_tcp_memory minus release_sock/lock_sock. - I think, these locks should be removed for datagram sockets. - */ -static long sock_wait_for_wmem(struct sock * sk, long timeo) -{ - DEFINE_WAIT(wait); - - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); - for (;;) { - if (!timeo) - break; - if (signal_pending(current)) - break; - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) - break; - if (sk->sk_shutdown & SEND_SHUTDOWN) - break; - if (sk->sk_err) - break; - timeo = schedule_timeout(timeo); - } - finish_wait(sk->sk_sleep, &wait); - return timeo; -} - - -/* - * Generic send/receive buffer handlers - */ - -static struct sk_buff *sock_alloc_send_pskb(struct sock *sk, - unsigned long header_len, - unsigned long data_len, - int noblock, int *errcode) -{ - struct sk_buff *skb; - gfp_t gfp_mask; - long timeo; - int err; - - gfp_mask = sk->sk_allocation; - if (gfp_mask & __GFP_WAIT) - gfp_mask |= __GFP_REPEAT; - - timeo = sock_sndtimeo(sk, noblock); - while (1) { - err = sock_error(sk); - if (err != 0) - goto failure; - - err = -EPIPE; - if (sk->sk_shutdown & SEND_SHUTDOWN) - goto failure; - - if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { - skb = alloc_skb(header_len, gfp_mask); - if (skb) { - int npages; - int i; - - /* No pages, we're done... */ - if (!data_len) - break; - - npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - skb->truesize += data_len; - skb_shinfo(skb)->nr_frags = npages; - for (i = 0; i < npages; i++) { - struct page *page; - skb_frag_t *frag; - - page = alloc_pages(sk->sk_allocation, 0); - if (!page) { - err = -ENOBUFS; - skb_shinfo(skb)->nr_frags = i; - kfree_skb(skb); - goto failure; - } - - frag = &skb_shinfo(skb)->frags[i]; - frag->page = page; - frag->page_offset = 0; - frag->size = (data_len >= PAGE_SIZE ? - PAGE_SIZE : - data_len); - data_len -= PAGE_SIZE; - } - - /* Full success... */ - break; - } - err = -ENOBUFS; - goto failure; - } - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - err = -EAGAIN; - if (!timeo) - goto failure; - if (signal_pending(current)) - goto interrupted; - timeo = sock_wait_for_wmem(sk, timeo); - } - - skb_set_owner_w(skb, sk); - return skb; - -interrupted: - err = sock_intr_errno(timeo); -failure: - *errcode = err; - return NULL; -} - -struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - int noblock, int *errcode) -{ - return sock_alloc_send_pskb(sk, size, 0, noblock, errcode); -} - -static void __lock_sock(struct sock *sk) -{ - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait_exclusive(&sk->sk_lock.wq, &wait, - TASK_UNINTERRUPTIBLE); - spin_unlock_bh(&sk->sk_lock.slock); - schedule(); - spin_lock_bh(&sk->sk_lock.slock); - if (!sock_owned_by_user(sk)) - break; - } - finish_wait(&sk->sk_lock.wq, &wait); -} - -static void __release_sock(struct sock *sk) -{ - struct sk_buff *skb = sk->sk_backlog.head; - - do { - sk->sk_backlog.head = sk->sk_backlog.tail = NULL; - bh_unlock_sock(sk); - - do { - struct sk_buff *next = skb->next; - - skb->next = NULL; - sk_backlog_rcv(sk, skb); - - /* - * We are in process context here with softirqs - * disabled, use cond_resched_softirq() to preempt. - * This is safe to do because we've taken the backlog - * queue private: - */ - cond_resched_softirq(); - - skb = next; - } while (skb != NULL); - - bh_lock_sock(sk); - } while ((skb = sk->sk_backlog.head) != NULL); -} - -/** - * sk_wait_data - wait for data to arrive at sk_receive_queue - * @sk: sock to wait on - * @timeo: for how long - * - * Now socket state including sk->sk_err is changed only under lock, - * hence we may omit checks after joining wait queue. - * We check receive queue before schedule() only as optimization; - * it is very likely that release_sock() added new data. - */ -int sk_wait_data(struct sock *sk, long *timeo) -{ - int rc; - DEFINE_WAIT(wait); - - prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue)); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - finish_wait(sk->sk_sleep, &wait); - return rc; -} - -EXPORT_SYMBOL(sk_wait_data); - -/** - * __sk_mem_schedule - increase sk_forward_alloc and memory_allocated - * @sk: socket - * @size: memory size to allocate - * @kind: allocation type - * - * If kind is SK_MEM_SEND, it means wmem allocation. Otherwise it means - * rmem allocation. This function assumes that protocols which have - * memory_pressure use sk_wmem_queued as write buffer accounting. - */ -int __sk_mem_schedule(struct sock *sk, int size, int kind) -{ - struct proto *prot = sk->sk_prot; - int amt = sk_mem_pages(size); - int allocated; - - sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; - allocated = atomic_add_return(amt, prot->memory_allocated); - - /* Under limit. */ - if (allocated <= prot->sysctl_mem[0]) { - if (prot->memory_pressure && *prot->memory_pressure) - *prot->memory_pressure = 0; - return 1; - } - - /* Under pressure. */ - if (allocated > prot->sysctl_mem[1]) - if (prot->enter_memory_pressure) - prot->enter_memory_pressure(sk); - - /* Over hard limit. */ - if (allocated > prot->sysctl_mem[2]) - goto suppress_allocation; - - /* guarantee minimum buffer size under pressure */ - if (kind == SK_MEM_RECV) { - if (atomic_read(&sk->sk_rmem_alloc) < prot->sysctl_rmem[0]) - return 1; - } else { /* SK_MEM_SEND */ - if (sk->sk_type == SOCK_STREAM) { - if (sk->sk_wmem_queued < prot->sysctl_wmem[0]) - return 1; - } else if (atomic_read(&sk->sk_wmem_alloc) < - prot->sysctl_wmem[0]) - return 1; - } - - if (prot->memory_pressure) { - int alloc; - - if (!*prot->memory_pressure) - return 1; - alloc = percpu_counter_read_positive(prot->sockets_allocated); - if (prot->sysctl_mem[2] > alloc * - sk_mem_pages(sk->sk_wmem_queued + - atomic_read(&sk->sk_rmem_alloc) + - sk->sk_forward_alloc)) - return 1; - } - -suppress_allocation: - - if (kind == SK_MEM_SEND && sk->sk_type == SOCK_STREAM) { - sk_stream_moderate_sndbuf(sk); - - /* Fail only if socket is _under_ its sndbuf. - * In this case we cannot block, so that we have to fail. - */ - if (sk->sk_wmem_queued + size >= sk->sk_sndbuf) - return 1; - } - - /* Alas. Undo changes. */ - sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; - atomic_sub(amt, prot->memory_allocated); - return 0; -} - -EXPORT_SYMBOL(__sk_mem_schedule); - -/** - * __sk_reclaim - reclaim memory_allocated - * @sk: socket - */ -void __sk_mem_reclaim(struct sock *sk) -{ - struct proto *prot = sk->sk_prot; - - atomic_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, - prot->memory_allocated); - sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; - - if (prot->memory_pressure && *prot->memory_pressure && - (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0])) - *prot->memory_pressure = 0; -} - -EXPORT_SYMBOL(__sk_mem_reclaim); - - -/* - * Set of default routines for initialising struct proto_ops when - * the protocol does not support a particular function. In certain - * cases where it makes no sense for a protocol to have a "do nothing" - * function, some default processing is provided. - */ - -int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len) -{ - return -EOPNOTSUPP; -} - -int sock_no_connect(struct socket *sock, struct sockaddr *saddr, - int len, int flags) -{ - return -EOPNOTSUPP; -} - -int sock_no_socketpair(struct socket *sock1, struct socket *sock2) -{ - return -EOPNOTSUPP; -} - -int sock_no_accept(struct socket *sock, struct socket *newsock, int flags) -{ - return -EOPNOTSUPP; -} - -int sock_no_getname(struct socket *sock, struct sockaddr *saddr, - int *len, int peer) -{ - return -EOPNOTSUPP; -} - -unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt) -{ - return 0; -} - -int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - return -EOPNOTSUPP; -} - -int sock_no_listen(struct socket *sock, int backlog) -{ - return -EOPNOTSUPP; -} - -int sock_no_shutdown(struct socket *sock, int how) -{ - return -EOPNOTSUPP; -} - -int sock_no_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) -{ - return -EOPNOTSUPP; -} - -int sock_no_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - return -EOPNOTSUPP; -} - -int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, - size_t len) -{ - return -EOPNOTSUPP; -} - -int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, - size_t len, int flags) -{ - return -EOPNOTSUPP; -} - -int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) -{ - /* Mirror missing mmap method error code */ - return -ENODEV; -} - -ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) -{ - ssize_t res; - struct msghdr msg = {.msg_flags = flags}; - struct kvec iov; - char *kaddr = kmap(page); - iov.iov_base = kaddr + offset; - iov.iov_len = size; - res = kernel_sendmsg(sock, &msg, &iov, 1, size); - kunmap(page); - return res; -} - -/* - * Default Socket Callbacks - */ - -static void sock_def_wakeup(struct sock *sk) -{ - read_lock(&sk->sk_callback_lock); - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_all(sk->sk_sleep); - read_unlock(&sk->sk_callback_lock); -} - -static void sock_def_error_report(struct sock *sk) -{ - read_lock(&sk->sk_callback_lock); - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); - sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR); - read_unlock(&sk->sk_callback_lock); -} - -static void sock_def_readable(struct sock *sk, int len) -{ - read_lock(&sk->sk_callback_lock); - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_sync(sk->sk_sleep); - sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); - read_unlock(&sk->sk_callback_lock); -} - -static void sock_def_write_space(struct sock *sk) -{ - read_lock(&sk->sk_callback_lock); - - /* Do not wake up a writer until he can make "significant" - * progress. --DaveM - */ - if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) { - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_sync(sk->sk_sleep); - - /* Should agree with poll, otherwise some programs break */ - if (sock_writeable(sk)) - sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); - } - - read_unlock(&sk->sk_callback_lock); -} - -static void sock_def_destruct(struct sock *sk) -{ - kfree(sk->sk_protinfo); -} - -void sk_send_sigurg(struct sock *sk) -{ - if (sk->sk_socket && sk->sk_socket->file) - if (send_sigurg(&sk->sk_socket->file->f_owner)) - sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI); -} - -void sk_reset_timer(struct sock *sk, struct timer_list* timer, - unsigned long expires) -{ - if (!mod_timer(timer, expires)) - sock_hold(sk); -} - -EXPORT_SYMBOL(sk_reset_timer); - -void sk_stop_timer(struct sock *sk, struct timer_list* timer) -{ - if (timer_pending(timer) && del_timer(timer)) - __sock_put(sk); -} - -EXPORT_SYMBOL(sk_stop_timer); - -void sock_init_data(struct socket *sock, struct sock *sk) -{ - skb_queue_head_init(&sk->sk_receive_queue); - skb_queue_head_init(&sk->sk_write_queue); - skb_queue_head_init(&sk->sk_error_queue); -#ifdef CONFIG_NET_DMA - skb_queue_head_init(&sk->sk_async_wait_queue); -#endif - - sk->sk_send_head = NULL; - - init_timer(&sk->sk_timer); - - sk->sk_allocation = GFP_KERNEL; - sk->sk_rcvbuf = sysctl_rmem_default; - sk->sk_sndbuf = sysctl_wmem_default; - sk->sk_state = TCP_CLOSE; - sk_set_socket(sk, sock); - - sock_set_flag(sk, SOCK_ZAPPED); - - if (sock) { - sk->sk_type = sock->type; - sk->sk_sleep = &sock->wait; - sock->sk = sk; - } else - sk->sk_sleep = NULL; - - rwlock_init(&sk->sk_dst_lock); - rwlock_init(&sk->sk_callback_lock); - lockdep_set_class_and_name(&sk->sk_callback_lock, - af_callback_keys + sk->sk_family, - af_family_clock_key_strings[sk->sk_family]); - - sk->sk_state_change = sock_def_wakeup; - sk->sk_data_ready = sock_def_readable; - sk->sk_write_space = sock_def_write_space; - sk->sk_error_report = sock_def_error_report; - sk->sk_destruct = sock_def_destruct; - - sk->sk_sndmsg_page = NULL; - sk->sk_sndmsg_off = 0; - - sk->sk_peercred.pid = 0; - sk->sk_peercred.uid = -1; - sk->sk_peercred.gid = -1; - sk->sk_write_pending = 0; - sk->sk_rcvlowat = 1; - sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; - sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; - - sk->sk_stamp = ktime_set(-1L, 0); - - atomic_set(&sk->sk_refcnt, 1); - atomic_set(&sk->sk_drops, 0); -} - -void lock_sock_nested(struct sock *sk, int subclass) -{ - might_sleep(); - spin_lock_bh(&sk->sk_lock.slock); - if (sk->sk_lock.owned) - __lock_sock(sk); - sk->sk_lock.owned = 1; - spin_unlock(&sk->sk_lock.slock); - /* - * The sk_lock has mutex_lock() semantics here: - */ - mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_); - local_bh_enable(); -} - -EXPORT_SYMBOL(lock_sock_nested); - -void release_sock(struct sock *sk) -{ - /* - * The sk_lock has mutex_unlock() semantics: - */ - mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); - - spin_lock_bh(&sk->sk_lock.slock); - if (sk->sk_backlog.tail) - __release_sock(sk); - sk->sk_lock.owned = 0; - if (waitqueue_active(&sk->sk_lock.wq)) - wake_up(&sk->sk_lock.wq); - spin_unlock_bh(&sk->sk_lock.slock); -} -EXPORT_SYMBOL(release_sock); - -int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) -{ - struct timeval tv; - if (!sock_flag(sk, SOCK_TIMESTAMP)) - sock_enable_timestamp(sk); - tv = ktime_to_timeval(sk->sk_stamp); - if (tv.tv_sec == -1) - return -ENOENT; - if (tv.tv_sec == 0) { - sk->sk_stamp = ktime_get_real(); - tv = ktime_to_timeval(sk->sk_stamp); - } - return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0; -} -EXPORT_SYMBOL(sock_get_timestamp); - -int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp) -{ - struct timespec ts; - if (!sock_flag(sk, SOCK_TIMESTAMP)) - sock_enable_timestamp(sk); - ts = ktime_to_timespec(sk->sk_stamp); - if (ts.tv_sec == -1) - return -ENOENT; - if (ts.tv_sec == 0) { - sk->sk_stamp = ktime_get_real(); - ts = ktime_to_timespec(sk->sk_stamp); - } - return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0; -} -EXPORT_SYMBOL(sock_get_timestampns); - -void sock_enable_timestamp(struct sock *sk) -{ - if (!sock_flag(sk, SOCK_TIMESTAMP)) { - sock_set_flag(sk, SOCK_TIMESTAMP); - net_enable_timestamp(); - } -} - -/* - * Get a socket option on an socket. - * - * FIX: POSIX 1003.1g is very ambiguous here. It states that - * asynchronous errors should be reported by getsockopt. We assume - * this means if you specify SO_ERROR (otherwise whats the point of it). - */ -int sock_common_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - - return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); -} - -EXPORT_SYMBOL(sock_common_getsockopt); - -#ifdef CONFIG_COMPAT -int compat_sock_common_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - - if (sk->sk_prot->compat_getsockopt != NULL) - return sk->sk_prot->compat_getsockopt(sk, level, optname, - optval, optlen); - return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_sock_common_getsockopt); -#endif - -int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size, int flags) -{ - struct sock *sk = sock->sk; - int addr_len = 0; - int err; - - err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT, - flags & ~MSG_DONTWAIT, &addr_len); - if (err >= 0) - msg->msg_namelen = addr_len; - return err; -} - -EXPORT_SYMBOL(sock_common_recvmsg); - -/* - * Set socket options on an inet socket. - */ -int sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) -{ - struct sock *sk = sock->sk; - - return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); -} - -EXPORT_SYMBOL(sock_common_setsockopt); - -#ifdef CONFIG_COMPAT -int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) -{ - struct sock *sk = sock->sk; - - if (sk->sk_prot->compat_setsockopt != NULL) - return sk->sk_prot->compat_setsockopt(sk, level, optname, - optval, optlen); - return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_sock_common_setsockopt); -#endif - -void sk_common_release(struct sock *sk) -{ - if (sk->sk_prot->destroy) - sk->sk_prot->destroy(sk); - - /* - * Observation: when sock_common_release is called, processes have - * no access to socket. But net still has. - * Step one, detach it from networking: - * - * A. Remove from hash tables. - */ - - sk->sk_prot->unhash(sk); - - /* - * In this point socket cannot receive new packets, but it is possible - * that some packets are in flight because some CPU runs receiver and - * did hash table lookup before we unhashed socket. They will achieve - * receive queue and will be purged by socket destructor. - * - * Also we still have packets pending on receive queue and probably, - * our own packets waiting in device queues. sock_destroy will drain - * receive queue, but transmitted packets will delay socket destruction - * until the last reference will be released. - */ - - sock_orphan(sk); - - xfrm_sk_free_policy(sk); - - sk_refcnt_debug_release(sk); - sock_put(sk); -} - -EXPORT_SYMBOL(sk_common_release); - -static DEFINE_RWLOCK(proto_list_lock); -static LIST_HEAD(proto_list); - -#ifdef CONFIG_PROC_FS -#define PROTO_INUSE_NR 64 /* should be enough for the first time */ -struct prot_inuse { - int val[PROTO_INUSE_NR]; -}; - -static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR); - -#ifdef CONFIG_NET_NS -void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) -{ - int cpu = smp_processor_id(); - per_cpu_ptr(net->core.inuse, cpu)->val[prot->inuse_idx] += val; -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_add); - -int sock_prot_inuse_get(struct net *net, struct proto *prot) -{ - int cpu, idx = prot->inuse_idx; - int res = 0; - - for_each_possible_cpu(cpu) - res += per_cpu_ptr(net->core.inuse, cpu)->val[idx]; - - return res >= 0 ? res : 0; -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_get); - -static int sock_inuse_init_net(struct net *net) -{ - net->core.inuse = alloc_percpu(struct prot_inuse); - return net->core.inuse ? 0 : -ENOMEM; -} - -static void sock_inuse_exit_net(struct net *net) -{ - free_percpu(net->core.inuse); -} - -static struct pernet_operations net_inuse_ops = { - .init = sock_inuse_init_net, - .exit = sock_inuse_exit_net, -}; - -static __init int net_inuse_init(void) -{ - if (register_pernet_subsys(&net_inuse_ops)) - panic("Cannot initialize net inuse counters"); - - return 0; -} - -core_initcall(net_inuse_init); -#else -static DEFINE_PER_CPU(struct prot_inuse, prot_inuse); - -void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) -{ - __get_cpu_var(prot_inuse).val[prot->inuse_idx] += val; -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_add); - -int sock_prot_inuse_get(struct net *net, struct proto *prot) -{ - int cpu, idx = prot->inuse_idx; - int res = 0; - - for_each_possible_cpu(cpu) - res += per_cpu(prot_inuse, cpu).val[idx]; - - return res >= 0 ? res : 0; -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_get); -#endif - -static void assign_proto_idx(struct proto *prot) -{ - prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR); - - if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) { - printk(KERN_ERR "PROTO_INUSE_NR exhausted\n"); - return; - } - - set_bit(prot->inuse_idx, proto_inuse_idx); -} - -static void release_proto_idx(struct proto *prot) -{ - if (prot->inuse_idx != PROTO_INUSE_NR - 1) - clear_bit(prot->inuse_idx, proto_inuse_idx); -} -#else -static inline void assign_proto_idx(struct proto *prot) -{ -} - -static inline void release_proto_idx(struct proto *prot) -{ -} -#endif - -int proto_register(struct proto *prot, int alloc_slab) -{ - if (alloc_slab) { - prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, - SLAB_HWCACHE_ALIGN | prot->slab_flags, - NULL); - - if (prot->slab == NULL) { - printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", - prot->name); - goto out; - } - - if (prot->rsk_prot != NULL) { - static const char mask[] = "request_sock_%s"; - - prot->rsk_prot->slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL); - if (prot->rsk_prot->slab_name == NULL) - goto out_free_sock_slab; - - sprintf(prot->rsk_prot->slab_name, mask, prot->name); - prot->rsk_prot->slab = kmem_cache_create(prot->rsk_prot->slab_name, - prot->rsk_prot->obj_size, 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (prot->rsk_prot->slab == NULL) { - printk(KERN_CRIT "%s: Can't create request sock SLAB cache!\n", - prot->name); - goto out_free_request_sock_slab_name; - } - } - - if (prot->twsk_prot != NULL) { - static const char mask[] = "tw_sock_%s"; - - prot->twsk_prot->twsk_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL); - - if (prot->twsk_prot->twsk_slab_name == NULL) - goto out_free_request_sock_slab; - - sprintf(prot->twsk_prot->twsk_slab_name, mask, prot->name); - prot->twsk_prot->twsk_slab = - kmem_cache_create(prot->twsk_prot->twsk_slab_name, - prot->twsk_prot->twsk_obj_size, - 0, - SLAB_HWCACHE_ALIGN | - prot->slab_flags, - NULL); - if (prot->twsk_prot->twsk_slab == NULL) - goto out_free_timewait_sock_slab_name; - } - } - - write_lock(&proto_list_lock); - list_add(&prot->node, &proto_list); - assign_proto_idx(prot); - write_unlock(&proto_list_lock); - return 0; - -out_free_timewait_sock_slab_name: - kfree(prot->twsk_prot->twsk_slab_name); -out_free_request_sock_slab: - if (prot->rsk_prot && prot->rsk_prot->slab) { - kmem_cache_destroy(prot->rsk_prot->slab); - prot->rsk_prot->slab = NULL; - } -out_free_request_sock_slab_name: - kfree(prot->rsk_prot->slab_name); -out_free_sock_slab: - kmem_cache_destroy(prot->slab); - prot->slab = NULL; -out: - return -ENOBUFS; -} - -EXPORT_SYMBOL(proto_register); - -void proto_unregister(struct proto *prot) -{ - write_lock(&proto_list_lock); - release_proto_idx(prot); - list_del(&prot->node); - write_unlock(&proto_list_lock); - - if (prot->slab != NULL) { - kmem_cache_destroy(prot->slab); - prot->slab = NULL; - } - - if (prot->rsk_prot != NULL && prot->rsk_prot->slab != NULL) { - kmem_cache_destroy(prot->rsk_prot->slab); - kfree(prot->rsk_prot->slab_name); - prot->rsk_prot->slab = NULL; - } - - if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) { - kmem_cache_destroy(prot->twsk_prot->twsk_slab); - kfree(prot->twsk_prot->twsk_slab_name); - prot->twsk_prot->twsk_slab = NULL; - } -} - -EXPORT_SYMBOL(proto_unregister); - -#ifdef CONFIG_PROC_FS -static void *proto_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(proto_list_lock) -{ - read_lock(&proto_list_lock); - return seq_list_start_head(&proto_list, *pos); -} - -static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_list_next(v, &proto_list, pos); -} - -static void proto_seq_stop(struct seq_file *seq, void *v) - __releases(proto_list_lock) -{ - read_unlock(&proto_list_lock); -} - -static char proto_method_implemented(const void *method) -{ - return method == NULL ? 'n' : 'y'; -} - -static void proto_seq_printf(struct seq_file *seq, struct proto *proto) -{ - seq_printf(seq, "%-9s %4u %6d %6d %-3s %6u %-3s %-10s " - "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n", - proto->name, - proto->obj_size, - sock_prot_inuse_get(seq_file_net(seq), proto), - proto->memory_allocated != NULL ? atomic_read(proto->memory_allocated) : -1, - proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI", - proto->max_header, - proto->slab == NULL ? "no" : "yes", - module_name(proto->owner), - proto_method_implemented(proto->close), - proto_method_implemented(proto->connect), - proto_method_implemented(proto->disconnect), - proto_method_implemented(proto->accept), - proto_method_implemented(proto->ioctl), - proto_method_implemented(proto->init), - proto_method_implemented(proto->destroy), - proto_method_implemented(proto->shutdown), - proto_method_implemented(proto->setsockopt), - proto_method_implemented(proto->getsockopt), - proto_method_implemented(proto->sendmsg), - proto_method_implemented(proto->recvmsg), - proto_method_implemented(proto->sendpage), - proto_method_implemented(proto->bind), - proto_method_implemented(proto->backlog_rcv), - proto_method_implemented(proto->hash), - proto_method_implemented(proto->unhash), - proto_method_implemented(proto->get_port), - proto_method_implemented(proto->enter_memory_pressure)); -} - -static int proto_seq_show(struct seq_file *seq, void *v) -{ - if (v == &proto_list) - seq_printf(seq, "%-9s %-4s %-8s %-6s %-5s %-7s %-4s %-10s %s", - "protocol", - "size", - "sockets", - "memory", - "press", - "maxhdr", - "slab", - "module", - "cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n"); - else - proto_seq_printf(seq, list_entry(v, struct proto, node)); - return 0; -} - -static const struct seq_operations proto_seq_ops = { - .start = proto_seq_start, - .next = proto_seq_next, - .stop = proto_seq_stop, - .show = proto_seq_show, -}; - -static int proto_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &proto_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations proto_seq_fops = { - .owner = THIS_MODULE, - .open = proto_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static __net_init int proto_init_net(struct net *net) -{ - if (!proc_net_fops_create(net, "protocols", S_IRUGO, &proto_seq_fops)) - return -ENOMEM; - - return 0; -} - -static __net_exit void proto_exit_net(struct net *net) -{ - proc_net_remove(net, "protocols"); -} - - -static __net_initdata struct pernet_operations proto_net_ops = { - .init = proto_init_net, - .exit = proto_exit_net, -}; - -static int __init proto_init(void) -{ - return register_pernet_subsys(&proto_net_ops); -} - -subsys_initcall(proto_init); - -#endif /* PROC_FS */ - -EXPORT_SYMBOL(sk_alloc); -EXPORT_SYMBOL(sk_free); -EXPORT_SYMBOL(sk_send_sigurg); -EXPORT_SYMBOL(sock_alloc_send_skb); -EXPORT_SYMBOL(sock_init_data); -EXPORT_SYMBOL(sock_kfree_s); -EXPORT_SYMBOL(sock_kmalloc); -EXPORT_SYMBOL(sock_no_accept); -EXPORT_SYMBOL(sock_no_bind); -EXPORT_SYMBOL(sock_no_connect); -EXPORT_SYMBOL(sock_no_getname); -EXPORT_SYMBOL(sock_no_getsockopt); -EXPORT_SYMBOL(sock_no_ioctl); -EXPORT_SYMBOL(sock_no_listen); -EXPORT_SYMBOL(sock_no_mmap); -EXPORT_SYMBOL(sock_no_poll); -EXPORT_SYMBOL(sock_no_recvmsg); -EXPORT_SYMBOL(sock_no_sendmsg); -EXPORT_SYMBOL(sock_no_sendpage); -EXPORT_SYMBOL(sock_no_setsockopt); -EXPORT_SYMBOL(sock_no_shutdown); -EXPORT_SYMBOL(sock_no_socketpair); -EXPORT_SYMBOL(sock_rfree); -EXPORT_SYMBOL(sock_setsockopt); -EXPORT_SYMBOL(sock_wfree); -EXPORT_SYMBOL(sock_wmalloc); -EXPORT_SYMBOL(sock_i_uid); -EXPORT_SYMBOL(sock_i_ino); -EXPORT_SYMBOL(sysctl_optmem_max); diff --git a/libdde_linux26/contrib/net/ethernet/.svn/all-wcprops b/libdde_linux26/contrib/net/ethernet/.svn/all-wcprops deleted file mode 100644 index 927d242c..00000000 --- a/libdde_linux26/contrib/net/ethernet/.svn/all-wcprops +++ /dev/null @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 71 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/ethernet -END -eth.c -K 25 -svn:wc:ra_dav:version-url -V 77 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/ethernet/eth.c -END diff --git a/libdde_linux26/contrib/net/ethernet/.svn/entries b/libdde_linux26/contrib/net/ethernet/.svn/entries deleted file mode 100644 index 1a83a365..00000000 --- a/libdde_linux26/contrib/net/ethernet/.svn/entries +++ /dev/null @@ -1,62 +0,0 @@ -9 - -dir -465 -http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/contrib/net/ethernet -http://svn.tudos.org/repos/tudos - - - -2009-05-20T14:32:55.606606Z -455 -l4check - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -a704ac0b-3a55-4d43-a2a9-7be6f07c34fb - -eth.c -file - - - - -2009-11-15T17:16:35.000000Z -9e32e52c590d3469dc0e13f209149807 -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -11140 - diff --git a/libdde_linux26/contrib/net/ethernet/.svn/format b/libdde_linux26/contrib/net/ethernet/.svn/format deleted file mode 100644 index ec635144..00000000 --- a/libdde_linux26/contrib/net/ethernet/.svn/format +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/libdde_linux26/contrib/net/ethernet/.svn/text-base/eth.c.svn-base b/libdde_linux26/contrib/net/ethernet/.svn/text-base/eth.c.svn-base deleted file mode 100644 index 280352ab..00000000 --- a/libdde_linux26/contrib/net/ethernet/.svn/text-base/eth.c.svn-base +++ /dev/null @@ -1,407 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Ethernet-type device handling. - * - * Version: @(#)eth.c 1.0.7 05/25/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> - * Mark Evans, <evansmp@uhura.aston.ac.uk> - * Florian La Roche, <rzsfl@rz.uni-sb.de> - * Alan Cox, <gw4pts@gw4pts.ampr.org> - * - * Fixes: - * Mr Linux : Arp problems - * Alan Cox : Generic queue tidyup (very tiny here) - * Alan Cox : eth_header ntohs should be htons - * Alan Cox : eth_rebuild_header missing an htons and - * minor other things. - * Tegge : Arp bug fixes. - * Florian : Removed many unnecessary functions, code cleanup - * and changes for new arp and skbuff. - * Alan Cox : Redid header building to reflect new format. - * Alan Cox : ARP only when compiled with CONFIG_INET - * Greg Page : 802.2 and SNAP stuff. - * Alan Cox : MAC layer pointers/new format. - * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding. - * Alan Cox : Protect against forwarding explosions with - * older network drivers and IFF_ALLMULTI. - * Christer Weinigel : Better rebuild header message. - * Andrew Morton : 26Feb01: kill ether_setup() - use netdev_boot_setup(). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/socket.h> -#include <linux/in.h> -#include <linux/inet.h> -#include <linux/ip.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/if_ether.h> -#include <net/dst.h> -#include <net/arp.h> -#include <net/sock.h> -#include <net/ipv6.h> -#include <net/ip.h> -#include <net/dsa.h> -#include <asm/uaccess.h> -#include <asm/system.h> - -__setup("ether=", netdev_boot_setup); - -/** - * eth_header - create the Ethernet header - * @skb: buffer to alter - * @dev: source device - * @type: Ethernet type field - * @daddr: destination address (NULL leave destination address) - * @saddr: source address (NULL use device source address) - * @len: packet length (<= skb->len) - * - * - * Set the protocol type. For a packet of type ETH_P_802_3 we put the length - * in here instead. It is up to the 802.2 layer to carry protocol information. - */ -int eth_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned len) -{ - struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); - - if (type != ETH_P_802_3) - eth->h_proto = htons(type); - else - eth->h_proto = htons(len); - - /* - * Set the source hardware address. - */ - - if (!saddr) - saddr = dev->dev_addr; - memcpy(eth->h_source, saddr, ETH_ALEN); - - if (daddr) { - memcpy(eth->h_dest, daddr, ETH_ALEN); - return ETH_HLEN; - } - - /* - * Anyway, the loopback-device should never use this function... - */ - - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - memset(eth->h_dest, 0, ETH_ALEN); - return ETH_HLEN; - } - - return -ETH_HLEN; -} -EXPORT_SYMBOL(eth_header); - -/** - * eth_rebuild_header- rebuild the Ethernet MAC header. - * @skb: socket buffer to update - * - * This is called after an ARP or IPV6 ndisc it's resolution on this - * sk_buff. We now let protocol (ARP) fill in the other fields. - * - * This routine CANNOT use cached dst->neigh! - * Really, it is used only when dst->neigh is wrong. - */ -int eth_rebuild_header(struct sk_buff *skb) -{ - struct ethhdr *eth = (struct ethhdr *)skb->data; - struct net_device *dev = skb->dev; - - switch (eth->h_proto) { -#ifdef CONFIG_INET - case htons(ETH_P_IP): - return arp_find(eth->h_dest, skb); -#endif - default: - printk(KERN_DEBUG - "%s: unable to resolve type %X addresses.\n", - dev->name, (int)eth->h_proto); - - memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); - break; - } - - return 0; -} -EXPORT_SYMBOL(eth_rebuild_header); - -/** - * eth_type_trans - determine the packet's protocol ID. - * @skb: received socket data - * @dev: receiving network device - * - * The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - */ -__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct ethhdr *eth; - unsigned char *rawp; - - skb->dev = dev; - skb_reset_mac_header(skb); - skb_pull(skb, ETH_HLEN); - eth = eth_hdr(skb); - - if (unlikely(is_multicast_ether_addr(eth->h_dest))) { - if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) - skb->pkt_type = PACKET_BROADCAST; - else - skb->pkt_type = PACKET_MULTICAST; - } - - /* - * This ALLMULTI check should be redundant by 1.4 - * so don't forget to remove it. - * - * Seems, you forgot to remove it. All silly devices - * seems to set IFF_PROMISC. - */ - - else if (1 /*dev->flags&IFF_PROMISC */ ) { - if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr))) - skb->pkt_type = PACKET_OTHERHOST; - } - - /* - * Some variants of DSA tagging don't have an ethertype field - * at all, so we check here whether one of those tagging - * variants has been configured on the receiving interface, - * and if so, set skb->protocol without looking at the packet. - */ - if (netdev_uses_dsa_tags(dev)) - return htons(ETH_P_DSA); - if (netdev_uses_trailer_tags(dev)) - return htons(ETH_P_TRAILER); - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - - rawp = skb->data; - - /* - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); - - /* - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); -} -EXPORT_SYMBOL(eth_type_trans); - -/** - * eth_header_parse - extract hardware address from packet - * @skb: packet to extract header from - * @haddr: destination buffer - */ -int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) -{ - const struct ethhdr *eth = eth_hdr(skb); - memcpy(haddr, eth->h_source, ETH_ALEN); - return ETH_ALEN; -} -EXPORT_SYMBOL(eth_header_parse); - -/** - * eth_header_cache - fill cache entry from neighbour - * @neigh: source neighbour - * @hh: destination cache entry - * Create an Ethernet header template from the neighbour. - */ -int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh) -{ - __be16 type = hh->hh_type; - struct ethhdr *eth; - const struct net_device *dev = neigh->dev; - - eth = (struct ethhdr *) - (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); - - if (type == htons(ETH_P_802_3)) - return -1; - - eth->h_proto = type; - memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); - memcpy(eth->h_dest, neigh->ha, ETH_ALEN); - hh->hh_len = ETH_HLEN; - return 0; -} -EXPORT_SYMBOL(eth_header_cache); - -/** - * eth_header_cache_update - update cache entry - * @hh: destination cache entry - * @dev: network device - * @haddr: new hardware address - * - * Called by Address Resolution module to notify changes in address. - */ -void eth_header_cache_update(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char *haddr) -{ - memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), - haddr, ETH_ALEN); -} -EXPORT_SYMBOL(eth_header_cache_update); - -/** - * eth_mac_addr - set new Ethernet hardware address - * @dev: network device - * @p: socket address - * Change hardware address of device. - * - * This doesn't change hardware matching, so needs to be overridden - * for most real devices. - */ -int eth_mac_addr(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - if (netif_running(dev)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); - return 0; -} -EXPORT_SYMBOL(eth_mac_addr); - -/** - * eth_change_mtu - set new MTU size - * @dev: network device - * @new_mtu: new Maximum Transfer Unit - * - * Allow changing MTU size. Needs to be overridden for devices - * supporting jumbo frames. - */ -int eth_change_mtu(struct net_device *dev, int new_mtu) -{ - if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} -EXPORT_SYMBOL(eth_change_mtu); - -int eth_validate_addr(struct net_device *dev) -{ - if (!is_valid_ether_addr(dev->dev_addr)) - return -EADDRNOTAVAIL; - - return 0; -} -EXPORT_SYMBOL(eth_validate_addr); - -const struct header_ops eth_header_ops ____cacheline_aligned = { - .create = eth_header, - .parse = eth_header_parse, - .rebuild = eth_rebuild_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, -}; - -/** - * ether_setup - setup Ethernet network device - * @dev: network device - * Fill in the fields of the device structure with Ethernet-generic values. - */ -void ether_setup(struct net_device *dev) -{ - dev->header_ops = ð_header_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = eth_change_mtu; - dev->set_mac_address = eth_mac_addr; - dev->validate_addr = eth_validate_addr; -#endif - dev->type = ARPHRD_ETHER; - dev->hard_header_len = ETH_HLEN; - dev->mtu = ETH_DATA_LEN; - dev->addr_len = ETH_ALEN; - dev->tx_queue_len = 1000; /* Ethernet wants good queues */ - dev->flags = IFF_BROADCAST|IFF_MULTICAST; - - memset(dev->broadcast, 0xFF, ETH_ALEN); - -} -EXPORT_SYMBOL(ether_setup); - -/** - * alloc_etherdev_mq - Allocates and sets up an Ethernet device - * @sizeof_priv: Size of additional driver-private structure to be allocated - * for this Ethernet device - * @queue_count: The number of queues this device has. - * - * Fill in the fields of the device structure with Ethernet-generic - * values. Basically does everything except registering the device. - * - * Constructs a new net device, complete with a private data area of - * size (sizeof_priv). A 32-byte (not bit) alignment is enforced for - * this private data area. - */ - -struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count) -{ - return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count); -} -EXPORT_SYMBOL(alloc_etherdev_mq); - -static size_t _format_mac_addr(char *buf, int buflen, - const unsigned char *addr, int len) -{ - int i; - char *cp = buf; - - for (i = 0; i < len; i++) { - cp += scnprintf(cp, buflen - (cp - buf), "%02x", addr[i]); - if (i == len - 1) - break; - cp += strlcpy(cp, ":", buflen - (cp - buf)); - } - return cp - buf; -} - -ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) -{ - size_t l; - - l = _format_mac_addr(buf, PAGE_SIZE, addr, len); - l += strlcpy(buf + l, "\n", PAGE_SIZE - l); - return ((ssize_t) l); -} -EXPORT_SYMBOL(sysfs_format_mac); - -char *print_mac(char *buf, const unsigned char *addr) -{ - _format_mac_addr(buf, MAC_BUF_SIZE, addr, ETH_ALEN); - return buf; -} -EXPORT_SYMBOL(print_mac); diff --git a/libdde_linux26/contrib/net/netlink/.svn/all-wcprops b/libdde_linux26/contrib/net/netlink/.svn/all-wcprops deleted file mode 100644 index ce1fb1f4..00000000 --- a/libdde_linux26/contrib/net/netlink/.svn/all-wcprops +++ /dev/null @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 70 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/netlink -END -attr.c -K 25 -svn:wc:ra_dav:version-url -V 77 -/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/contrib/net/netlink/attr.c -END diff --git a/libdde_linux26/contrib/net/netlink/.svn/entries b/libdde_linux26/contrib/net/netlink/.svn/entries deleted file mode 100644 index 266f7da2..00000000 --- a/libdde_linux26/contrib/net/netlink/.svn/entries +++ /dev/null @@ -1,62 +0,0 @@ -9 - -dir -465 -http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/contrib/net/netlink -http://svn.tudos.org/repos/tudos - - - -2009-05-20T14:32:55.606606Z -455 -l4check - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -a704ac0b-3a55-4d43-a2a9-7be6f07c34fb - -attr.c -file - - - - -2009-11-15T17:16:31.000000Z -947f16bcde5e9f39a59a4ea48b74cc1b -2009-05-20T14:32:55.606606Z -455 -l4check - - - - - - - - - - - - - - - - - - - - - -11827 - diff --git a/libdde_linux26/contrib/net/netlink/.svn/format b/libdde_linux26/contrib/net/netlink/.svn/format deleted file mode 100644 index ec635144..00000000 --- a/libdde_linux26/contrib/net/netlink/.svn/format +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/libdde_linux26/contrib/net/netlink/.svn/text-base/attr.c.svn-base b/libdde_linux26/contrib/net/netlink/.svn/text-base/attr.c.svn-base deleted file mode 100644 index 56c3ce7f..00000000 --- a/libdde_linux26/contrib/net/netlink/.svn/text-base/attr.c.svn-base +++ /dev/null @@ -1,473 +0,0 @@ -/* - * NETLINK Netlink attributes - * - * Authors: Thomas Graf <tgraf@suug.ch> - * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/jiffies.h> -#include <linux/netdevice.h> -#include <linux/skbuff.h> -#include <linux/string.h> -#include <linux/types.h> -#include <net/netlink.h> - -static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { - [NLA_U8] = sizeof(u8), - [NLA_U16] = sizeof(u16), - [NLA_U32] = sizeof(u32), - [NLA_U64] = sizeof(u64), - [NLA_NESTED] = NLA_HDRLEN, -}; - -static int validate_nla(struct nlattr *nla, int maxtype, - const struct nla_policy *policy) -{ - const struct nla_policy *pt; - int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); - - if (type <= 0 || type > maxtype) - return 0; - - pt = &policy[type]; - - BUG_ON(pt->type > NLA_TYPE_MAX); - - switch (pt->type) { - case NLA_FLAG: - if (attrlen > 0) - return -ERANGE; - break; - - case NLA_NUL_STRING: - if (pt->len) - minlen = min_t(int, attrlen, pt->len + 1); - else - minlen = attrlen; - - if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) - return -EINVAL; - /* fall through */ - - case NLA_STRING: - if (attrlen < 1) - return -ERANGE; - - if (pt->len) { - char *buf = nla_data(nla); - - if (buf[attrlen - 1] == '\0') - attrlen--; - - if (attrlen > pt->len) - return -ERANGE; - } - break; - - case NLA_BINARY: - if (pt->len && attrlen > pt->len) - return -ERANGE; - break; - - case NLA_NESTED_COMPAT: - if (attrlen < pt->len) - return -ERANGE; - if (attrlen < NLA_ALIGN(pt->len)) - break; - if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN) - return -ERANGE; - nla = nla_data(nla) + NLA_ALIGN(pt->len); - if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla)) - return -ERANGE; - break; - case NLA_NESTED: - /* a nested attributes is allowed to be empty; if its not, - * it must have a size of at least NLA_HDRLEN. - */ - if (attrlen == 0) - break; - default: - if (pt->len) - minlen = pt->len; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; - - if (attrlen < minlen) - return -ERANGE; - } - - return 0; -} - -/** - * nla_validate - Validate a stream of attributes - * @head: head of attribute stream - * @len: length of attribute stream - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - * - * Validates all attributes in the specified attribute stream against the - * specified policy. Attributes with a type exceeding maxtype will be - * ignored. See documenation of struct nla_policy for more details. - * - * Returns 0 on success or a negative error code. - */ -int nla_validate(struct nlattr *head, int len, int maxtype, - const struct nla_policy *policy) -{ - struct nlattr *nla; - int rem, err; - - nla_for_each_attr(nla, head, len, rem) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - err = 0; -errout: - return err; -} - -/** - * nla_parse - Parse a stream of attributes into a tb buffer - * @tb: destination array with maxtype+1 elements - * @maxtype: maximum attribute type to be expected - * @head: head of attribute stream - * @len: length of attribute stream - * @policy: validation policy - * - * Parses a stream of attributes and stores a pointer to each attribute in - * the tb array accessable via the attribute type. Attributes with a type - * exceeding maxtype will be silently ignored for backwards compatibility - * reasons. policy may be set to NULL if no validation is required. - * - * Returns 0 on success or a negative error code. - */ -int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - const struct nla_policy *policy) -{ - struct nlattr *nla; - int rem, err; - - memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - u16 type = nla_type(nla); - - if (type > 0 && type <= maxtype) { - if (policy) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - tb[type] = nla; - } - } - - if (unlikely(rem > 0)) - printk(KERN_WARNING "netlink: %d bytes leftover after parsing " - "attributes.\n", rem); - - err = 0; -errout: - return err; -} - -/** - * nla_find - Find a specific attribute in a stream of attributes - * @head: head of attribute stream - * @len: length of attribute stream - * @attrtype: type of attribute to look for - * - * Returns the first attribute in the stream matching the specified type. - */ -struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) -{ - struct nlattr *nla; - int rem; - - nla_for_each_attr(nla, head, len, rem) - if (nla_type(nla) == attrtype) - return nla; - - return NULL; -} - -/** - * nla_strlcpy - Copy string attribute payload into a sized buffer - * @dst: where to copy the string to - * @nla: attribute to copy the string from - * @dstsize: size of destination buffer - * - * Copies at most dstsize - 1 bytes into the destination buffer. - * The result is always a valid NUL-terminated string. Unlike - * strlcpy the destination buffer is always padded out. - * - * Returns the length of the source buffer. - */ -size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len(nla); - char *src = nla_data(nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; - - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; - - memset(dst, 0, dstsize); - memcpy(dst, src, len); - } - - return srclen; -} - -/** - * nla_memcpy - Copy a netlink attribute into another memory area - * @dest: where to copy to memcpy - * @src: netlink attribute to copy from - * @count: size of the destination area - * - * Note: The number of bytes copied is limited by the length of - * attribute's payload. memcpy - * - * Returns the number of bytes copied. - */ -int nla_memcpy(void *dest, const struct nlattr *src, int count) -{ - int minlen = min_t(int, count, nla_len(src)); - - memcpy(dest, nla_data(src), minlen); - - return minlen; -} - -/** - * nla_memcmp - Compare an attribute with sized memory area - * @nla: netlink attribute - * @data: memory area - * @size: size of memory area - */ -int nla_memcmp(const struct nlattr *nla, const void *data, - size_t size) -{ - int d = nla_len(nla) - size; - - if (d == 0) - d = memcmp(nla_data(nla), data, size); - - return d; -} - -/** - * nla_strcmp - Compare a string attribute against a string - * @nla: netlink string attribute - * @str: another string - */ -int nla_strcmp(const struct nlattr *nla, const char *str) -{ - int len = strlen(str) + 1; - int d = nla_len(nla) - len; - - if (d == 0) - d = memcmp(nla_data(nla), str, len); - - return d; -} - -/** - * __nla_reserve - reserve room for attribute on the skb - * @skb: socket buffer to reserve room on - * @attrtype: attribute type - * @attrlen: length of attribute payload - * - * Adds a netlink attribute header to a socket buffer and reserves - * room for the payload but does not copy it. - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute header and payload. - */ -struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) -{ - struct nlattr *nla; - - nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen)); - nla->nla_type = attrtype; - nla->nla_len = nla_attr_size(attrlen); - - memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); - - return nla; -} - -/** - * __nla_reserve_nohdr - reserve room for attribute without header - * @skb: socket buffer to reserve room on - * @attrlen: length of attribute payload - * - * Reserves room for attribute payload without a header. - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the payload. - */ -void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen) -{ - void *start; - - start = skb_put(skb, NLA_ALIGN(attrlen)); - memset(start, 0, NLA_ALIGN(attrlen)); - - return start; -} - -/** - * nla_reserve - reserve room for attribute on the skb - * @skb: socket buffer to reserve room on - * @attrtype: attribute type - * @attrlen: length of attribute payload - * - * Adds a netlink attribute header to a socket buffer and reserves - * room for the payload but does not copy it. - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) -{ - if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) - return NULL; - - return __nla_reserve(skb, attrtype, attrlen); -} - -/** - * nla_reserve_nohdr - reserve room for attribute without header - * @skb: socket buffer to reserve room on - * @attrlen: length of attribute payload - * - * Reserves room for attribute payload without a header. - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the attribute payload. - */ -void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen) -{ - if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) - return NULL; - - return __nla_reserve_nohdr(skb, attrlen); -} - -/** - * __nla_put - Add a netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute header and payload. - */ -void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, - const void *data) -{ - struct nlattr *nla; - - nla = __nla_reserve(skb, attrtype, attrlen); - memcpy(nla_data(nla), data, attrlen); -} - -/** - * __nla_put_nohdr - Add a netlink attribute without header - * @skb: socket buffer to add attribute to - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute payload. - */ -void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) -{ - void *start; - - start = __nla_reserve_nohdr(skb, attrlen); - memcpy(start, data, attrlen); -} - -/** - * nla_put - Add a netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) -{ - if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) - return -EMSGSIZE; - - __nla_put(skb, attrtype, attrlen, data); - return 0; -} - -/** - * nla_put_nohdr - Add a netlink attribute without header - * @skb: socket buffer to add attribute to - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute payload. - */ -int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) -{ - if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) - return -EMSGSIZE; - - __nla_put_nohdr(skb, attrlen, data); - return 0; -} - -/** - * nla_append - Add a netlink attribute without header or padding - * @skb: socket buffer to add attribute to - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute payload. - */ -int nla_append(struct sk_buff *skb, int attrlen, const void *data) -{ - if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) - return -EMSGSIZE; - - memcpy(skb_put(skb, attrlen), data, attrlen); - return 0; -} - -EXPORT_SYMBOL(nla_validate); -EXPORT_SYMBOL(nla_parse); -EXPORT_SYMBOL(nla_find); -EXPORT_SYMBOL(nla_strlcpy); -EXPORT_SYMBOL(__nla_reserve); -EXPORT_SYMBOL(__nla_reserve_nohdr); -EXPORT_SYMBOL(nla_reserve); -EXPORT_SYMBOL(nla_reserve_nohdr); -EXPORT_SYMBOL(__nla_put); -EXPORT_SYMBOL(__nla_put_nohdr); -EXPORT_SYMBOL(nla_put); -EXPORT_SYMBOL(nla_put_nohdr); -EXPORT_SYMBOL(nla_memcpy); -EXPORT_SYMBOL(nla_memcmp); -EXPORT_SYMBOL(nla_strcmp); -EXPORT_SYMBOL(nla_append); diff --git a/libdde_linux26/contrib/net/sched/.svn/all-wcprops b/libdde_linux26/contrib/net/sched/.svn/all-wcprops deleted file mode 100644 index 1afccd56..00000000 --- a/libdde_linux26/contrib/net/sched/.svn/all-wcprops +++ /dev/null @@ -1,5 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 68 -/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/linux26/contrib/net/sched -END diff --git a/libdde_linux26/contrib/net/sched/.svn/entries b/libdde_linux26/contrib/net/sched/.svn/entries deleted file mode 100644 index 71f93f72..00000000 --- a/libdde_linux26/contrib/net/sched/.svn/entries +++ /dev/null @@ -1,28 +0,0 @@ -9 - -dir -465 -http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/contrib/net/sched -http://svn.tudos.org/repos/tudos - - - -2007-09-08T19:44:13.897747Z -174 -l4check - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -a704ac0b-3a55-4d43-a2a9-7be6f07c34fb - diff --git a/libdde_linux26/contrib/net/sched/.svn/format b/libdde_linux26/contrib/net/sched/.svn/format deleted file mode 100644 index ec635144..00000000 --- a/libdde_linux26/contrib/net/sched/.svn/format +++ /dev/null @@ -1 +0,0 @@ -9 |