x_tables.c revision 739674fb7febf116e7d647031fab16989a08a965
12e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* 22e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * x_tables core - Backend for {ip,ip6,arp}_tables 32e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * 42e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org> 52e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * 62e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Based on existing ip_tables code which is 72e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling 82e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org> 92e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * 102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * This program is free software; you can redistribute it and/or modify 112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * it under the terms of the GNU General Public License version 2 as 122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * published by the Free Software Foundation. 132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * 142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */ 152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/kernel.h> 172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/socket.h> 182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/net.h> 192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/proc_fs.h> 202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/seq_file.h> 212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/string.h> 222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/vmalloc.h> 239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar#include <linux/mutex.h> 24d7fe0f241dceade9c8d4af75498765c5ff7f27e6Al Viro#include <linux/mm.h> 25457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h> 262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h> 282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h> 29e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h> 30e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h> 31e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_arp/arp_tables.h> 329e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar 332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL"); 342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 35043ef46c7690bfdbd5b012e15812a14a19ca5604Jan EngelhardtMODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module"); 362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) 382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 39b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardystruct compat_delta { 40b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *next; 41b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy unsigned int offset; 42b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy short delta; 43b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}; 44b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af { 469e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar struct mutex mutex; 472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct list_head match; 482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct list_head target; 49b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#ifdef CONFIG_COMPAT 502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin struct mutex compat_mutex; 51b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *compat_offsets; 52b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#endif 532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt; 562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef DEBUG_IP_FIREWALL_USER 582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) printk(format , ## args) 592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#else 602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) 612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 637e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = { 647e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_UNSPEC] = "x", 657e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_IPV4] = "ip", 667e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_ARP] = "arp", 677e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_BRIDGE] = "eb", 687e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_IPV6] = "ip6", 6937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}; 7037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */ 722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint 73a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target) 742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = target->family; 7676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt int ret; 772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 789e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[af].mutex); 792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_add(&target->list, &xt[af].target); 829e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target); 862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid 88a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target) 892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 9076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = target->family; 91a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso 929e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[af].mutex); 93df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&target->list); 949e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target); 972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint 9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n) 10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy int err = 0; 10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) { 10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy err = xt_register_target(&target[i]); 10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (err) 10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy goto err; 10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy } 10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr: 11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (i > 0) 11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_targets(target, i); 11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets); 11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid 11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n) 12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 12352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) 12452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_target(&target[i]); 12552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 12652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets); 12752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 12852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint 129a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match) 1302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 13176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = match->family; 13276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt int ret; 1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1349e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[af].mutex); 1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_add(&match->list, &xt[af].match); 1399e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 1402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 1422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match); 1442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid 146a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match) 1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 14876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = match->family; 149a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso 1509e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[af].mutex); 151df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&match->list); 1529e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 1542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match); 1552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint 15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n) 15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy int err = 0; 16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) { 16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy err = xt_register_match(&match[i]); 16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (err) 16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy goto err; 16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy } 16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr: 17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (i > 0) 17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_matches(match, i); 17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches); 17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid 17752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n) 17852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 17952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 18052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 18152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) 18252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_match(&match[i]); 18352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 18452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches); 18552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* 1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex 1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single 1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module(). 1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */ 1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref. Returns ERR_PTR() on error. */ 19476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision) 1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_match *m; 1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int err = 0; 1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(m, &xt[af].match, list) { 2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(m->name, name) == 0) { 2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision == revision) { 2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (try_module_get(m->me)) { 2069e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return m; 2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } else 2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte err = -EPROTOTYPE; /* Found something. */ 2112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 21455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 21555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt if (af != NFPROTO_UNSPEC) 21655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt /* Try searching again in the family-independent list */ 21755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt return xt_find_match(NFPROTO_UNSPEC, name, revision); 21855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(err); 2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match); 2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref. Returns ERR_PTR() on error. */ 22476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision) 2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_target *t; 2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int err = 0; 2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2299e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(t, &xt[af].target, list) { 2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0) { 2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision == revision) { 2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (try_module_get(t->me)) { 2369e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return t; 2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } else 2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte err = -EPROTOTYPE; /* Found something. */ 2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2439e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 24455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 24555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt if (af != NFPROTO_UNSPEC) 24655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt /* Try searching again in the family-independent list */ 24755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt return xt_find_target(NFPROTO_UNSPEC, name, revision); 24855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(err); 2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target); 2522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 25376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision) 2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_target *target; 2562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte target = try_then_request_module(xt_find_target(af, name, revision), 25837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy "%st_%s", xt_prefix[af], name); 2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (IS_ERR(target) || !target) 2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return target; 2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target); 2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 26576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp) 2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2675452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *m; 2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev = 0; 2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(m, &xt[af].match, list) { 2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(m->name, name) == 0) { 2722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision > *bestp) 2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *bestp = m->revision; 2742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision == revision) 2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = 1; 2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 278656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 279656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy if (af != NFPROTO_UNSPEC && !have_rev) 280656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy return match_revfn(NFPROTO_UNSPEC, name, revision, bestp); 281656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return have_rev; 2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 28576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp) 2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2875452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *t; 2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev = 0; 2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(t, &xt[af].target, list) { 2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0) { 2922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision > *bestp) 2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *bestp = t->revision; 2942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision == revision) 2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = 1; 2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 298656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 299656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy if (af != NFPROTO_UNSPEC && !have_rev) 300656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy return target_revfn(NFPROTO_UNSPEC, name, revision, bestp); 301656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return have_rev; 3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */ 30676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target, 3072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int *err) 3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev, best = -1; 3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3119e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) { 3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -EINTR; 3132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 1; 3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (target == 1) 3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = target_revfn(af, name, revision, &best); 3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = match_revfn(af, name, revision, &best); 3199e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Nothing at all? Return 0 to try loading module. */ 3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (best == -1) { 3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -ENOENT; 3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 0; 3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = best; 3282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!have_rev) 3292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -EPROTONOSUPPORT; 3302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 1; 3312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 3322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision); 3332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 334451853645f3cb804b523227eca054701e4cbc589Jan Engelhardtstatic char *textify_hooks(char *buf, size_t size, unsigned int mask) 335451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{ 336451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt static const char *const names[] = { 337451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "PREROUTING", "INPUT", "FORWARD", 338451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "OUTPUT", "POSTROUTING", "BROUTING", 339451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt }; 340451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt unsigned int i; 341451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char *p = buf; 342451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt bool np = false; 343451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt int res; 344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt *p = '\0'; 346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt for (i = 0; i < ARRAY_SIZE(names); ++i) { 347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt if (!(mask & (1 << i))) 348451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt continue; 349451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]); 350451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt if (res > 0) { 351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt size -= res; 352451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt p += res; 353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt } 354451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt np = true; 355451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt } 356451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 357451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt return buf; 358451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt} 359451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 360916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par, 3619b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt unsigned int size, u_int8_t proto, bool inv_proto) 36237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{ 3639b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (XT_ALIGN(par->match->matchsize) != size && 3649b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt par->match->matchsize != -1) { 365043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt /* 366043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt * ebt_among is exempt from centralized matchsize checking 367043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt * because it uses a dynamic-size data set. 368043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt */ 369b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt pr_err("%s_tables: %s.%u match: invalid size " 370b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt "%u (kernel) != (user) %u\n", 371916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 372b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt par->match->revision, 3739b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt XT_ALIGN(par->match->matchsize), size); 37437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 37537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3769b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->table != NULL && 3779b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt strcmp(par->match->table, par->table) != 0) { 3783dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: only valid in %s table, not %s\n", 379916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 3809b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt par->match->table, par->table); 38137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 38237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3839b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { 384451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char used[64], allow[64]; 385451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 3863dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: used from hooks %s, but only " 387451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "valid from %s\n", 388916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 389451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(used, sizeof(used), par->hook_mask), 390451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(allow, sizeof(allow), par->match->hooks)); 39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 39237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3939b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->proto && (par->match->proto != proto || inv_proto)) { 3943dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: only valid for protocol %u\n", 395916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 396916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt par->match->proto); 39737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 39837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3999b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->checkentry != NULL && !par->match->checkentry(par)) 400367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt return -EINVAL; 40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return 0; 40237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy} 40337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match); 40437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 4052722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 40676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta) 407b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 408b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp; 409b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 410b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); 411b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (!tmp) 412b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return -ENOMEM; 413b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 414b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->offset = offset; 415b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->delta = delta; 416b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 417b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (xt[af].compat_offsets) { 418b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->next = xt[af].compat_offsets->next; 419b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets->next = tmp; 420b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } else { 421b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets = tmp; 422b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->next = NULL; 423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 424b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return 0; 425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 426b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset); 427b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 42876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af) 429b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 430b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp, *next; 431b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 432b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (xt[af].compat_offsets) { 433b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy for (tmp = xt[af].compat_offsets; tmp; tmp = next) { 434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy next = tmp->next; 435b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy kfree(tmp); 436b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets = NULL; 438b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 439b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 440b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets); 441b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 44276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtshort xt_compat_calc_jump(u_int8_t af, unsigned int offset) 443b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp; 445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy short delta; 446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 447b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) 448b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (tmp->offset < offset) 449b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy delta += tmp->delta; 450b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return delta; 451b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 452b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump); 453b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 4545452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match) 4552722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 4569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t csize = match->compatsize ? : match->matchsize; 4579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize); 4589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 4599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset); 4609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4618956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, 462b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy unsigned int *size) 4639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 4645452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *match = m->u.kernel.match; 4659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; 4669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int pad, off = xt_compat_match_offset(match); 4679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t msize = cm->u.user.match_size; 4689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy m = *dstptr; 4709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(m, cm, sizeof(*cm)); 4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_from_user) 4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy match->compat_from_user(m->data, cm->data); 4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy else 4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(m->data, cm->data, msize - sizeof(*cm)); 4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy pad = XT_ALIGN(match->matchsize) - match->matchsize; 4769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (pad > 0) 4779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memset(m->data + match->matchsize, 0, pad); 4789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy msize += off; 4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy m->u.user.match_size = msize; 4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size += off; 4839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += msize; 4848956695131b8a7878891667469899d667eb5892bPatrick McHardy return 0; 4859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user); 4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 488739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m, 489739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt void __user **dstptr, unsigned int *size) 4909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 4915452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *match = m->u.kernel.match; 4929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_match __user *cm = *dstptr; 4939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int off = xt_compat_match_offset(match); 4949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t msize = m->u.user.match_size - off; 4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(cm, m, sizeof(*cm)) || 497a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy put_user(msize, &cm->u.user.match_size) || 498a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy copy_to_user(cm->u.user.name, m->u.kernel.match->name, 499a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy strlen(m->u.kernel.match->name) + 1)) 500601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki return -EFAULT; 5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_to_user) { 5039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_to_user((void __user *)cm->data, m->data)) 5049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy } else { 5069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(cm->data, m->data, msize - sizeof(*cm))) 5079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 5082722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin } 5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size -= off; 5119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += msize; 5129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return 0; 5132722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 5149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user); 5159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */ 5162722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 517916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par, 518af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt unsigned int size, u_int8_t proto, bool inv_proto) 51937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{ 520af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (XT_ALIGN(par->target->targetsize) != size) { 521b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt pr_err("%s_tables: %s.%u target: invalid size " 522b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt "%u (kernel) != (user) %u\n", 523916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 524b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt par->target->revision, 525af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt XT_ALIGN(par->target->targetsize), size); 52637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 52737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 528af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->table != NULL && 529af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt strcmp(par->target->table, par->table) != 0) { 5303dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: only valid in %s table, not %s\n", 531916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 532af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt par->target->table, par->table); 53337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 53437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 535af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { 536451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char used[64], allow[64]; 537451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 5383dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: used from hooks %s, but only " 539451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "usable from %s\n", 540916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 541451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(used, sizeof(used), par->hook_mask), 542451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(allow, sizeof(allow), par->target->hooks)); 54337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 54437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 545af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->proto && (par->target->proto != proto || inv_proto)) { 5463dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: only valid for protocol %u\n", 547916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 548af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt par->target->proto); 54937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 55037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 551af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->checkentry != NULL && !par->target->checkentry(par)) 552367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt return -EINVAL; 55337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return 0; 55437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy} 55537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target); 55637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 5572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 5585452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target) 5592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 5609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t csize = target->compatsize ? : target->targetsize; 5619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize); 5629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 5639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset); 5649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, 566b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy unsigned int *size) 5679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 5685452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *target = t->u.kernel.target; 5699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; 5709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int pad, off = xt_compat_target_offset(target); 5719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t tsize = ct->u.user.target_size; 5729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy t = *dstptr; 5749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(t, ct, sizeof(*ct)); 5759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_from_user) 5769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy target->compat_from_user(t->data, ct->data); 5779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy else 5789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(t->data, ct->data, tsize - sizeof(*ct)); 5799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy pad = XT_ALIGN(target->targetsize) - target->targetsize; 5809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (pad > 0) 5819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memset(t->data + target->targetsize, 0, pad); 5829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy tsize += off; 5849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy t->u.user.target_size = tsize; 5859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size += off; 5879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += tsize; 5889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 5899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user); 5909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 591739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t, 592739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt void __user **dstptr, unsigned int *size) 5939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 5945452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *target = t->u.kernel.target; 5959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_target __user *ct = *dstptr; 5969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int off = xt_compat_target_offset(target); 5979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t tsize = t->u.user.target_size - off; 5989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(ct, t, sizeof(*ct)) || 600a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy put_user(tsize, &ct->u.user.target_size) || 601a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy copy_to_user(ct->u.user.name, t->u.kernel.target->name, 602a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy strlen(t->u.kernel.target->name) + 1)) 603601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki return -EFAULT; 6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_to_user) { 6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_to_user((void __user *)ct->data, t->data)) 6079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy } else { 6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct))) 6109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 6112722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin } 6129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size -= off; 6149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += tsize; 6159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return 0; 6162722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 6179fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user); 6182722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 6192722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 6202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size) 6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *newinfo; 6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int cpu; 6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ 6264481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages) 6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 629259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL); 6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!newinfo) 6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->size = size; 6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6356f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) { 6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (size <= PAGE_SIZE) 6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->entries[cpu] = kmalloc_node(size, 6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte GFP_KERNEL, 6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte cpu_to_node(cpu)); 6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->entries[cpu] = vmalloc_node(size, 6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte cpu_to_node(cpu)); 6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (newinfo->entries[cpu] == NULL) { 6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte xt_free_table_info(newinfo); 6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return newinfo; 6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info); 6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info) 6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int cpu; 6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6586f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) { 6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (info->size <= PAGE_SIZE) 6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(info->entries[cpu]); 6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte vfree(info->entries[cpu]); 6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(info); 6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info); 6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ 66976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, 67076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt const char *name) 6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table *t; 6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6749e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6778d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_for_each_entry(t, &net->xt.tables[af], list) 6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0 && try_module_get(t->me)) 6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return t; 6809e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock); 6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table) 6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6879e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock); 6902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6912722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 69276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af) 6932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 6942722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_lock(&xt[af].compat_mutex); 6952722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 6962722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock); 6972722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 69876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af) 6992722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 7002722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_unlock(&xt[af].compat_mutex); 7012722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 7022722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock); 7032722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 705942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerDEFINE_PER_CPU(struct xt_info_lock, xt_info_locks); 706942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerEXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks); 707942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 708942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info * 7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table, 7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unsigned int num_counters, 7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *newinfo, 7132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int *error) 7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 715942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger struct xt_table_info *private; 7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Do the substitution. */ 718942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_disable(); 7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 720942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Check inside lock: is the old number correct? */ 7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (num_counters != private->number) { 7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte duprintf("num_counters != table->private->number (%u/%u)\n", 7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte num_counters, private->number); 725942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_enable(); 7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *error = -EAGAIN; 7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 730942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger table->private = newinfo; 731942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger newinfo->initial_entries = private->initial_entries; 732942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 733942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger /* 734942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * Even though table entries have now been swapped, other CPU's 735942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * may still be using the old entries. This is okay, because 736942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * resynchronization happens because of the locking done 737942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * during the get_counters() routine. 738942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger */ 739942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_enable(); 740942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 741942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger return private; 7422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table); 7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 74535aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net, 74635aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt const struct xt_table *input_table, 747a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan struct xt_table_info *bootstrap, 748a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan struct xt_table_info *newinfo) 7492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int ret; 7512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *private; 75235aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt struct xt_table *t, *table; 7532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 75444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan /* Don't add one object to multiple lists. */ 75535aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); 75644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan if (!table) { 75744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan ret = -ENOMEM; 75844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan goto out; 75944d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan } 76044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan 7619e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[table->af].mutex); 7622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 76344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan goto out_free; 7642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Don't autoload: we'd eat our tail... */ 7668d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_for_each_entry(t, &net->xt.tables[table->af], list) { 767df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy if (strcmp(t->name, table->name) == 0) { 768df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy ret = -EEXIST; 769df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy goto unlock; 770df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy } 7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Simplifies replace_table code. */ 7742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte table->private = bootstrap; 775784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger 7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!xt_replace_table(table, 0, newinfo, &ret)) 7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto unlock; 7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 7802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte duprintf("table->private->number = %u\n", private->number); 7812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* save number of initial entries */ 7832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private->initial_entries = private->number; 7842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7858d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_add(&table->list, &net->xt.tables[table->af]); 786a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan mutex_unlock(&xt[table->af].mutex); 787a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan return table; 7882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock: 7909e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 79144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free: 79244d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan kfree(table); 793a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout: 794a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan return ERR_PTR(ret); 7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table); 7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table) 7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *private; 8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8029e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[table->af].mutex); 8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 804df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&table->list); 8059e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 80644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan kfree(table); 8072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return private; 8092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table); 8112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 813715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv { 814715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct seq_net_private p; 81576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af; 816715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan}; 817025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) 8182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 819715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 8201218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 82176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 823025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan mutex_lock(&xt[af].mutex); 824715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan return seq_list_start(&net->xt.tables[af], *pos); 825025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 8262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 827025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos) 828025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 829715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 8301218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 83176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 8322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 833715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan return seq_list_next(v, &net->xt.tables[af], pos); 8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 836025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v) 8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 838715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 83976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 8402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 841025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan mutex_unlock(&xt[af].mutex); 842025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 8432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 844025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v) 845025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 846025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan struct xt_table *table = list_entry(v, struct xt_table, list); 8472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 848025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan if (strlen(table->name)) 849025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return seq_printf(seq, "%s\n", table->name); 850025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan else 851025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return 0; 852025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 853601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki 854025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = { 855025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_table_seq_start, 856025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_table_seq_next, 857025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .stop = xt_table_seq_stop, 858025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_table_seq_show, 859025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 860025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 861025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file) 862025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 863025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan int ret; 864715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv; 865025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 866715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan ret = seq_open_net(inode, file, &xt_table_seq_ops, 867715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan sizeof(struct xt_names_priv)); 868025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan if (!ret) { 869715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan priv = ((struct seq_file *)file->private_data)->private; 870715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan priv->af = (unsigned long)PDE(inode)->data; 871025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan } 872025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return ret; 8732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 875025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = { 876025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .owner = THIS_MODULE, 877025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_table_open, 878025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .read = seq_read, 879025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .llseek = seq_lseek, 8800e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov .release = seq_release_net, 881025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 882025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 883eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/* 884eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing 885eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes. 886eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */ 887eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav { 888eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct list_head *head, *curr; 889eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt uint8_t class, nfproto; 890eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}; 891eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 892eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum { 893eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_INIT, 894eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_NFP_UNSPEC, 895eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_NFP_SPEC, 896eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_DONE, 897eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}; 898eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 899eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos, 900eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt bool is_target) 9012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 902eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt static const uint8_t next_class[] = { 903eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt [MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC, 904eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt [MTTG_TRAV_NFP_SPEC] = MTTG_TRAV_DONE, 905eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt }; 906eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 907eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 908eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 909eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_INIT: 910eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = MTTG_TRAV_NFP_UNSPEC; 911eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_lock(&xt[NFPROTO_UNSPEC].mutex); 912eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->head = trav->curr = is_target ? 913eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt &xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match; 914eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 915eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 916eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->curr = trav->curr->next; 917eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr != trav->head) 918eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 919eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); 920eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_lock(&xt[trav->nfproto].mutex); 921eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->head = trav->curr = is_target ? 922eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt &xt[trav->nfproto].target : &xt[trav->nfproto].match; 923eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = next_class[trav->class]; 924eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 925eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 926eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->curr = trav->curr->next; 927eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr != trav->head) 928eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 929eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt /* fallthru, _stop will unlock */ 930eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt default: 931eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return NULL; 932eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 9332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 934eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ppos != NULL) 935eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ++*ppos; 936eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return trav; 937025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 938601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki 939eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos, 940eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt bool is_target) 941025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 942eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 943eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt unsigned int j; 9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 945eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = MTTG_TRAV_INIT; 946eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt for (j = 0; j < *pos; ++j) 947eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL) 948eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return NULL; 949eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return trav; 9502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 952eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v) 9532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 954eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 955eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 956eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 957eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 958eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); 959eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 960eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 961eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[trav->nfproto].mutex); 962eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 963eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 964eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt} 9652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 966eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) 967eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{ 968eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_start(seq, pos, false); 9692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 971eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos) 9722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 973eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_next(seq, v, ppos, false); 974eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt} 9752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 976eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v) 977eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{ 978eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct nf_mttg_trav *trav = seq->private; 979eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct xt_match *match; 980eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 981eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 982eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 983eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 984eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr == trav->head) 985eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 986eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt match = list_entry(trav->curr, struct xt_match, list); 987eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return (*match->name == '\0') ? 0 : 988eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq_printf(seq, "%s\n", match->name); 989eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 9912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 993025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = { 994025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_match_seq_start, 995025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_match_seq_next, 996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .stop = xt_mttg_seq_stop, 997025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_match_seq_show, 9982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 9992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1000025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file) 10012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct seq_file *seq; 1003eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav; 10042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int ret; 10052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav = kmalloc(sizeof(*trav), GFP_KERNEL); 1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav == NULL) 1008eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return -ENOMEM; 10092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ret = seq_open(file, &xt_match_seq_ops); 1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ret < 0) { 1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt kfree(trav); 1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return ret; 10142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 1015eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1016eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq = file->private_data; 1017eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq->private = trav; 1018eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->nfproto = (unsigned long)PDE(inode)->data; 1019eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1020025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1021025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1022025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = { 1023025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .owner = THIS_MODULE, 1024025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_match_open, 1025025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .read = seq_read, 1026025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .llseek = seq_lseek, 1027eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .release = seq_release_private, 1028025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 10292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1030025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos) 1031025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1032eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_start(seq, pos, true); 1033025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1034025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1035eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos) 1036025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_next(seq, v, ppos, true); 1038025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1039025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1040025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v) 1041025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct nf_mttg_trav *trav = seq->private; 1043eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct xt_target *target; 1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 1046eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 1047eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 1048eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr == trav->head) 1049eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1050eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt target = list_entry(trav->curr, struct xt_target, list); 1051eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return (*target->name == '\0') ? 0 : 1052eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq_printf(seq, "%s\n", target->name); 1053eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1055025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1056025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1057025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = { 1058025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_target_seq_start, 1059025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_target_seq_next, 1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .stop = xt_mttg_seq_stop, 1061025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_target_seq_show, 1062025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 1063025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1064025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file) 1065025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1066eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct seq_file *seq; 1067eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav; 1068025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan int ret; 1069025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav = kmalloc(sizeof(*trav), GFP_KERNEL); 1071eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav == NULL) 1072eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return -ENOMEM; 1073025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1074eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ret = seq_open(file, &xt_target_seq_ops); 1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ret < 0) { 1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt kfree(trav); 1077eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return ret; 1078025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan } 1079eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1080eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq = file->private_data; 1081eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq->private = trav; 1082eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->nfproto = (unsigned long)PDE(inode)->data; 1083eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 10842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 10852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1086025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = { 10872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .owner = THIS_MODULE, 1088025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_target_open, 10892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .read = seq_read, 10902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .llseek = seq_lseek, 1091eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .release = seq_release_private, 10922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 10932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 10942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES "_tables_names" 10952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_MATCHES "_tables_matches" 10962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS "_tables_targets" 10972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 10982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */ 10992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/** 11012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table 11022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table: table with metadata needed to set up hooks 11032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn: Hook function 11042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * 11052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary 11062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables. 11072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */ 11082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn) 11092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{ 11102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt unsigned int hook_mask = table->valid_hooks; 11112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt uint8_t i, num_hooks = hweight32(hook_mask); 11122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt uint8_t hooknum; 11132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt struct nf_hook_ops *ops; 11142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt int ret; 11152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); 11172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (ops == NULL) 11182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ERR_PTR(-ENOMEM); 11192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0; 11212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt hook_mask >>= 1, ++hooknum) { 11222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (!(hook_mask & 1)) 11232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt continue; 11242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].hook = fn; 11252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].owner = table->me; 11262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].pf = table->af; 11272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].hooknum = hooknum; 11282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].priority = table->priority; 11292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ++i; 11302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt } 11312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ret = nf_register_hooks(ops, num_hooks); 11332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (ret < 0) { 11342b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt kfree(ops); 11352b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ERR_PTR(ret); 11362b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt } 11372b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11382b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ops; 11392b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt} 11402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link); 11412b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11422b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/** 11432b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table 11442b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops: nf_hook_ops array as returned by nf_hook_link 11452b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask: the very same mask that was passed to nf_hook_link 11462b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */ 11472b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops) 11482b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{ 11492b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt nf_unregister_hooks(ops, hweight32(table->valid_hooks)); 11502b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt kfree(ops); 11512b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt} 11522b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink); 11532b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 115476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af) 11552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 11562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 11572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte char buf[XT_FUNCTION_MAXNAMELEN]; 11582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct proc_dir_entry *proc; 11592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 11602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt if (af >= ARRAY_SIZE(xt_prefix)) 11622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -EINVAL; 11632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 1166ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 11688b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops, 11698b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 11702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 11712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out; 11722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1173ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 11758b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops, 11768b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 11772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 11782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out_remove_tables; 11792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1180ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TARGETS, sizeof(buf)); 11828b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops, 11838b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 11842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 11852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out_remove_matches; 11862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 11872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 0; 11892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 11912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches: 1192ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 11943cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 11952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables: 1197ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 11993cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout: 12012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -1; 12022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 12032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init); 12052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 120676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af) 12072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 12092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte char buf[XT_FUNCTION_MAXNAMELEN]; 12102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1211ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 12133cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1215ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TARGETS, sizeof(buf)); 12173cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1219ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 12213cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/ 12232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini); 12252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net) 12278d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{ 12288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan int i; 12298d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan 12307e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt for (i = 0; i < NFPROTO_NUMPROTO; i++) 12318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan INIT_LIST_HEAD(&net->xt.tables[i]); 12328d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan return 0; 12338d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan} 12348d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan 12358d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = { 12368d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan .init = xt_net_init, 12378d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}; 12382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void) 12402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1241942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger unsigned int i; 1242942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger int rv; 1243942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 1244942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger for_each_possible_cpu(i) { 1245942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger struct xt_info_lock *lock = &per_cpu(xt_info_locks, i); 1246942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger spin_lock_init(&lock->lock); 1247942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger lock->readers = 0; 1248942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger } 12492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12507e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL); 12512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!xt) 12522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -ENOMEM; 12532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12547e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt for (i = 0; i < NFPROTO_NUMPROTO; i++) { 12559e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_init(&xt[i].mutex); 12562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 12572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_init(&xt[i].compat_mutex); 1258b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[i].compat_offsets = NULL; 12592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 12602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte INIT_LIST_HEAD(&xt[i].target); 12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte INIT_LIST_HEAD(&xt[i].match); 12622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 12638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan rv = register_pernet_subsys(&xt_net_ops); 12648d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan if (rv < 0) 12658d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan kfree(xt); 12668d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan return rv; 12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void) 12702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12718d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan unregister_pernet_subsys(&xt_net_ops); 12722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(xt); 12732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init); 12762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini); 12772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1278