x_tables.c revision be91fd5e323b46450ca82f6828e933e3791fb2f2
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 */ 15be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 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; 423e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal int 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 577e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = { 587e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_UNSPEC] = "x", 597e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_IPV4] = "ip", 607e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_ARP] = "arp", 617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_BRIDGE] = "eb", 627e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_IPV6] = "ip6", 6337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}; 6437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */ 662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint 67a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target) 682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = target->family; 7076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt int ret; 712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 729e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[af].mutex); 732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_add(&target->list, &xt[af].target); 769e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target); 802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid 82a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target) 832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 8476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = target->family; 85a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso 869e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[af].mutex); 87df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&target->list); 889e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target); 912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint 9352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n) 9452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 9552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 9652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy int err = 0; 9752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 9852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) { 9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy err = xt_register_target(&target[i]); 10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (err) 10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy goto err; 10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy } 10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr: 10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (i > 0) 10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_targets(target, i); 10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets); 11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid 11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n) 11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) 11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_target(&target[i]); 11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets); 12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint 123a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match) 1242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = match->family; 12676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt int ret; 1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1289e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[af].mutex); 1292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 1302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_add(&match->list, &xt[af].match); 1339e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match); 1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid 140a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match) 1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 14276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = match->family; 143a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso 1449e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[af].mutex); 145df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&match->list); 1469e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 1482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match); 1492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 15052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint 15152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n) 15252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 15352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy int err = 0; 15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) { 15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy err = xt_register_match(&match[i]); 15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (err) 15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy goto err; 16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy } 16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr: 16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (i > 0) 16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_matches(match, i); 16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches); 16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid 17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n) 17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) 17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_match(&match[i]); 17752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 17852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches); 17952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* 1822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex 1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single 1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module(). 1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */ 1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref. Returns ERR_PTR() on error. */ 18876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision) 1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_match *m; 1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int err = 0; 1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1939e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(m, &xt[af].match, list) { 1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(m->name, name) == 0) { 1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision == revision) { 1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (try_module_get(m->me)) { 2009e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return m; 2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } else 2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte err = -EPROTOTYPE; /* Found something. */ 2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2079e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 20855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 20955b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt if (af != NFPROTO_UNSPEC) 21055b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt /* Try searching again in the family-independent list */ 21155b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt return xt_find_match(NFPROTO_UNSPEC, name, revision); 21255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 2132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(err); 2142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match); 2162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref. Returns ERR_PTR() on error. */ 21876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision) 2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_target *t; 2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int err = 0; 2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(t, &xt[af].target, list) { 2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0) { 2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision == revision) { 2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (try_module_get(t->me)) { 2309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return t; 2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } else 2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte err = -EPROTOTYPE; /* Found something. */ 2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2379e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 23855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 23955b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt if (af != NFPROTO_UNSPEC) 24055b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt /* Try searching again in the family-independent list */ 24155b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt return xt_find_target(NFPROTO_UNSPEC, name, revision); 24255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(err); 2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target); 2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 24776108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision) 2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_target *target; 2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte target = try_then_request_module(xt_find_target(af, name, revision), 25237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy "%st_%s", xt_prefix[af], name); 2532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (IS_ERR(target) || !target) 2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return target; 2562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target); 2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 25976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp) 2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2615452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *m; 2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev = 0; 2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(m, &xt[af].match, list) { 2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(m->name, name) == 0) { 2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision > *bestp) 2672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *bestp = m->revision; 2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision == revision) 2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = 1; 2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 272656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 273656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy if (af != NFPROTO_UNSPEC && !have_rev) 274656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy return match_revfn(NFPROTO_UNSPEC, name, revision, bestp); 275656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return have_rev; 2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 27976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp) 2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2815452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *t; 2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev = 0; 2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(t, &xt[af].target, list) { 2852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0) { 2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision > *bestp) 2872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *bestp = t->revision; 2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision == revision) 2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = 1; 2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 292656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 293656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy if (af != NFPROTO_UNSPEC && !have_rev) 294656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy return target_revfn(NFPROTO_UNSPEC, name, revision, bestp); 295656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return have_rev; 2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */ 30076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target, 3012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int *err) 3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev, best = -1; 3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3059e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) { 3062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -EINTR; 3072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 1; 3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (target == 1) 3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = target_revfn(af, name, revision, &best); 3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = match_revfn(af, name, revision, &best); 3139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Nothing at all? Return 0 to try loading module. */ 3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (best == -1) { 3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -ENOENT; 3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 0; 3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = best; 3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!have_rev) 3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -EPROTONOSUPPORT; 3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 1; 3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 3262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision); 3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 328451853645f3cb804b523227eca054701e4cbc589Jan Engelhardtstatic char *textify_hooks(char *buf, size_t size, unsigned int mask) 329451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{ 330451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt static const char *const names[] = { 331451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "PREROUTING", "INPUT", "FORWARD", 332451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "OUTPUT", "POSTROUTING", "BROUTING", 333451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt }; 334451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt unsigned int i; 335451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char *p = buf; 336451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt bool np = false; 337451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt int res; 338451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 339451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt *p = '\0'; 340451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt for (i = 0; i < ARRAY_SIZE(names); ++i) { 341451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt if (!(mask & (1 << i))) 342451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt continue; 343451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]); 344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt if (res > 0) { 345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt size -= res; 346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt p += res; 347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt } 348451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt np = true; 349451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt } 350451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt return buf; 352451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt} 353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 354916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par, 3559b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt unsigned int size, u_int8_t proto, bool inv_proto) 35637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{ 3579b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (XT_ALIGN(par->match->matchsize) != size && 3589b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt par->match->matchsize != -1) { 359043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt /* 360043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt * ebt_among is exempt from centralized matchsize checking 361043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt * because it uses a dynamic-size data set. 362043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt */ 363b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt pr_err("%s_tables: %s.%u match: invalid size " 364b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt "%u (kernel) != (user) %u\n", 365916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 366b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt par->match->revision, 3679b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt XT_ALIGN(par->match->matchsize), size); 36837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 36937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3709b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->table != NULL && 3719b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt strcmp(par->match->table, par->table) != 0) { 3723dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: only valid in %s table, not %s\n", 373916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 3749b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt par->match->table, par->table); 37537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 37637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3779b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { 378451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char used[64], allow[64]; 379451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 3803dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: used from hooks %s, but only " 381451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "valid from %s\n", 382916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 383451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(used, sizeof(used), par->hook_mask), 384451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(allow, sizeof(allow), par->match->hooks)); 38537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 38637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3879b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->proto && (par->match->proto != proto || inv_proto)) { 3883dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: only valid for protocol %u\n", 389916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 390916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt par->match->proto); 39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 39237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3939b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->checkentry != NULL && !par->match->checkentry(par)) 394367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt return -EINVAL; 39537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return 0; 39637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy} 39737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match); 39837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 3992722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 40076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta) 401b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 402b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp; 403b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 404b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); 405b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (!tmp) 406b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return -ENOMEM; 407b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 408b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->offset = offset; 409b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->delta = delta; 410b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 411b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (xt[af].compat_offsets) { 412b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->next = xt[af].compat_offsets->next; 413b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets->next = tmp; 414b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } else { 415b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets = tmp; 416b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->next = NULL; 417b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 418b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return 0; 419b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 420b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset); 421b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 42276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af) 423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 424b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp, *next; 425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 426b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (xt[af].compat_offsets) { 427b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy for (tmp = xt[af].compat_offsets; tmp; tmp = next) { 428b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy next = tmp->next; 429b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy kfree(tmp); 430b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 431b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets = NULL; 432b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 433b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets); 435b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 4363e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphalint xt_compat_calc_jump(u_int8_t af, unsigned int offset) 437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 438b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp; 4393e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal int delta; 440b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 441b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) 442b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (tmp->offset < offset) 443b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy delta += tmp->delta; 444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return delta; 445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump); 447b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 4485452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match) 4492722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 4509fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t csize = match->compatsize ? : match->matchsize; 4519fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize); 4529fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 4539fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset); 4549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4558956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, 456b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy unsigned int *size) 4579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 4585452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *match = m->u.kernel.match; 4599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; 4609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int pad, off = xt_compat_match_offset(match); 4619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t msize = cm->u.user.match_size; 4629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy m = *dstptr; 4649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(m, cm, sizeof(*cm)); 4659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_from_user) 4669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy match->compat_from_user(m->data, cm->data); 4679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy else 4689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(m->data, cm->data, msize - sizeof(*cm)); 4699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy pad = XT_ALIGN(match->matchsize) - match->matchsize; 4709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (pad > 0) 4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memset(m->data + match->matchsize, 0, pad); 4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy msize += off; 4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy m->u.user.match_size = msize; 4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size += off; 4779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += msize; 4788956695131b8a7878891667469899d667eb5892bPatrick McHardy return 0; 4799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user); 4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 482739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m, 483739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt void __user **dstptr, unsigned int *size) 4849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 4855452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *match = m->u.kernel.match; 4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_match __user *cm = *dstptr; 4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int off = xt_compat_match_offset(match); 4889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t msize = m->u.user.match_size - off; 4899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(cm, m, sizeof(*cm)) || 491a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy put_user(msize, &cm->u.user.match_size) || 492a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy copy_to_user(cm->u.user.name, m->u.kernel.match->name, 493a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy strlen(m->u.kernel.match->name) + 1)) 494601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki return -EFAULT; 4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_to_user) { 4979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_to_user((void __user *)cm->data, m->data)) 4989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 4999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy } else { 5009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(cm->data, m->data, msize - sizeof(*cm))) 5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 5022722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin } 5039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size -= off; 5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += msize; 5069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return 0; 5072722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 5089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user); 5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */ 5102722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 511916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par, 512af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt unsigned int size, u_int8_t proto, bool inv_proto) 51337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{ 514af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (XT_ALIGN(par->target->targetsize) != size) { 515b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt pr_err("%s_tables: %s.%u target: invalid size " 516b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt "%u (kernel) != (user) %u\n", 517916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 518b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt par->target->revision, 519af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt XT_ALIGN(par->target->targetsize), size); 52037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 52137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 522af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->table != NULL && 523af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt strcmp(par->target->table, par->table) != 0) { 5243dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: only valid in %s table, not %s\n", 525916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 526af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt par->target->table, par->table); 52737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 52837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 529af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { 530451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char used[64], allow[64]; 531451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 5323dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: used from hooks %s, but only " 533451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "usable from %s\n", 534916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 535451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(used, sizeof(used), par->hook_mask), 536451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(allow, sizeof(allow), par->target->hooks)); 53737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 53837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 539af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->proto && (par->target->proto != proto || inv_proto)) { 5403dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: only valid for protocol %u\n", 541916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 542af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt par->target->proto); 54337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 54437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 545af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->checkentry != NULL && !par->target->checkentry(par)) 546367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt return -EINVAL; 54737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return 0; 54837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy} 54937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target); 55037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 5512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 5525452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target) 5532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 5549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t csize = target->compatsize ? : target->targetsize; 5559fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize); 5569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 5579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset); 5589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, 560b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy unsigned int *size) 5619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 5625452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *target = t->u.kernel.target; 5639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; 5649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int pad, off = xt_compat_target_offset(target); 5659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t tsize = ct->u.user.target_size; 5669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy t = *dstptr; 5689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(t, ct, sizeof(*ct)); 5699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_from_user) 5709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy target->compat_from_user(t->data, ct->data); 5719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy else 5729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(t->data, ct->data, tsize - sizeof(*ct)); 5739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy pad = XT_ALIGN(target->targetsize) - target->targetsize; 5749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (pad > 0) 5759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memset(t->data + target->targetsize, 0, pad); 5769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy tsize += off; 5789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy t->u.user.target_size = tsize; 5799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size += off; 5819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += tsize; 5829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 5839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user); 5849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 585739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t, 586739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt void __user **dstptr, unsigned int *size) 5879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 5885452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *target = t->u.kernel.target; 5899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_target __user *ct = *dstptr; 5909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int off = xt_compat_target_offset(target); 5919fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t tsize = t->u.user.target_size - off; 5929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(ct, t, sizeof(*ct)) || 594a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy put_user(tsize, &ct->u.user.target_size) || 595a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy copy_to_user(ct->u.user.name, t->u.kernel.target->name, 596a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy strlen(t->u.kernel.target->name) + 1)) 597601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki return -EFAULT; 5989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_to_user) { 6009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_to_user((void __user *)ct->data, t->data)) 6019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 6029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy } else { 6039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct))) 6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 6052722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin } 6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size -= off; 6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += tsize; 6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return 0; 6102722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 6119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user); 6122722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 6132722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 6142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size) 6152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *newinfo; 6172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int cpu; 6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ 6204481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages) 6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 623259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL); 6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!newinfo) 6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->size = size; 6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6296f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) { 6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (size <= PAGE_SIZE) 6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->entries[cpu] = kmalloc_node(size, 6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte GFP_KERNEL, 6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte cpu_to_node(cpu)); 6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 6352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->entries[cpu] = vmalloc_node(size, 6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte cpu_to_node(cpu)); 6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (newinfo->entries[cpu] == NULL) { 6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte xt_free_table_info(newinfo); 6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return newinfo; 6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info); 6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info) 6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int cpu; 6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6526f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) { 6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (info->size <= PAGE_SIZE) 6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(info->entries[cpu]); 6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte vfree(info->entries[cpu]); 6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(info); 6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info); 6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ 66376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, 66476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt const char *name) 6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table *t; 6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6689e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6718d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_for_each_entry(t, &net->xt.tables[af], list) 6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0 && try_module_get(t->me)) 6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return t; 6749e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock); 6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table) 6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6819e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock); 6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6852722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 68676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af) 6872722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 6882722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_lock(&xt[af].compat_mutex); 6892722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 6902722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock); 6912722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 69276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af) 6932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 6942722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_unlock(&xt[af].compat_mutex); 6952722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 6962722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock); 6972722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 6982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 699942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerDEFINE_PER_CPU(struct xt_info_lock, xt_info_locks); 700942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerEXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks); 701942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 702942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 7032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info * 7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table, 7052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unsigned int num_counters, 7062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *newinfo, 7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int *error) 7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 709942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger struct xt_table_info *private; 7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Do the substitution. */ 712942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_disable(); 7132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 714942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Check inside lock: is the old number correct? */ 7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (num_counters != private->number) { 717be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt pr_debug("num_counters != table->private->number (%u/%u)\n", 7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte num_counters, private->number); 719942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_enable(); 7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *error = -EAGAIN; 7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 724942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger table->private = newinfo; 725942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger newinfo->initial_entries = private->initial_entries; 726942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 727942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger /* 728942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * Even though table entries have now been swapped, other CPU's 729942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * may still be using the old entries. This is okay, because 730942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * resynchronization happens because of the locking done 731942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * during the get_counters() routine. 732942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger */ 733942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_enable(); 734942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 735942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger return private; 7362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table); 7382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 73935aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net, 74035aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt const struct xt_table *input_table, 741a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan struct xt_table_info *bootstrap, 742a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan struct xt_table_info *newinfo) 7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int ret; 7452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *private; 74635aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt struct xt_table *t, *table; 7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 74844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan /* Don't add one object to multiple lists. */ 74935aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); 75044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan if (!table) { 75144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan ret = -ENOMEM; 75244d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan goto out; 75344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan } 75444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan 7559e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[table->af].mutex); 7562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 75744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan goto out_free; 7582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Don't autoload: we'd eat our tail... */ 7608d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_for_each_entry(t, &net->xt.tables[table->af], list) { 761df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy if (strcmp(t->name, table->name) == 0) { 762df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy ret = -EEXIST; 763df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy goto unlock; 764df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy } 7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 7662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Simplifies replace_table code. */ 7682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte table->private = bootstrap; 769784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger 7702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!xt_replace_table(table, 0, newinfo, &ret)) 7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto unlock; 7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 774be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt pr_debug("table->private->number = %u\n", private->number); 7752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* save number of initial entries */ 7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private->initial_entries = private->number; 7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7798d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_add(&table->list, &net->xt.tables[table->af]); 780a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan mutex_unlock(&xt[table->af].mutex); 781a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan return table; 7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock: 7849e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 78544d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free: 78644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan kfree(table); 787a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout: 788a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan return ERR_PTR(ret); 7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table); 7912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table) 7932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *private; 7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7969e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[table->af].mutex); 7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 798df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&table->list); 7999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 80044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan kfree(table); 8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return private; 8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table); 8052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 807715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv { 808715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct seq_net_private p; 80976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af; 810715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan}; 811025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) 8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 813715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 8141218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 81576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 8162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 817025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan mutex_lock(&xt[af].mutex); 818715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan return seq_list_start(&net->xt.tables[af], *pos); 819025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 8202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 821025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos) 822025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 823715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 8241218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 82576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 8262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 827715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan return seq_list_next(v, &net->xt.tables[af], pos); 8282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 830025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v) 8312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 832715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 83376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 835025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan mutex_unlock(&xt[af].mutex); 836025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 838025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v) 839025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 840025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan struct xt_table *table = list_entry(v, struct xt_table, list); 8412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 842025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan if (strlen(table->name)) 843025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return seq_printf(seq, "%s\n", table->name); 844025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan else 845025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return 0; 846025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 847601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki 848025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = { 849025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_table_seq_start, 850025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_table_seq_next, 851025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .stop = xt_table_seq_stop, 852025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_table_seq_show, 853025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 854025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 855025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file) 856025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 857025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan int ret; 858715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv; 859025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 860715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan ret = seq_open_net(inode, file, &xt_table_seq_ops, 861715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan sizeof(struct xt_names_priv)); 862025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan if (!ret) { 863715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan priv = ((struct seq_file *)file->private_data)->private; 864715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan priv->af = (unsigned long)PDE(inode)->data; 865025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan } 866025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return ret; 8672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 869025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = { 870025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .owner = THIS_MODULE, 871025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_table_open, 872025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .read = seq_read, 873025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .llseek = seq_lseek, 8740e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov .release = seq_release_net, 875025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 876025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 877eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/* 878eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing 879eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes. 880eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */ 881eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav { 882eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct list_head *head, *curr; 883eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt uint8_t class, nfproto; 884eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}; 885eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 886eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum { 887eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_INIT, 888eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_NFP_UNSPEC, 889eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_NFP_SPEC, 890eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_DONE, 891eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}; 892eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 893eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos, 894eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt bool is_target) 8952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 896eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt static const uint8_t next_class[] = { 897eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt [MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC, 898eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt [MTTG_TRAV_NFP_SPEC] = MTTG_TRAV_DONE, 899eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt }; 900eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 901eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 902eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 903eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_INIT: 904eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = MTTG_TRAV_NFP_UNSPEC; 905eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_lock(&xt[NFPROTO_UNSPEC].mutex); 906eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->head = trav->curr = is_target ? 907eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt &xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match; 908eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 909eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 910eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->curr = trav->curr->next; 911eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr != trav->head) 912eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 913eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); 914eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_lock(&xt[trav->nfproto].mutex); 915eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->head = trav->curr = is_target ? 916eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt &xt[trav->nfproto].target : &xt[trav->nfproto].match; 917eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = next_class[trav->class]; 918eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 919eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 920eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->curr = trav->curr->next; 921eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr != trav->head) 922eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 923eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt /* fallthru, _stop will unlock */ 924eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt default: 925eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return NULL; 926eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 9272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 928eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ppos != NULL) 929eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ++*ppos; 930eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return trav; 931025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 932601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki 933eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos, 934eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt bool is_target) 935025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 936eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 937eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt unsigned int j; 9382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 939eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = MTTG_TRAV_INIT; 940eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt for (j = 0; j < *pos; ++j) 941eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL) 942eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return NULL; 943eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return trav; 9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 946eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v) 9472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 948eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 949eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 950eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 951eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 952eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); 953eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 954eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 955eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[trav->nfproto].mutex); 956eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 957eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 958eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt} 9592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 960eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) 961eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{ 962eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_start(seq, pos, false); 9632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 965eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos) 9662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 967eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_next(seq, v, ppos, false); 968eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt} 9692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 970eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v) 971eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{ 972eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct nf_mttg_trav *trav = seq->private; 973eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct xt_match *match; 974eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 975eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 976eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 977eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 978eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr == trav->head) 979eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 980eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt match = list_entry(trav->curr, struct xt_match, list); 981eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return (*match->name == '\0') ? 0 : 982eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq_printf(seq, "%s\n", match->name); 983eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 984eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 9852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 987025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = { 988025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_match_seq_start, 989025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_match_seq_next, 990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .stop = xt_mttg_seq_stop, 991025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_match_seq_show, 9922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 9932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 994025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file) 9952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct seq_file *seq; 997eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav; 9982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int ret; 9992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1000eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav = kmalloc(sizeof(*trav), GFP_KERNEL); 1001eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav == NULL) 1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return -ENOMEM; 10032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1004eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ret = seq_open(file, &xt_match_seq_ops); 1005eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ret < 0) { 1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt kfree(trav); 1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return ret; 10082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 1009eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq = file->private_data; 1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq->private = trav; 1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->nfproto = (unsigned long)PDE(inode)->data; 1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1014025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1015025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1016025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = { 1017025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .owner = THIS_MODULE, 1018025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_match_open, 1019025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .read = seq_read, 1020025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .llseek = seq_lseek, 1021eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .release = seq_release_private, 1022025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 10232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1024025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos) 1025025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1026eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_start(seq, pos, true); 1027025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1028025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1029eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos) 1030025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1031eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_next(seq, v, ppos, true); 1032025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1033025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1034025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v) 1035025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1036eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct nf_mttg_trav *trav = seq->private; 1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct xt_target *target; 1038eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1039eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 1040eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 1041eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr == trav->head) 1043eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt target = list_entry(trav->curr, struct xt_target, list); 1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return (*target->name == '\0') ? 0 : 1046eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq_printf(seq, "%s\n", target->name); 1047eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 1048eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1049025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1050025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1051025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = { 1052025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_target_seq_start, 1053025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_target_seq_next, 1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .stop = xt_mttg_seq_stop, 1055025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_target_seq_show, 1056025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 1057025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1058025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file) 1059025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct seq_file *seq; 1061eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav; 1062025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan int ret; 1063025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1064eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav = kmalloc(sizeof(*trav), GFP_KERNEL); 1065eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav == NULL) 1066eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return -ENOMEM; 1067025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1068eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ret = seq_open(file, &xt_target_seq_ops); 1069eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ret < 0) { 1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt kfree(trav); 1071eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return ret; 1072025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan } 1073eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1074eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq = file->private_data; 1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq->private = trav; 1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->nfproto = (unsigned long)PDE(inode)->data; 1077eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 10782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 10792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1080025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = { 10812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .owner = THIS_MODULE, 1082025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_target_open, 10832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .read = seq_read, 10842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .llseek = seq_lseek, 1085eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .release = seq_release_private, 10862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 10872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 10882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES "_tables_names" 10892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_MATCHES "_tables_matches" 10902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS "_tables_targets" 10912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 10922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */ 10932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 10942b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/** 10952b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table 10962b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table: table with metadata needed to set up hooks 10972b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn: Hook function 10982b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * 10992b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary 11002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables. 11012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */ 11022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn) 11032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{ 11042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt unsigned int hook_mask = table->valid_hooks; 11052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt uint8_t i, num_hooks = hweight32(hook_mask); 11062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt uint8_t hooknum; 11072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt struct nf_hook_ops *ops; 11082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt int ret; 11092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); 11112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (ops == NULL) 11122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ERR_PTR(-ENOMEM); 11132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0; 11152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt hook_mask >>= 1, ++hooknum) { 11162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (!(hook_mask & 1)) 11172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt continue; 11182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].hook = fn; 11192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].owner = table->me; 11202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].pf = table->af; 11212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].hooknum = hooknum; 11222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].priority = table->priority; 11232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ++i; 11242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt } 11252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ret = nf_register_hooks(ops, num_hooks); 11272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (ret < 0) { 11282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt kfree(ops); 11292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ERR_PTR(ret); 11302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt } 11312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ops; 11332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt} 11342b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link); 11352b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 11362b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/** 11372b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table 11382b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops: nf_hook_ops array as returned by nf_hook_link 11392b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask: the very same mask that was passed to nf_hook_link 11402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */ 11412b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops) 11422b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{ 11432b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt nf_unregister_hooks(ops, hweight32(table->valid_hooks)); 11442b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt kfree(ops); 11452b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt} 11462b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink); 11472b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 114876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af) 11492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 11502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 11512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte char buf[XT_FUNCTION_MAXNAMELEN]; 11522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct proc_dir_entry *proc; 11532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 11542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11557e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt if (af >= ARRAY_SIZE(xt_prefix)) 11562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -EINVAL; 11572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 1160ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 11628b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops, 11638b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 11642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 11652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out; 11662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1167ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 11698b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops, 11708b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 11712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 11722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out_remove_tables; 11732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1174ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TARGETS, sizeof(buf)); 11768b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops, 11778b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 11782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 11792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out_remove_matches; 11802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 11812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 0; 11832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 11852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches: 1186ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 11883cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 11892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables: 1191ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 11922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 11933cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 11942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout: 11952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -1; 11962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 11972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 11982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init); 11992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 120076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af) 12012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 12032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte char buf[XT_FUNCTION_MAXNAMELEN]; 12042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1205ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 12073cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1209ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TARGETS, sizeof(buf)); 12113cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1213ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 12153cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/ 12172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini); 12192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12208d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net) 12218d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{ 12228d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan int i; 12238d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan 12247e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt for (i = 0; i < NFPROTO_NUMPROTO; i++) 12258d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan INIT_LIST_HEAD(&net->xt.tables[i]); 12268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan return 0; 12278d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan} 12288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan 12298d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = { 12308d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan .init = xt_net_init, 12318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}; 12322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void) 12342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1235942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger unsigned int i; 1236942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger int rv; 1237942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 1238942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger for_each_possible_cpu(i) { 1239942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger struct xt_info_lock *lock = &per_cpu(xt_info_locks, i); 1240942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger spin_lock_init(&lock->lock); 1241942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger lock->readers = 0; 1242942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger } 12432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12447e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL); 12452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!xt) 12462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -ENOMEM; 12472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12487e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt for (i = 0; i < NFPROTO_NUMPROTO; i++) { 12499e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_init(&xt[i].mutex); 12502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 12512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_init(&xt[i].compat_mutex); 1252b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[i].compat_offsets = NULL; 12532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 12542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte INIT_LIST_HEAD(&xt[i].target); 12552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte INIT_LIST_HEAD(&xt[i].match); 12562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 12578d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan rv = register_pernet_subsys(&xt_net_ops); 12588d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan if (rv < 0) 12598d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan kfree(xt); 12608d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan return rv; 12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void) 12642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12658d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan unregister_pernet_subsys(&xt_net_ops); 12662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(xt); 12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init); 12702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini); 12712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1272