x_tables.c revision d97a9e47ba148cfc41e354c5cd241f472273207c
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> 255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 26457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h> 272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h> 292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h> 30e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h> 31e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h> 32e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_arp/arp_tables.h> 339e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar 342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL"); 352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 36043ef46c7690bfdbd5b012e15812a14a19ca5604Jan EngelhardtMODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module"); 372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) 392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 40b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardystruct compat_delta { 41b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *next; 42b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy unsigned int offset; 433e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal int delta; 44b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}; 45b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af { 479e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar struct mutex mutex; 482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct list_head match; 492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct list_head target; 50b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#ifdef CONFIG_COMPAT 512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin struct mutex compat_mutex; 52b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *compat_offsets; 53b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#endif 542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt; 572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 587e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = { 597e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_UNSPEC] = "x", 607e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_IPV4] = "ip", 617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_ARP] = "arp", 627e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_BRIDGE] = "eb", 637e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt [NFPROTO_IPV6] = "ip6", 6437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}; 6537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 66f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt/* Allow this many total (re)entries. */ 67f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardtstatic const unsigned int xt_jumpstack_multiplier = 2; 68f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */ 702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint 71a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target) 722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = target->family; 7476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt int ret; 752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 769e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[af].mutex); 772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_add(&target->list, &xt[af].target); 809e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target); 842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid 86a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target) 872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 8876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = target->family; 89a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso 909e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[af].mutex); 91df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&target->list); 929e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target); 952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint 9752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n) 9852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy int err = 0; 10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) { 10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy err = xt_register_target(&target[i]); 10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (err) 10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy goto err; 10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy } 10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr: 11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (i > 0) 11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_targets(target, i); 11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets); 11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid 11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n) 11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) 12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_target(&target[i]); 12352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 12452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets); 12552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 12652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint 127a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match) 1282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = match->family; 13076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt int ret; 1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1329e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[af].mutex); 1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_add(&match->list, &xt[af].match); 1379e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ret; 1402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match); 1422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid 144a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match) 1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 14676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = match->family; 147a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso 1489e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[af].mutex); 149df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&match->list); 1509e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 1512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 1522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match); 1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint 15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n) 15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy int err = 0; 15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) { 16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy err = xt_register_match(&match[i]); 16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (err) 16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy goto err; 16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy } 16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr: 16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy if (i > 0) 16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_matches(match, i); 17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy return err; 17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches); 17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid 17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n) 17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{ 17752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy unsigned int i; 17852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 17952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy for (i = 0; i < n; i++) 18052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy xt_unregister_match(&match[i]); 18152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy} 18252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches); 18352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy 1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* 1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex 1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single 1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module(). 1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */ 1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref. Returns ERR_PTR() on error. */ 19276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision) 1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_match *m; 1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int err = 0; 1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1979e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(m, &xt[af].match, list) { 2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(m->name, name) == 0) { 2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision == revision) { 2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (try_module_get(m->me)) { 2049e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return m; 2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } else 2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte err = -EPROTOTYPE; /* Found something. */ 2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2119e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 21255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 21355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt if (af != NFPROTO_UNSPEC) 21455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt /* Try searching again in the family-independent list */ 21555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt return xt_find_match(NFPROTO_UNSPEC, name, revision); 21655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(err); 2182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match); 2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 221fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardtstruct xt_match * 222fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardtxt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision) 223fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt{ 224fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt struct xt_match *match; 225fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt 226fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt match = try_then_request_module(xt_find_match(nfproto, name, revision), 227fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt "%st_%s", xt_prefix[nfproto], name); 228fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt return (match != NULL) ? match : ERR_PTR(-ENOENT); 229fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt} 230fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan EngelhardtEXPORT_SYMBOL_GPL(xt_request_find_match); 231fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt 2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref. Returns ERR_PTR() on error. */ 23376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision) 2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_target *t; 2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int err = 0; 2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2389e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(t, &xt[af].target, list) { 2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0) { 2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision == revision) { 2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (try_module_get(t->me)) { 2459e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return t; 2472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } else 2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte err = -EPROTOTYPE; /* Found something. */ 2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2529e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 25355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 25455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt if (af != NFPROTO_UNSPEC) 25555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt /* Try searching again in the family-independent list */ 25655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt return xt_find_target(NFPROTO_UNSPEC, name, revision); 25755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt 2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(err); 2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target); 2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 26276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision) 2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_target *target; 2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte target = try_then_request_module(xt_find_target(af, name, revision), 26737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy "%st_%s", xt_prefix[af], name); 268d2a7b6bad2c38e41eddb0b24d03627d9e7aa3f7bJan Engelhardt return (target != NULL) ? target : ERR_PTR(-ENOENT); 2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target); 2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 27276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp) 2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2745452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *m; 2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev = 0; 2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(m, &xt[af].match, list) { 2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(m->name, name) == 0) { 2792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision > *bestp) 2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *bestp = m->revision; 2812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (m->revision == revision) 2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = 1; 2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 285656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 286656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy if (af != NFPROTO_UNSPEC && !have_rev) 287656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy return match_revfn(NFPROTO_UNSPEC, name, revision, bestp); 288656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return have_rev; 2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 29276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp) 2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 2945452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *t; 2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev = 0; 2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte list_for_each_entry(t, &xt[af].target, list) { 2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0) { 2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision > *bestp) 3002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *bestp = t->revision; 3012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (t->revision == revision) 3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = 1; 3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 305656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 306656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy if (af != NFPROTO_UNSPEC && !have_rev) 307656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy return target_revfn(NFPROTO_UNSPEC, name, revision, bestp); 308656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy 3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return have_rev; 3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */ 31376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target, 3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int *err) 3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int have_rev, best = -1; 3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3189e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) { 3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -EINTR; 3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 1; 3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (target == 1) 3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = target_revfn(af, name, revision, &best); 3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte have_rev = match_revfn(af, name, revision, &best); 3269e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Nothing at all? Return 0 to try loading module. */ 3292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (best == -1) { 3302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -ENOENT; 3312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 0; 3322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 3332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 3342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = best; 3352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!have_rev) 3362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *err = -EPROTONOSUPPORT; 3372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 1; 3382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 3392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision); 3402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 341451853645f3cb804b523227eca054701e4cbc589Jan Engelhardtstatic char *textify_hooks(char *buf, size_t size, unsigned int mask) 342451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{ 343451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt static const char *const names[] = { 344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "PREROUTING", "INPUT", "FORWARD", 345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "OUTPUT", "POSTROUTING", "BROUTING", 346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt }; 347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt unsigned int i; 348451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char *p = buf; 349451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt bool np = false; 350451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt int res; 351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 352451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt *p = '\0'; 353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt for (i = 0; i < ARRAY_SIZE(names); ++i) { 354451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt if (!(mask & (1 << i))) 355451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt continue; 356451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]); 357451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt if (res > 0) { 358451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt size -= res; 359451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt p += res; 360451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt } 361451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt np = true; 362451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt } 363451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 364451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt return buf; 365451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt} 366451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 367916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par, 3689b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt unsigned int size, u_int8_t proto, bool inv_proto) 36937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{ 370bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt int ret; 371bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt 3729b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (XT_ALIGN(par->match->matchsize) != size && 3739b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt par->match->matchsize != -1) { 374043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt /* 375043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt * ebt_among is exempt from centralized matchsize checking 376043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt * because it uses a dynamic-size data set. 377043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt */ 378b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt pr_err("%s_tables: %s.%u match: invalid size " 379b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt "%u (kernel) != (user) %u\n", 380916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 381b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt par->match->revision, 3829b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt XT_ALIGN(par->match->matchsize), size); 38337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 38437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3859b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->table != NULL && 3869b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt strcmp(par->match->table, par->table) != 0) { 3873dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: only valid in %s table, not %s\n", 388916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 3899b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt par->match->table, par->table); 39037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 3929b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { 393451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char used[64], allow[64]; 394451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 3953dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: used from hooks %s, but only " 396451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "valid from %s\n", 397916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 398451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(used, sizeof(used), par->hook_mask), 399451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(allow, sizeof(allow), par->match->hooks)); 40037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 4029b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->match->proto && (par->match->proto != proto || inv_proto)) { 4033dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s match: only valid for protocol %u\n", 404916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->match->name, 405916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt par->match->proto); 40637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 40737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 408bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt if (par->match->checkentry != NULL) { 409bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt ret = par->match->checkentry(par); 410bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt if (ret < 0) 411bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return ret; 412bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt else if (ret > 0) 413bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt /* Flag up potential errors. */ 414bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return -EIO; 415bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt } 41637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return 0; 41737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy} 41837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match); 41937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 4202722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 42176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta) 422b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp; 424b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); 426b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (!tmp) 427b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return -ENOMEM; 428b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 429b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->offset = offset; 430b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->delta = delta; 431b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 432b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (xt[af].compat_offsets) { 433b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->next = xt[af].compat_offsets->next; 434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets->next = tmp; 435b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } else { 436b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets = tmp; 437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy tmp->next = NULL; 438b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 439b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return 0; 440b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 441b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset); 442b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 44376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af) 444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp, *next; 446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 447b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (xt[af].compat_offsets) { 448b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy for (tmp = xt[af].compat_offsets; tmp; tmp = next) { 449b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy next = tmp->next; 450b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy kfree(tmp); 451b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 452b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[af].compat_offsets = NULL; 453b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy } 454b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 455b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets); 456b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 4573e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphalint xt_compat_calc_jump(u_int8_t af, unsigned int offset) 458b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{ 459b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy struct compat_delta *tmp; 4603e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal int delta; 461b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 462b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) 463b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy if (tmp->offset < offset) 464b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy delta += tmp->delta; 465b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy return delta; 466b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy} 467b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump); 468b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy 4695452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match) 4702722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t csize = match->compatsize ? : match->matchsize; 4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize); 4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset); 4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4768956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, 477b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy unsigned int *size) 4789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 4795452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *match = m->u.kernel.match; 4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; 4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int pad, off = xt_compat_match_offset(match); 4829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t msize = cm->u.user.match_size; 4839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy m = *dstptr; 4859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(m, cm, sizeof(*cm)); 4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_from_user) 4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy match->compat_from_user(m->data, cm->data); 4889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy else 4899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(m->data, cm->data, msize - sizeof(*cm)); 4909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy pad = XT_ALIGN(match->matchsize) - match->matchsize; 4919fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (pad > 0) 4929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memset(m->data + match->matchsize, 0, pad); 4939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy msize += off; 4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy m->u.user.match_size = msize; 4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 4979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size += off; 4989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += msize; 4998956695131b8a7878891667469899d667eb5892bPatrick McHardy return 0; 5009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user); 5029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 503739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m, 504739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt void __user **dstptr, unsigned int *size) 5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 5065452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_match *match = m->u.kernel.match; 5079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_match __user *cm = *dstptr; 5089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int off = xt_compat_match_offset(match); 5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t msize = m->u.user.match_size - off; 5109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(cm, m, sizeof(*cm)) || 512a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy put_user(msize, &cm->u.user.match_size) || 513a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy copy_to_user(cm->u.user.name, m->u.kernel.match->name, 514a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy strlen(m->u.kernel.match->name) + 1)) 515601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki return -EFAULT; 5169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5179fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_to_user) { 5189fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (match->compat_to_user((void __user *)cm->data, m->data)) 5199fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 5209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy } else { 5219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(cm->data, m->data, msize - sizeof(*cm))) 5229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 5232722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin } 5249fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5259fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size -= off; 5269fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += msize; 5279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return 0; 5282722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 5299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user); 5309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */ 5312722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 532916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par, 533af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt unsigned int size, u_int8_t proto, bool inv_proto) 53437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{ 535d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt int ret; 536d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt 537af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (XT_ALIGN(par->target->targetsize) != size) { 538b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt pr_err("%s_tables: %s.%u target: invalid size " 539b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt "%u (kernel) != (user) %u\n", 540916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 541b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt par->target->revision, 542af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt XT_ALIGN(par->target->targetsize), size); 54337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 54437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 545af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->table != NULL && 546af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt strcmp(par->target->table, par->table) != 0) { 5473dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: only valid in %s table, not %s\n", 548916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 549af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt par->target->table, par->table); 55037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 55137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 552af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { 553451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt char used[64], allow[64]; 554451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt 5553dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: used from hooks %s, but only " 556451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt "usable from %s\n", 557916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 558451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(used, sizeof(used), par->hook_mask), 559451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt textify_hooks(allow, sizeof(allow), par->target->hooks)); 56037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 56137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 562af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt if (par->target->proto && (par->target->proto != proto || inv_proto)) { 5633dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches pr_err("%s_tables: %s target: only valid for protocol %u\n", 564916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt xt_prefix[par->family], par->target->name, 565af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt par->target->proto); 56637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return -EINVAL; 56737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy } 568d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt if (par->target->checkentry != NULL) { 569d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt ret = par->target->checkentry(par); 570d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt if (ret < 0) 571d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return ret; 572d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt else if (ret > 0) 573d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt /* Flag up potential errors. */ 574d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt return -EIO; 575d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt } 57637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy return 0; 57737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy} 57837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target); 57937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy 5802722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 5815452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target) 5822722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 5839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t csize = target->compatsize ? : target->targetsize; 5849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize); 5859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 5869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset); 5879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, 589b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy unsigned int *size) 5909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 5915452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *target = t->u.kernel.target; 5929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; 5939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int pad, off = xt_compat_target_offset(target); 5949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t tsize = ct->u.user.target_size; 5959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 5969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy t = *dstptr; 5979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(t, ct, sizeof(*ct)); 5989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_from_user) 5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy target->compat_from_user(t->data, ct->data); 6009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy else 6019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memcpy(t->data, ct->data, tsize - sizeof(*ct)); 6029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy pad = XT_ALIGN(target->targetsize) - target->targetsize; 6039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (pad > 0) 6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy memset(t->data + target->targetsize, 0, pad); 6059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy tsize += off; 6079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy t->u.user.target_size = tsize; 6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size += off; 6109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += tsize; 6119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy} 6129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user); 6139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 614739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t, 615739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt void __user **dstptr, unsigned int *size) 6169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{ 6175452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt const struct xt_target *target = t->u.kernel.target; 6189fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy struct compat_xt_entry_target __user *ct = *dstptr; 6199fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy int off = xt_compat_target_offset(target); 6209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy u_int16_t tsize = t->u.user.target_size - off; 6219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(ct, t, sizeof(*ct)) || 623a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy put_user(tsize, &ct->u.user.target_size) || 624a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy copy_to_user(ct->u.user.name, t->u.kernel.target->name, 625a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy strlen(t->u.kernel.target->name) + 1)) 626601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki return -EFAULT; 6279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6289fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_to_user) { 6299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (target->compat_to_user((void __user *)ct->data, t->data)) 6309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 6319fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy } else { 6329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct))) 6339fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return -EFAULT; 6342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin } 6359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy 6369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *size -= off; 6379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy *dstptr += tsize; 6389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy return 0; 6392722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 6409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user); 6412722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 6422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size) 6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *newinfo; 6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int cpu; 6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ 6494481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages) 6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 652259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL); 6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!newinfo) 6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->size = size; 6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6586f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) { 6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (size <= PAGE_SIZE) 6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->entries[cpu] = kmalloc_node(size, 6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte GFP_KERNEL, 6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte cpu_to_node(cpu)); 6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte newinfo->entries[cpu] = vmalloc_node(size, 6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte cpu_to_node(cpu)); 6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (newinfo->entries[cpu] == NULL) { 6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte xt_free_table_info(newinfo); 6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return newinfo; 6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info); 6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info) 6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int cpu; 6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 6816f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) { 6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (info->size <= PAGE_SIZE) 6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(info->entries[cpu]); 6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte else 6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte vfree(info->entries[cpu]); 6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 687f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 688f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (info->jumpstack != NULL) { 689f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (sizeof(void *) * info->stacksize > PAGE_SIZE) { 690f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt for_each_possible_cpu(cpu) 691f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt vfree(info->jumpstack[cpu]); 692f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt } else { 693f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt for_each_possible_cpu(cpu) 694f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt kfree(info->jumpstack[cpu]); 695f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt } 696f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt } 697f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 698f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE) 699f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt vfree(info->jumpstack); 700f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt else 701f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt kfree(info->jumpstack); 702f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE) 703f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt vfree(info->stackptr); 704f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt else 705f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt kfree(info->stackptr); 706f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(info); 7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info); 7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ 71276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, 71376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt const char *name) 7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table *t; 7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7179e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar if (mutex_lock_interruptible(&xt[af].mutex) != 0) 7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return ERR_PTR(-EINTR); 7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7208d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_for_each_entry(t, &net->xt.tables[af], list) 7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (strcmp(t->name, name) == 0 && try_module_get(t->me)) 7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return t; 7239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[af].mutex); 7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 7252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock); 7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table) 7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 7309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 7312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 7322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock); 7332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 7342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 73576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af) 7362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 7372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_lock(&xt[af].compat_mutex); 7382722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 7392722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock); 7402722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin 74176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af) 7422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{ 7432722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_unlock(&xt[af].compat_mutex); 7442722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin} 7452722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock); 7462722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 748942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerDEFINE_PER_CPU(struct xt_info_lock, xt_info_locks); 749942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerEXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks); 750942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 751f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardtstatic int xt_jumpstack_alloc(struct xt_table_info *i) 752f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt{ 753f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt unsigned int size; 754f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt int cpu; 755f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 756f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt size = sizeof(unsigned int) * nr_cpu_ids; 757f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (size > PAGE_SIZE) 758f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->stackptr = vmalloc(size); 759f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt else 760f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->stackptr = kmalloc(size, GFP_KERNEL); 761f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (i->stackptr == NULL) 762f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt return -ENOMEM; 763f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt memset(i->stackptr, 0, size); 764f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 765f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt size = sizeof(void **) * nr_cpu_ids; 766f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (size > PAGE_SIZE) 767f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->jumpstack = vmalloc(size); 768f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt else 769f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->jumpstack = kmalloc(size, GFP_KERNEL); 770f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (i->jumpstack == NULL) 771f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt return -ENOMEM; 772f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt memset(i->jumpstack, 0, size); 773f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 774f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->stacksize *= xt_jumpstack_multiplier; 775f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt size = sizeof(void *) * i->stacksize; 776f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt for_each_possible_cpu(cpu) { 777f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (size > PAGE_SIZE) 778f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->jumpstack[cpu] = vmalloc_node(size, 779f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt cpu_to_node(cpu)); 780f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt else 781f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt i->jumpstack[cpu] = kmalloc_node(size, 782f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt GFP_KERNEL, cpu_to_node(cpu)); 783f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (i->jumpstack[cpu] == NULL) 784f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt /* 785f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt * Freeing will be done later on by the callers. The 786f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt * chain is: xt_replace_table -> __do_replace -> 787f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt * do_replace -> xt_free_table_info. 788f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt */ 789f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt return -ENOMEM; 790f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt } 791f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 792f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt return 0; 793f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt} 794942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info * 7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table, 7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unsigned int num_counters, 7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *newinfo, 7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int *error) 8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 801942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger struct xt_table_info *private; 802f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt int ret; 8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 804d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt ret = xt_jumpstack_alloc(newinfo); 805d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt if (ret < 0) { 806d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt *error = ret; 807d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt return NULL; 808d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt } 809d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt 8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Do the substitution. */ 811942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_disable(); 8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 813942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 8142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Check inside lock: is the old number correct? */ 8152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (num_counters != private->number) { 816be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt pr_debug("num_counters != table->private->number (%u/%u)\n", 8172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte num_counters, private->number); 818942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_enable(); 8192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *error = -EAGAIN; 8202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return NULL; 8212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 823942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger table->private = newinfo; 824942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger newinfo->initial_entries = private->initial_entries; 825942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 826942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger /* 827942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * Even though table entries have now been swapped, other CPU's 828942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * may still be using the old entries. This is okay, because 829942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * resynchronization happens because of the locking done 830942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger * during the get_counters() routine. 831942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger */ 832942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger local_bh_enable(); 833942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 834942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger return private; 8352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table); 8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 83835aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net, 83935aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt const struct xt_table *input_table, 840a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan struct xt_table_info *bootstrap, 841a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan struct xt_table_info *newinfo) 8422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 8432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int ret; 8442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *private; 84535aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt struct xt_table *t, *table; 8462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 847f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt ret = xt_jumpstack_alloc(newinfo); 848f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt if (ret < 0) 849f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt return ERR_PTR(ret); 850f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt 85144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan /* Don't add one object to multiple lists. */ 85235aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); 85344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan if (!table) { 85444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan ret = -ENOMEM; 85544d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan goto out; 85644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan } 85744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan 8589e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar ret = mutex_lock_interruptible(&xt[table->af].mutex); 8592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (ret != 0) 86044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan goto out_free; 8612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Don't autoload: we'd eat our tail... */ 8638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_for_each_entry(t, &net->xt.tables[table->af], list) { 864df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy if (strcmp(t->name, table->name) == 0) { 865df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy ret = -EEXIST; 866df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy goto unlock; 867df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy } 8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 8692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* Simplifies replace_table code. */ 8712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte table->private = bootstrap; 872784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger 8732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!xt_replace_table(table, 0, newinfo, &ret)) 8742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto unlock; 8752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 877be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt pr_debug("table->private->number = %u\n", private->number); 8782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte /* save number of initial entries */ 8802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private->initial_entries = private->number; 8812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8828d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan list_add(&table->list, &net->xt.tables[table->af]); 883a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan mutex_unlock(&xt[table->af].mutex); 884a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan return table; 8852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock: 8879e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 88844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free: 88944d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan kfree(table); 890a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout: 891a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan return ERR_PTR(ret); 8922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 8932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table); 8942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table) 8962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 8972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct xt_table_info *private; 8982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 8999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_lock(&xt[table->af].mutex); 9002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte private = table->private; 901df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy list_del(&table->list); 9029e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_unlock(&xt[table->af].mutex); 90344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan kfree(table); 9042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 9052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return private; 9062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table); 9082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 9092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 910715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv { 911715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct seq_net_private p; 91276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af; 913715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan}; 914025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) 9152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 916715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 9171218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 91876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 9192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 920025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan mutex_lock(&xt[af].mutex); 921715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan return seq_list_start(&net->xt.tables[af], *pos); 922025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 9232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 924025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos) 925025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 926715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 9271218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki struct net *net = seq_file_net(seq); 92876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 9292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 930715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan return seq_list_next(v, &net->xt.tables[af], pos); 9312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 933025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v) 9342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 935715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv = seq->private; 93676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt u_int8_t af = priv->af; 9372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 938025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan mutex_unlock(&xt[af].mutex); 939025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 9402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 941025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v) 942025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 943025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan struct xt_table *table = list_entry(v, struct xt_table, list); 9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 945025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan if (strlen(table->name)) 946025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return seq_printf(seq, "%s\n", table->name); 947025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan else 948025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return 0; 949025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 950601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki 951025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = { 952025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_table_seq_start, 953025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_table_seq_next, 954025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .stop = xt_table_seq_stop, 955025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_table_seq_show, 956025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 957025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 958025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file) 959025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 960025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan int ret; 961715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan struct xt_names_priv *priv; 962025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 963715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan ret = seq_open_net(inode, file, &xt_table_seq_ops, 964715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan sizeof(struct xt_names_priv)); 965025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan if (!ret) { 966715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan priv = ((struct seq_file *)file->private_data)->private; 967715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan priv->af = (unsigned long)PDE(inode)->data; 968025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan } 969025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan return ret; 9702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 9712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 972025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = { 973025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .owner = THIS_MODULE, 974025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_table_open, 975025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .read = seq_read, 976025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .llseek = seq_lseek, 9770e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov .release = seq_release_net, 978025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 979025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 980eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/* 981eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing 982eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes. 983eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */ 984eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav { 985eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct list_head *head, *curr; 986eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt uint8_t class, nfproto; 987eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}; 988eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 989eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum { 990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_INIT, 991eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_NFP_UNSPEC, 992eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_NFP_SPEC, 993eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt MTTG_TRAV_DONE, 994eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}; 995eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos, 997eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt bool is_target) 9982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 999eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt static const uint8_t next_class[] = { 1000eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt [MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC, 1001eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt [MTTG_TRAV_NFP_SPEC] = MTTG_TRAV_DONE, 1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt }; 1003eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 1004eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1005eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_INIT: 1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = MTTG_TRAV_NFP_UNSPEC; 1008eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_lock(&xt[NFPROTO_UNSPEC].mutex); 1009eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->head = trav->curr = is_target ? 1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt &xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match; 1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->curr = trav->curr->next; 1014eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr != trav->head) 1015eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 1016eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); 1017eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_lock(&xt[trav->nfproto].mutex); 1018eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->head = trav->curr = is_target ? 1019eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt &xt[trav->nfproto].target : &xt[trav->nfproto].match; 1020eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = next_class[trav->class]; 1021eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 1022eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 1023eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->curr = trav->curr->next; 1024eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr != trav->head) 1025eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 1026eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt /* fallthru, _stop will unlock */ 1027eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt default: 1028eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return NULL; 1029eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 10302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1031eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ppos != NULL) 1032eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ++*ppos; 1033eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return trav; 1034025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1035601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki 1036eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos, 1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt bool is_target) 1038025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1039eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 1040eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt unsigned int j; 10412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->class = MTTG_TRAV_INIT; 1043eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt for (j = 0; j < *pos; ++j) 1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL) 1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return NULL; 1046eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return trav; 10472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 10482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1049eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v) 10502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1051eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav = seq->private; 1052eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1053eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 1055eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); 1056eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 1057eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 1058eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt mutex_unlock(&xt[trav->nfproto].mutex); 1059eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt break; 1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 1061eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt} 10622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1063eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) 1064eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{ 1065eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_start(seq, pos, false); 10662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 10672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1068eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos) 10692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_next(seq, v, ppos, false); 1071eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt} 10722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1073eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v) 1074eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{ 1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct nf_mttg_trav *trav = seq->private; 1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct xt_match *match; 1077eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1078eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 1079eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 1080eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 1081eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr == trav->head) 1082eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1083eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt match = list_entry(trav->curr, struct xt_match, list); 1084eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return (*match->name == '\0') ? 0 : 1085eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq_printf(seq, "%s\n", match->name); 1086eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 1087eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 10882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 10892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1090025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = { 1091025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_match_seq_start, 1092025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_match_seq_next, 1093eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .stop = xt_mttg_seq_stop, 1094025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_match_seq_show, 10952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 10962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1097025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file) 10982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1099eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct seq_file *seq; 1100eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav; 11012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte int ret; 11022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1103eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav = kmalloc(sizeof(*trav), GFP_KERNEL); 1104eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav == NULL) 1105eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return -ENOMEM; 11062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1107eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ret = seq_open(file, &xt_match_seq_ops); 1108eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ret < 0) { 1109eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt kfree(trav); 1110eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return ret; 11112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 1112eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1113eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq = file->private_data; 1114eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq->private = trav; 1115eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->nfproto = (unsigned long)PDE(inode)->data; 1116eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1117025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1118025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1119025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = { 1120025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .owner = THIS_MODULE, 1121025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_match_open, 1122025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .read = seq_read, 1123025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .llseek = seq_lseek, 1124eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .release = seq_release_private, 1125025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 11262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1127025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos) 1128025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1129eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_start(seq, pos, true); 1130025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1131025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1132eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos) 1133025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1134eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return xt_mttg_seq_next(seq, v, ppos, true); 1135025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1136025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1137025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v) 1138025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1139eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct nf_mttg_trav *trav = seq->private; 1140eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt const struct xt_target *target; 1141eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1142eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt switch (trav->class) { 1143eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_UNSPEC: 1144eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt case MTTG_TRAV_NFP_SPEC: 1145eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav->curr == trav->head) 1146eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1147eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt target = list_entry(trav->curr, struct xt_target, list); 1148eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return (*target->name == '\0') ? 0 : 1149eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq_printf(seq, "%s\n", target->name); 1150eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt } 1151eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 1152025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan} 1153025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1154025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = { 1155025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .start = xt_target_seq_start, 1156025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .next = xt_target_seq_next, 1157eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .stop = xt_mttg_seq_stop, 1158025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .show = xt_target_seq_show, 1159025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}; 1160025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1161025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file) 1162025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{ 1163eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct seq_file *seq; 1164eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt struct nf_mttg_trav *trav; 1165025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan int ret; 1166025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1167eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav = kmalloc(sizeof(*trav), GFP_KERNEL); 1168eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (trav == NULL) 1169eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return -ENOMEM; 1170025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan 1171eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt ret = seq_open(file, &xt_target_seq_ops); 1172eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt if (ret < 0) { 1173eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt kfree(trav); 1174eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return ret; 1175025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan } 1176eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 1177eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq = file->private_data; 1178eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt seq->private = trav; 1179eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt trav->nfproto = (unsigned long)PDE(inode)->data; 1180eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt return 0; 11812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 11822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1183025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = { 11842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .owner = THIS_MODULE, 1185025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan .open = xt_target_open, 11862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .read = seq_read, 11872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte .llseek = seq_lseek, 1188eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt .release = seq_release_private, 11892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}; 11902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES "_tables_names" 11922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_MATCHES "_tables_matches" 11932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS "_tables_targets" 11942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */ 11962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 11972b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/** 11982b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table 11992b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table: table with metadata needed to set up hooks 12002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn: Hook function 12012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * 12022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary 12032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables. 12042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */ 12052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn) 12062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{ 12072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt unsigned int hook_mask = table->valid_hooks; 12082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt uint8_t i, num_hooks = hweight32(hook_mask); 12092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt uint8_t hooknum; 12102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt struct nf_hook_ops *ops; 12112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt int ret; 12122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 12132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); 12142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (ops == NULL) 12152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ERR_PTR(-ENOMEM); 12162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 12172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0; 12182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt hook_mask >>= 1, ++hooknum) { 12192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (!(hook_mask & 1)) 12202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt continue; 12212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].hook = fn; 12222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].owner = table->me; 12232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].pf = table->af; 12242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].hooknum = hooknum; 12252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ops[i].priority = table->priority; 12262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ++i; 12272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt } 12282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 12292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt ret = nf_register_hooks(ops, num_hooks); 12302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt if (ret < 0) { 12312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt kfree(ops); 12322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ERR_PTR(ret); 12332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt } 12342b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 12352b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt return ops; 12362b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt} 12372b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link); 12382b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 12392b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/** 12402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table 12412b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops: nf_hook_ops array as returned by nf_hook_link 12422b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask: the very same mask that was passed to nf_hook_link 12432b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */ 12442b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops) 12452b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{ 12462b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt nf_unregister_hooks(ops, hweight32(table->valid_hooks)); 12472b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt kfree(ops); 12482b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt} 12492b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink); 12502b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt 125176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af) 12522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 12532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 12542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte char buf[XT_FUNCTION_MAXNAMELEN]; 12552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte struct proc_dir_entry *proc; 12562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 12572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12587e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt if (af >= ARRAY_SIZE(xt_prefix)) 12592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -EINVAL; 12602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 1263ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 12658b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops, 12668b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out; 12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1270ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 12728b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops, 12738b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 12742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 12752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out_remove_tables; 12762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1277ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TARGETS, sizeof(buf)); 12798b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops, 12808b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev (void *)(unsigned long)af); 12812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!proc) 12822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte goto out_remove_matches; 12832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 12842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return 0; 12862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 12882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches: 1289ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 12913cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 12932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables: 1294ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 12952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 12963cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 12972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout: 12982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -1; 12992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif 13002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 13012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init); 13022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 130376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af) 13042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 13052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS 13062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte char buf[XT_FUNCTION_MAXNAMELEN]; 13072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1308ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 13092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TABLES, sizeof(buf)); 13103cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 13112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1312ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 13132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_TARGETS, sizeof(buf)); 13143cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 13152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1316ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser strlcpy(buf, xt_prefix[af], sizeof(buf)); 13172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte strlcat(buf, FORMAT_MATCHES, sizeof(buf)); 13183cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan proc_net_remove(net, buf); 13192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/ 13202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 13212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini); 13222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 13238d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net) 13248d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{ 13258d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan int i; 13268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan 13277e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt for (i = 0; i < NFPROTO_NUMPROTO; i++) 13288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan INIT_LIST_HEAD(&net->xt.tables[i]); 13298d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan return 0; 13308d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan} 13318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan 13328d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = { 13338d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan .init = xt_net_init, 13348d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}; 13352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 13362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void) 13372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 1338942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger unsigned int i; 1339942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger int rv; 1340942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger 1341942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger for_each_possible_cpu(i) { 1342942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger struct xt_info_lock *lock = &per_cpu(xt_info_locks, i); 1343942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger spin_lock_init(&lock->lock); 1344942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger lock->readers = 0; 1345942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger } 13462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 13477e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL); 13482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte if (!xt) 13492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte return -ENOMEM; 13502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 13517e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt for (i = 0; i < NFPROTO_NUMPROTO; i++) { 13529e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar mutex_init(&xt[i].mutex); 13532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT 13542722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin mutex_init(&xt[i].compat_mutex); 1355b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy xt[i].compat_offsets = NULL; 13562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif 13572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte INIT_LIST_HEAD(&xt[i].target); 13582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte INIT_LIST_HEAD(&xt[i].match); 13592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte } 13608d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan rv = register_pernet_subsys(&xt_net_ops); 13618d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan if (rv < 0) 13628d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan kfree(xt); 13638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan return rv; 13642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 13652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 13662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void) 13672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{ 13688d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan unregister_pernet_subsys(&xt_net_ops); 13692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte kfree(xt); 13702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte} 13712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 13722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init); 13732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini); 13742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte 1375