/* GTP according to GSM TS 09.60 / 3GPP TS 29.060
*
* (C) 2012-2014 by sysmocom - s.f.m.c. GmbH
* (C) 2016 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* Author: Harald Welte <hwelte@sysmocom.de>
* Pablo Neira Ayuso <pablo@netfilter.org>
* Andreas Schultz <aschultz@travelping.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/rculist.h>
#include <linux/jhash.h>
#include <linux/if_tunnel.h>
#include <linux/net.h>
#include <linux/file.h>
#include <linux/gtp.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/udp_tunnel.h>
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/genetlink.h>
#include <net/netns/generic.h>
#include <net/gtp.h>
/* An active session for the subscriber. */
struct pdp_ctx {
struct hlist_node hlist_tid;
struct hlist_node hlist_addr;
union {
u64 tid;
struct {
u64 tid;
u16 flow;
} v0;
struct {
u32 i_tei;
u32 o_tei;
} v1;
} u;
u8 gtp_version;
u16 af;
struct in_addr ms_addr_ip4;
struct in_addr sgsn_addr_ip4;
atomic_t tx_seq;
struct rcu_head rcu_head;
};
/* One instance of the GTP device. */
struct gtp_dev {
struct list_head list;
struct socket *sock0;
struct socket *sock1u;
struct net *net;
struct net_device *dev;
unsigned int hash_size;
struct hlist_head *tid_hash;
struct hlist_head *addr_hash;
};
static int gtp_net_id __read_mostly;
struct gtp_net {
struct list_head gtp_dev_list;
};
static u32 gtp_h_initval;
static inline u32 gtp0_hashfn(u64 tid)
{
u32 *tid32 = (u32 *) &tid;
return jhash_2words(tid32[0], tid32[1], gtp_h_initval);
}
static inline u32 gtp1u_hashfn(u32 tid)
{
return jhash_1word(tid, gtp_h_initval);
}
static inline u32 ipv4_hashfn(__be32 ip)
{
return jhash_1word((__force u32)ip, gtp_h_initval);
}
/* Resolve a PDP context structure based on the 64bit TID. */
static struct pdp_ctx *gtp0_pdp_find(