X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fpacket%2Faf_packet.c;h=4172a5235916e3f71ee6fbed85b4c296ab9de3c4;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=a996d9c43f9e4859653bdf955480b054e261e1a3;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a996d9c43..4172a5235 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -7,7 +7,7 @@ * * Version: $Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $ * - * Authors: Ross Biro, + * Authors: Ross Biro * Fred N. van Kempen, * Alan Cox, * @@ -36,6 +36,11 @@ * Michal Ostrowski : Module initialization cleanup. * Ulises Alonso : Frame number limit removal and * packet_set_ring memory leak. + * Eric Biederman : Allow for > 8 byte hardware addresses. + * The convention is that longer addresses + * will simply extend the hardware address + * byte arrays at the end of sockaddr_ll + * and packet_mreq. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -44,10 +49,10 @@ * */ -#include #include #include #include +#include #include #include #include @@ -161,7 +166,17 @@ struct packet_mclist int count; unsigned short type; unsigned short alen; - unsigned char addr[8]; + unsigned char addr[MAX_ADDR_LEN]; +}; +/* identical to struct packet_mreq except it has + * a longer address field. + */ +struct packet_mreq_max +{ + int mr_ifindex; + unsigned short mr_type; + unsigned short mr_alen; + unsigned char mr_address[MAX_ADDR_LEN]; }; #endif #ifdef CONFIG_PACKET_MMAP @@ -170,8 +185,9 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing static void packet_flush_mclist(struct sock *sk); -struct packet_opt -{ +struct packet_sock { + /* struct sock has to be the first member of packet_sock */ + struct sock sk; struct tpacket_stats stats; #ifdef CONFIG_PACKET_MMAP char * *pg_vec; @@ -199,7 +215,7 @@ struct packet_opt #ifdef CONFIG_PACKET_MMAP -static inline char *packet_lookup_frame(struct packet_opt *po, unsigned int position) +static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) { unsigned int pg_vec_pos, frame_offset; char *frame; @@ -213,7 +229,10 @@ static inline char *packet_lookup_frame(struct packet_opt *po, unsigned int posi } #endif -#define pkt_sk(__sk) ((struct packet_opt *)(__sk)->sk_protinfo) +static inline struct packet_sock *pkt_sk(struct sock *sk) +{ + return (struct packet_sock *)sk; +} static void packet_sock_destruct(struct sock *sk) { @@ -225,8 +244,6 @@ static void packet_sock_destruct(struct sock *sk) return; } - if (pkt_sk(sk)) - kfree(pkt_sk(sk)); atomic_dec(&packet_socks_nr); #ifdef PACKET_REFCNT_DEBUG printk(KERN_DEBUG "PACKET socket %p is free, %d are alive\n", sk, atomic_read(&packet_socks_nr)); @@ -234,12 +251,12 @@ static void packet_sock_destruct(struct sock *sk) } -static struct proto_ops packet_ops; +static const struct proto_ops packet_ops; #ifdef CONFIG_SOCK_PACKET -static struct proto_ops packet_ops_spkt; +static const struct proto_ops packet_ops_spkt; -static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct sock *sk; struct sockaddr_pkt *spkt; @@ -272,6 +289,9 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct dst_release(skb->dst); skb->dst = NULL; + /* drop conntrack reference */ + nf_reset(skb); + spkt = (struct sockaddr_pkt*)skb->cb; skb_push(skb, skb->data-skb->mac.raw); @@ -344,7 +364,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ err = -EMSGSIZE; - if(len>dev->mtu+dev->hard_header_len) + if (len > dev->mtu + dev->hard_header_len) goto out_unlock; err = -ENOBUFS; @@ -436,11 +456,11 @@ static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned we will not harm anyone. */ -static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct sock *sk; struct sockaddr_ll *sll; - struct packet_opt *po; + struct packet_sock *po; u8 * skb_head = skb->data; int skb_len = skb->len; unsigned snaplen; @@ -515,6 +535,9 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packe dst_release(skb->dst); skb->dst = NULL; + /* drop conntrack reference */ + nf_reset(skb); + spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_packets++; __skb_queue_tail(&sk->sk_receive_queue, skb); @@ -538,10 +561,10 @@ drop: } #ifdef CONFIG_PACKET_MMAP -static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct sock *sk; - struct packet_opt *po; + struct packet_sock *po; struct sockaddr_ll *sll; struct tpacket_hdr *h; u8 * skb_head = skb->data; @@ -603,8 +626,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct pack if ((int)snaplen < 0) snaplen = 0; } - if (snaplen > skb->len-skb->data_len) - snaplen = skb->len-skb->data_len; spin_lock(&sk->sk_receive_queue.lock); h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head); @@ -621,18 +642,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct pack status &= ~TP_STATUS_LOSING; spin_unlock(&sk->sk_receive_queue.lock); - memcpy((u8*)h + macoff, skb->data, snaplen); + skb_copy_bits(skb, 0, (u8*)h + macoff, snaplen); h->tp_len = skb->len; h->tp_snaplen = snaplen; h->tp_mac = macoff; h->tp_net = netoff; - if (skb->stamp.tv_sec == 0) { - do_gettimeofday(&skb->stamp); + if (skb->tstamp.off_sec == 0) { + __net_timestamp(skb); sock_enable_timestamp(sk); } - h->tp_sec = skb->stamp.tv_sec; - h->tp_usec = skb->stamp.tv_usec; + h->tp_sec = skb->tstamp.off_sec; + h->tp_usec = skb->tstamp.off_usec; sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); sll->sll_halen = 0; @@ -699,7 +720,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, */ if (saddr == NULL) { - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); ifindex = po->ifindex; proto = po->num; @@ -708,6 +729,8 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, err = -EINVAL; if (msg->msg_namelen < sizeof(struct sockaddr_ll)) goto out; + if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) + goto out; ifindex = saddr->sll_ifindex; proto = saddr->sll_protocol; addr = saddr->sll_addr; @@ -786,7 +809,7 @@ out: static int packet_release(struct socket *sock) { struct sock *sk = sock->sk; - struct packet_opt *po; + struct packet_sock *po; if (!sk) return 0; @@ -844,7 +867,7 @@ static int packet_release(struct socket *sock) static int packet_do_bind(struct sock *sk, struct net_device *dev, int protocol) { - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); /* * Detach an existing hook if present. */ @@ -909,7 +932,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add * Check legality */ - if(addr_len!=sizeof(struct sockaddr)) + if (addr_len != sizeof(struct sockaddr)) return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); @@ -953,6 +976,11 @@ out: return err; } +static struct proto packet_proto = { + .name = "PACKET", + .owner = THIS_MODULE, + .obj_size = sizeof(struct packet_sock), +}; /* * Create a packet of type SOCK_PACKET. @@ -961,7 +989,7 @@ out: static int packet_create(struct socket *sock, int protocol) { struct sock *sk; - struct packet_opt *po; + struct packet_sock *po; int err; if (!capable(CAP_NET_RAW)) @@ -976,7 +1004,7 @@ static int packet_create(struct socket *sock, int protocol) sock->state = SS_UNCONNECTED; err = -ENOBUFS; - sk = sk_alloc(PF_PACKET, GFP_KERNEL, 1, NULL); + sk = sk_alloc(PF_PACKET, GFP_KERNEL, &packet_proto, 1); if (sk == NULL) goto out; @@ -985,13 +1013,9 @@ static int packet_create(struct socket *sock, int protocol) if (sock->type == SOCK_PACKET) sock->ops = &packet_ops_spkt; #endif - sock_init_data(sock,sk); - sk_set_owner(sk, THIS_MODULE); + sock_init_data(sock, sk); - po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL); - if (!po) - goto out_free; - memset(po, 0, sizeof(*po)); + po = pkt_sk(sk); sk->sk_family = PF_PACKET; po->num = protocol; @@ -1021,9 +1045,6 @@ static int packet_create(struct socket *sock, int protocol) sk_add_node(sk, &packet_sklist); write_unlock_bh(&packet_sklist_lock); return(0); - -out_free: - sk_free(sk); out: return err; } @@ -1039,6 +1060,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, struct sock *sk = sock->sk; struct sk_buff *skb; int copied, err; + struct sockaddr_ll *sll; err = -EINVAL; if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) @@ -1050,16 +1072,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, return -ENODEV; #endif - /* - * If the address length field is there to be filled in, we fill - * it in now. - */ - - if (sock->type == SOCK_PACKET) - msg->msg_namelen = sizeof(struct sockaddr_pkt); - else - msg->msg_namelen = sizeof(struct sockaddr_ll); - /* * Call the generic datagram receiver. This handles all sorts * of horrible races and re-entrancy so we can forget about it @@ -1077,9 +1089,20 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, * retries. */ - if(skb==NULL) + if (skb == NULL) goto out; + /* + * If the address length field is there to be filled in, we fill + * it in now. + */ + + sll = (struct sockaddr_ll*)skb->cb; + if (sock->type == SOCK_PACKET) + msg->msg_namelen = sizeof(struct sockaddr_pkt); + else + msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); + /* * You lose any data beyond the buffer you gave. If it worries a * user program they can ask the device for its MTU anyway. @@ -1141,7 +1164,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, { struct net_device *dev; struct sock *sk = sock->sk; - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr; if (peer) @@ -1160,7 +1183,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_halen = 0; } - *uaddr_len = sizeof(*sll); + *uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen; return 0; } @@ -1193,9 +1216,9 @@ static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, i } } -static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq) +static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) { - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); struct packet_mclist *ml, *i; struct net_device *dev; int err; @@ -1212,7 +1235,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq) goto done; err = -ENOBUFS; - i = (struct packet_mclist *)kmalloc(sizeof(*i), GFP_KERNEL); + i = kmalloc(sizeof(*i), GFP_KERNEL); if (i == NULL) goto done; @@ -1243,7 +1266,7 @@ done: return err; } -static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq) +static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) { struct packet_mclist *ml, **mlp; @@ -1274,7 +1297,7 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq) static void packet_flush_mclist(struct sock *sk) { - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); struct packet_mclist *ml; if (!po->mclist) @@ -1309,11 +1332,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { - struct packet_mreq mreq; - if (optlen sizeof(mreq)) + len = sizeof(mreq); + if (copy_from_user(&mreq,optval,len)) return -EFAULT; + if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address))) + return -EINVAL; if (optname == PACKET_ADD_MEMBERSHIP) ret = packet_mc_add(sk, &mreq); else @@ -1355,13 +1384,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, { int len; struct sock *sk = sock->sk; - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); if (level != SOL_PACKET) return -ENOPROTOOPT; - if (get_user(len,optlen)) - return -EFAULT; + if (get_user(len, optlen)) + return -EFAULT; if (len < 0) return -EINVAL; @@ -1387,9 +1416,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, return -ENOPROTOOPT; } - if (put_user(len, optlen)) - return -EFAULT; - return 0; + if (put_user(len, optlen)) + return -EFAULT; + return 0; } @@ -1401,7 +1430,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void read_lock(&packet_sklist_lock); sk_for_each(sk, node, &packet_sklist) { - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); switch (msg) { case NETDEV_UNREGISTER: @@ -1490,7 +1519,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, #endif default: - return dev_ioctl(cmd, (void __user *)arg); + return -ENOIOCTLCMD; } return 0; } @@ -1504,7 +1533,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); unsigned int mask = datagram_poll(file, sock, wait); spin_lock_bh(&sk->sk_receive_queue.lock); @@ -1529,8 +1558,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, static void packet_mm_open(struct vm_area_struct *vma) { struct file *file = vma->vm_file; - struct inode *inode = file->f_dentry->d_inode; - struct socket * sock = SOCKET_I(inode); + struct socket * sock = file->private_data; struct sock *sk = sock->sk; if (sk) @@ -1540,8 +1568,7 @@ static void packet_mm_open(struct vm_area_struct *vma) static void packet_mm_close(struct vm_area_struct *vma) { struct file *file = vma->vm_file; - struct inode *inode = file->f_dentry->d_inode; - struct socket * sock = SOCKET_I(inode); + struct socket * sock = file->private_data; struct sock *sk = sock->sk; if (sk) @@ -1558,28 +1585,52 @@ static inline struct page *pg_vec_endpage(char *one_pg_vec, unsigned int order) return virt_to_page(one_pg_vec + (PAGE_SIZE << order) - 1); } -static void free_pg_vec(char **pg_vec, unsigned order, unsigned len) +static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len) { int i; - for (i=0; itp_block_nr; + char **pg_vec; + int i; + + pg_vec = kzalloc(block_nr * sizeof(char *), GFP_KERNEL); + if (unlikely(!pg_vec)) + goto out; + + for (i = 0; i < block_nr; i++) { + pg_vec[i] = alloc_one_pg_vec_page(order); + if (unlikely(!pg_vec[i])) + goto out_free_pgvec; + } + +out: + return pg_vec; + +out_free_pgvec: + free_pg_vec(pg_vec, order, block_nr); + pg_vec = NULL; + goto out; +} static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) { char **pg_vec = NULL; - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); int was_running, num, order = 0; int err = 0; @@ -1588,64 +1639,46 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing /* Sanity tests and some calculations */ - if (po->pg_vec) + if (unlikely(po->pg_vec)) return -EBUSY; - if ((int)req->tp_block_size <= 0) + if (unlikely((int)req->tp_block_size <= 0)) return -EINVAL; - if (req->tp_block_size&(PAGE_SIZE-1)) + if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) return -EINVAL; - if (req->tp_frame_size < TPACKET_HDRLEN) + if (unlikely(req->tp_frame_size < TPACKET_HDRLEN)) return -EINVAL; - if (req->tp_frame_size&(TPACKET_ALIGNMENT-1)) + if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) return -EINVAL; po->frames_per_block = req->tp_block_size/req->tp_frame_size; - if (po->frames_per_block <= 0) + if (unlikely(po->frames_per_block <= 0)) return -EINVAL; - if (po->frames_per_block*req->tp_block_nr != req->tp_frame_nr) + if (unlikely((po->frames_per_block * req->tp_block_nr) != + req->tp_frame_nr)) return -EINVAL; - /* OK! */ - - /* Allocate page vector */ - while ((PAGE_SIZE<tp_block_size) - order++; err = -ENOMEM; - - pg_vec = kmalloc(req->tp_block_nr*sizeof(char *), GFP_KERNEL); - if (pg_vec == NULL) + order = get_order(req->tp_block_size); + pg_vec = alloc_pg_vec(req, order); + if (unlikely(!pg_vec)) goto out; - memset(pg_vec, 0, req->tp_block_nr*sizeof(char **)); - - for (i=0; itp_block_nr; i++) { - struct page *page, *pend; - pg_vec[i] = (char *)__get_free_pages(GFP_KERNEL, order); - if (!pg_vec[i]) - goto out_free_pgvec; - - pend = pg_vec_endpage(pg_vec[i], order); - for (page = virt_to_page(pg_vec[i]); page <= pend; page++) - SetPageReserved(page); - } - /* Page vector is allocated */ l = 0; - for (i=0; itp_block_nr; i++) { + for (i = 0; i < req->tp_block_nr; i++) { char *ptr = pg_vec[i]; struct tpacket_hdr *header; int k; - for (k=0; kframes_per_block; k++) { - - header = (struct tpacket_hdr*)ptr; + for (k = 0; k < po->frames_per_block; k++) { + header = (struct tpacket_hdr *) ptr; header->tp_status = TP_STATUS_KERNEL; ptr += req->tp_frame_size; } } /* Done */ } else { - if (req->tp_frame_nr) + if (unlikely(req->tp_frame_nr)) return -EINVAL; } @@ -1672,7 +1705,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing spin_lock_bh(&sk->sk_receive_queue.lock); pg_vec = XC(po->pg_vec, pg_vec); - po->frame_max = req->tp_frame_nr-1; + po->frame_max = (req->tp_frame_nr - 1); po->head = 0; po->frame_size = req->tp_frame_size; spin_unlock_bh(&sk->sk_receive_queue.lock); @@ -1699,7 +1732,6 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing release_sock(sk); -out_free_pgvec: if (pg_vec) free_pg_vec(pg_vec, order, req->tp_block_nr); out: @@ -1709,7 +1741,7 @@ out: static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) { struct sock *sk = sock->sk; - struct packet_opt *po = pkt_sk(sk); + struct packet_sock *po = pkt_sk(sk); unsigned long size; unsigned long start; int err = -EINVAL; @@ -1726,17 +1758,19 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) goto out; - atomic_inc(&po->mapped); start = vma->vm_start; - err = -EAGAIN; - for (i=0; ipg_vec_len; i++) { - if (remap_pfn_range(vma, start, - __pa(po->pg_vec[i]) >> PAGE_SHIFT, - po->pg_vec_pages*PAGE_SIZE, - vma->vm_page_prot)) - goto out; - start += po->pg_vec_pages*PAGE_SIZE; + for (i = 0; i < po->pg_vec_len; i++) { + struct page *page = virt_to_page(po->pg_vec[i]); + int pg_num; + + for (pg_num = 0; pg_num < po->pg_vec_pages; pg_num++, page++) { + err = vm_insert_page(vma, start, page); + if (unlikely(err)) + goto out; + start += PAGE_SIZE; + } } + atomic_inc(&po->mapped); vma->vm_ops = &packet_mmap_ops; err = 0; @@ -1748,7 +1782,7 @@ out: #ifdef CONFIG_SOCK_PACKET -static struct proto_ops packet_ops_spkt = { +static const struct proto_ops packet_ops_spkt = { .family = PF_PACKET, .owner = THIS_MODULE, .release = packet_release, @@ -1770,7 +1804,7 @@ static struct proto_ops packet_ops_spkt = { }; #endif -static struct proto_ops packet_ops = { +static const struct proto_ops packet_ops = { .family = PF_PACKET, .owner = THIS_MODULE, .release = packet_release, @@ -1839,7 +1873,7 @@ static int packet_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "sk RefCnt Type Proto Iface R Rmem User Inode\n"); else { struct sock *s = v; - const struct packet_opt *po = pkt_sk(s); + const struct packet_sock *po = pkt_sk(s); seq_printf(seq, "%p %-6d %-4d %04x %-5d %1d %-6u %-6u %-6lu\n", @@ -1884,16 +1918,21 @@ static void __exit packet_exit(void) proc_net_remove("packet"); unregister_netdevice_notifier(&packet_netdev_notifier); sock_unregister(PF_PACKET); - return; + proto_unregister(&packet_proto); } static int __init packet_init(void) { + int rc = proto_register(&packet_proto, 0); + + if (rc != 0) + goto out; + sock_register(&packet_family_ops); register_netdevice_notifier(&packet_netdev_notifier); proc_net_fops_create("packet", 0, &packet_seq_fops); - - return 0; +out: + return rc; } module_init(packet_init);