X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=net%2Fipv6%2Fnetfilter%2Fip6_queue.c;h=db4d5725cce8c252ecb0b47e23b82b12fde5f112;hb=424eff975192553a9ea8bfd51bf65039ffb356ef;hp=9c50cb19b39b92f845866e59ad094b81c371dab9;hpb=7a6c6653b3a977087ec64d76817c7ee6e1df5b60;p=safe%2Fjmp%2Flinux-2.6 diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 9c50cb1..db4d572 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -39,13 +39,7 @@ #define NET_IPQ_QMAX 2088 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen" -struct ipq_queue_entry { - struct list_head list; - struct nf_info *info; - struct sk_buff *skb; -}; - -typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); +typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long); static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; @@ -59,17 +53,8 @@ static struct sock *ipqnl __read_mostly; static LIST_HEAD(queue_list); static DEFINE_MUTEX(ipqnl_mutex); -static void -ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) -{ - local_bh_disable(); - nf_reinject(entry->skb, entry->info, verdict); - local_bh_enable(); - kfree(entry); -} - static inline void -__ipq_enqueue_entry(struct ipq_queue_entry *entry) +__ipq_enqueue_entry(struct nf_queue_entry *entry) { list_add_tail(&entry->list, &queue_list); queue_total++; @@ -112,10 +97,10 @@ __ipq_reset(void) __ipq_flush(NULL, 0); } -static struct ipq_queue_entry * +static struct nf_queue_entry * ipq_find_dequeue_entry(unsigned long id) { - struct ipq_queue_entry *entry = NULL, *i; + struct nf_queue_entry *entry = NULL, *i; write_lock_bh(&queue_lock); @@ -138,13 +123,13 @@ ipq_find_dequeue_entry(unsigned long id) static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data) { - struct ipq_queue_entry *entry, *next; + struct nf_queue_entry *entry, *next; list_for_each_entry_safe(entry, next, &queue_list, list) { if (!cmpfn || cmpfn(entry, data)) { list_del(&entry->list); queue_total--; - ipq_issue_verdict(entry, NF_DROP); + nf_reinject(entry, NF_DROP); } } } @@ -158,7 +143,7 @@ ipq_flush(ipq_cmpfn cmpfn, unsigned long data) } static struct sk_buff * -ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) +ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) { sk_buff_data_t old_tail; size_t size = 0; @@ -174,7 +159,6 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) case IPQ_COPY_META: case IPQ_COPY_NONE: size = NLMSG_SPACE(sizeof(*pmsg)); - data_len = 0; break; case IPQ_COPY_PACKET: @@ -215,20 +199,20 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) pmsg->timestamp_sec = tv.tv_sec; pmsg->timestamp_usec = tv.tv_usec; pmsg->mark = entry->skb->mark; - pmsg->hook = entry->info->hook; + pmsg->hook = entry->hook; pmsg->hw_protocol = entry->skb->protocol; - if (entry->info->indev) - strcpy(pmsg->indev_name, entry->info->indev->name); + if (entry->indev) + strcpy(pmsg->indev_name, entry->indev->name); else pmsg->indev_name[0] = '\0'; - if (entry->info->outdev) - strcpy(pmsg->outdev_name, entry->info->outdev->name); + if (entry->outdev) + strcpy(pmsg->outdev_name, entry->outdev->name); else pmsg->outdev_name[0] = '\0'; - if (entry->info->indev && entry->skb->dev) { + if (entry->indev && entry->skb->dev) { pmsg->hw_type = entry->skb->dev->type; pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr); } @@ -241,36 +225,23 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) return skb; nlmsg_failure: - if (skb) - kfree_skb(skb); *errp = -EINVAL; printk(KERN_ERR "ip6_queue: error creating packet message\n"); return NULL; } static int -ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, - unsigned int queuenum) +ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; - struct ipq_queue_entry *entry; if (copy_mode == IPQ_COPY_NONE) return -EAGAIN; - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) { - printk(KERN_ERR "ip6_queue: OOM in ipq_enqueue_packet()\n"); - return -ENOMEM; - } - - entry->info = info; - entry->skb = skb; - nskb = ipq_build_packet_message(entry, &status); if (nskb == NULL) - goto err_out_free; + return status; write_lock_bh(&queue_lock); @@ -304,18 +275,15 @@ err_out_free_nskb: err_out_unlock: write_unlock_bh(&queue_lock); - -err_out_free: - kfree(entry); return status; } static int -ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) +ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) { int diff; - int err; struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -327,14 +295,15 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, - diff - skb_tailroom(e->skb), - GFP_ATOMIC); - if (err) { + nskb = skb_copy_expand(e->skb, skb_headroom(e->skb), + diff, GFP_ATOMIC); + if (!nskb) { printk(KERN_WARNING "ip6_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } @@ -349,7 +318,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) static int ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) { - struct ipq_queue_entry *entry; + struct nf_queue_entry *entry; if (vmsg->value > NF_MAX_VERDICT) return -EINVAL; @@ -364,7 +333,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) if (ipq_mangle_ipv6(vmsg, entry) < 0) verdict = NF_DROP; - ipq_issue_verdict(entry, verdict); + nf_reinject(entry, verdict); return 0; } } @@ -409,14 +378,14 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg, } static int -dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex) +dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) { - if (entry->info->indev) - if (entry->info->indev->ifindex == ifindex) + if (entry->indev) + if (entry->indev->ifindex == ifindex) return 1; - if (entry->info->outdev) - if (entry->info->outdev->ifindex == ifindex) + if (entry->outdev) + if (entry->outdev->ifindex == ifindex) return 1; #ifdef CONFIG_BRIDGE_NETFILTER if (entry->skb->nf_bridge) { @@ -511,7 +480,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ @@ -530,10 +499,9 @@ ipq_rcv_nl_event(struct notifier_block *this, { struct netlink_notify *n = ptr; - if (event == NETLINK_URELEASE && - n->protocol == NETLINK_IP6_FW && n->pid) { + if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) { write_lock_bh(&queue_lock); - if ((n->net == &init_net) && (n->pid == peer_pid)) + if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } @@ -544,6 +512,7 @@ static struct notifier_block ipq_nl_notifier = { .notifier_call = ipq_rcv_nl_event, }; +#ifdef CONFIG_SYSCTL static struct ctl_table_header *ipq_sysctl_header; static ctl_table ipq_table[] = { @@ -557,27 +526,9 @@ static ctl_table ipq_table[] = { }, { .ctl_name = 0 } }; +#endif -static ctl_table ipq_dir_table[] = { - { - .ctl_name = NET_IPV6, - .procname = "ipv6", - .mode = 0555, - .child = ipq_table - }, - { .ctl_name = 0 } -}; - -static ctl_table ipq_root_table[] = { - { - .ctl_name = CTL_NET, - .procname = "net", - .mode = 0555, - .child = ipq_dir_table - }, - { .ctl_name = 0 } -}; - +#ifdef CONFIG_PROC_FS static int ip6_queue_show(struct seq_file *m, void *v) { read_lock_bh(&queue_lock); @@ -614,6 +565,7 @@ static const struct file_operations ip6_queue_proc_fops = { .release = single_release, .owner = THIS_MODULE, }; +#endif static const struct nf_queue_handler nfqh = { .name = "ip6_queue", @@ -623,7 +575,7 @@ static const struct nf_queue_handler nfqh = { static int __init ip6_queue_init(void) { int status = -ENOMEM; - struct proc_dir_entry *proc; + struct proc_dir_entry *proc __maybe_unused; netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, @@ -633,19 +585,19 @@ static int __init ip6_queue_init(void) goto cleanup_netlink_notifier; } - proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net); - if (proc) { - proc->owner = THIS_MODULE; - proc->proc_fops = &ip6_queue_proc_fops; - } else { +#ifdef CONFIG_PROC_FS + proc = proc_create(IPQ_PROC_FS_NAME, 0, init_net.proc_net, + &ip6_queue_proc_fops); + if (!proc) { printk(KERN_ERR "ip6_queue: failed to create proc entry\n"); goto cleanup_ipqnl; } - +#endif register_netdevice_notifier(&ipq_dev_notifier); - ipq_sysctl_header = register_sysctl_table(ipq_root_table); - - status = nf_register_queue_handler(PF_INET6, &nfqh); +#ifdef CONFIG_SYSCTL + ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table); +#endif + status = nf_register_queue_handler(NFPROTO_IPV6, &nfqh); if (status < 0) { printk(KERN_ERR "ip6_queue: failed to register queue handler\n"); goto cleanup_sysctl; @@ -653,12 +605,14 @@ static int __init ip6_queue_init(void) return status; cleanup_sysctl: +#ifdef CONFIG_SYSCTL unregister_sysctl_table(ipq_sysctl_header); +#endif unregister_netdevice_notifier(&ipq_dev_notifier); proc_net_remove(&init_net, IPQ_PROC_FS_NAME); -cleanup_ipqnl: - sock_release(ipqnl->sk_socket); +cleanup_ipqnl: __maybe_unused + netlink_kernel_release(ipqnl); mutex_lock(&ipqnl_mutex); mutex_unlock(&ipqnl_mutex); @@ -670,14 +624,16 @@ cleanup_netlink_notifier: static void __exit ip6_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); - synchronize_net(); + ipq_flush(NULL, 0); +#ifdef CONFIG_SYSCTL unregister_sysctl_table(ipq_sysctl_header); +#endif unregister_netdevice_notifier(&ipq_dev_notifier); proc_net_remove(&init_net, IPQ_PROC_FS_NAME); - sock_release(ipqnl->sk_socket); + netlink_kernel_release(ipqnl); mutex_lock(&ipqnl_mutex); mutex_unlock(&ipqnl_mutex); @@ -686,6 +642,7 @@ static void __exit ip6_queue_fini(void) MODULE_DESCRIPTION("IPv6 packet queue handler"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_IP6_FW); module_init(ip6_queue_init); module_exit(ip6_queue_fini);