Commit 83a0e2be authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/network-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 99447171 d786675f
......@@ -152,10 +152,7 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
void crypto_free_tfm(struct crypto_tfm *tfm)
{
if (crypto_tfm_alg_type(tfm) == CRYPTO_ALG_TYPE_CIPHER)
if (tfm->crt_cipher.cit_iv)
kfree(tfm->crt_cipher.cit_iv);
crypto_exit_ops(tfm);
crypto_alg_put(tfm->__crt_alg);
kfree(tfm);
}
......
......@@ -175,7 +175,7 @@ extern void addrconf_forwarding_on(void);
* Hash function taken from net_alias.c
*/
static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr)
static __inline__ u8 ipv6_addr_hash(const struct in6_addr *addr)
{
__u32 word;
......@@ -195,7 +195,7 @@ static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr)
* compute link-local solicited-node multicast address
*/
static inline void addrconf_addr_solict_mult(struct in6_addr *addr,
static inline void addrconf_addr_solict_mult(const struct in6_addr *addr,
struct in6_addr *solicited)
{
ipv6_addr_set(solicited,
......@@ -219,7 +219,7 @@ static inline void ipv6_addr_all_routers(struct in6_addr *addr)
__constant_htonl(0x2));
}
static inline int ipv6_addr_is_multicast(struct in6_addr *addr)
static inline int ipv6_addr_is_multicast(const struct in6_addr *addr)
{
return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000);
}
......
......@@ -203,12 +203,8 @@ extern int ip6_ra_control(struct sock *sk, int sel,
extern int ip6_call_ra_chain(struct sk_buff *skb, int sel);
extern int ipv6_reassembly(struct sk_buff **skb, int);
extern int ipv6_parse_hopopts(struct sk_buff *skb, int);
extern int ipv6_parse_exthdrs(struct sk_buff **skb, int);
extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
extern int ip6_frag_nqueues;
......@@ -226,21 +222,21 @@ typedef int (*inet_getfrag_t) (const void *data,
unsigned int, unsigned int);
extern int ipv6_addr_type(struct in6_addr *addr);
extern int ipv6_addr_type(const struct in6_addr *addr);
static inline int ipv6_addr_scope(struct in6_addr *addr)
static inline int ipv6_addr_scope(const struct in6_addr *addr)
{
return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
}
static inline int ipv6_addr_cmp(struct in6_addr *a1, struct in6_addr *a2)
static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
{
return memcmp((void *) a1, (void *) a2, sizeof(struct in6_addr));
return memcmp((const void *) a1, (const void *) a2, sizeof(struct in6_addr));
}
static inline void ipv6_addr_copy(struct in6_addr *a1, struct in6_addr *a2)
static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
{
memcpy((void *) a1, (void *) a2, sizeof(struct in6_addr));
memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr));
}
#ifndef __HAVE_ARCH_ADDR_SET
......@@ -255,7 +251,7 @@ static inline void ipv6_addr_set(struct in6_addr *addr,
}
#endif
static inline int ipv6_addr_any(struct in6_addr *a)
static inline int ipv6_addr_any(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1] |
a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
......
......@@ -44,7 +44,7 @@ struct inet_protocol
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct inet6_protocol
{
int (*handler)(struct sk_buff *skb);
int (*handler)(struct sk_buff **skbp);
void (*err_handler)(struct sk_buff *skb,
struct inet6_skb_parm *opt,
......
......@@ -15,6 +15,14 @@ extern struct proto tcpv6_prot;
struct flowi;
/* extention headers */
extern void ipv6_hopopts_init(void);
extern void ipv6_rthdr_init(void);
extern void ipv6_frag_init(void);
extern void ipv6_nodata_init(void);
extern void ipv6_destopt_init(void);
/* transport protocols */
extern void rawv6_init(void);
extern void udpv6_init(void);
extern void tcpv6_init(void);
......
......@@ -730,7 +730,7 @@ extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm6_rcv(struct sk_buff *skb);
extern int xfrm6_rcv(struct sk_buff **pskb);
extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir);
extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
......
......@@ -97,6 +97,8 @@ static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad
static void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
static struct crypto_tfm *md5_tfm;
static spinlock_t md5_tfm_lock = SPIN_LOCK_UNLOCKED;
#endif
static int ipv6_count_addresses(struct inet6_dev *idev);
......@@ -172,7 +174,7 @@ static struct ipv6_devconf ipv6_devconf_dflt =
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
int ipv6_addr_type(struct in6_addr *addr)
int ipv6_addr_type(const struct in6_addr *addr)
{
int type;
u32 st;
......@@ -426,8 +428,7 @@ static void dev_forward_change(struct inet6_dev *idev)
}
for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
ipv6_addr_prefix(&addr, &ifa->addr, ifa->prefix_len);
if (addr.s6_addr32[0] == 0 && addr.s6_addr32[1] == 0 &&
addr.s6_addr32[2] == 0 && addr.s6_addr32[3] == 0)
if (ipv6_addr_any(&addr))
continue;
if (idev->cnf.forwarding)
ipv6_dev_ac_inc(idev->dev, &addr);
......@@ -486,7 +487,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
/* On success it returns ifp with increased reference count */
static struct inet6_ifaddr *
ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
int scope, unsigned flags)
{
struct inet6_ifaddr *ifa;
......@@ -1046,7 +1047,6 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
struct net_device *dev;
u8 eui64[8];
u8 digest[16];
struct crypto_tfm *tfm;
struct scatterlist sg[2];
sg[0].page = virt_to_page(idev->entropy);
......@@ -1068,18 +1068,16 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
get_random_bytes(eui64, sizeof(eui64));
}
regen:
tfm = crypto_alloc_tfm("md5", 0);
if (tfm == NULL) {
if (net_ratelimit())
printk(KERN_WARNING
"failed to load transform for md5\n");
spin_lock(&md5_tfm_lock);
if (unlikely(md5_tfm == NULL)) {
spin_unlock(&md5_tfm_lock);
in6_dev_put(idev);
return -1;
}
crypto_digest_init(tfm);
crypto_digest_update(tfm, sg, 2);
crypto_digest_final(tfm, digest);
crypto_free_tfm(tfm);
crypto_digest_init(md5_tfm);
crypto_digest_update(md5_tfm, sg, 2);
crypto_digest_final(md5_tfm, digest);
spin_unlock(&md5_tfm_lock);
memcpy(idev->rndid, &digest[0], 8);
idev->rndid[0] &= ~0x02;
......@@ -1107,6 +1105,9 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
goto regen;
}
idev->regen_timer.expires = jiffies +
idev->cnf.temp_prefered_lft * HZ -
idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
if (time_before(idev->regen_timer.expires, jiffies)) {
idev->regen_timer.expires = 0;
printk(KERN_WARNING
......@@ -1646,7 +1647,6 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
static void init_loopback(struct net_device *dev)
{
struct in6_addr addr;
struct inet6_dev *idev;
struct inet6_ifaddr * ifp;
......@@ -1654,15 +1654,12 @@ static void init_loopback(struct net_device *dev)
ASSERT_RTNL();
memset(&addr, 0, sizeof(struct in6_addr));
addr.s6_addr[15] = 1;
if ((idev = ipv6_find_idev(dev)) == NULL) {
printk(KERN_DEBUG "init loopback: add_dev failed\n");
return;
}
ifp = ipv6_add_addr(idev, &addr, 128, IFA_HOST, IFA_F_PERMANENT);
ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT);
if (ifp) {
spin_lock_bh(&ifp->lock);
ifp->flags &= ~IFA_F_TENTATIVE;
......@@ -2034,8 +2031,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (addr.s6_addr32[0] || addr.s6_addr32[1] ||
addr.s6_addr32[2] || addr.s6_addr32[3])
if (!ipv6_addr_any(&addr))
ipv6_dev_ac_inc(ifp->idev->dev, &addr);
}
}
......@@ -2372,8 +2368,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (addr.s6_addr32[0] || addr.s6_addr32[1] ||
addr.s6_addr32[2] || addr.s6_addr32[3])
if (!ipv6_addr_any(&addr))
ipv6_dev_ac_dec(ifp->idev->dev, &addr);
}
if (!ipv6_chk_addr(&ifp->addr, NULL))
......@@ -2654,7 +2649,16 @@ void __init addrconf_init(void)
{
#ifdef MODULE
struct net_device *dev;
#endif
#ifdef CONFIG_IPV6_PRIVACY
md5_tfm = crypto_alloc_tfm("md5", 0);
if (unlikely(md5_tfm == NULL))
printk(KERN_WARNING
"failed to load transform for md5\n");
#endif
#ifdef MODULE
/* This takes sense only during module load. */
rtnl_lock();
for (dev = dev_base; dev; dev = dev->next) {
......@@ -2739,6 +2743,13 @@ void addrconf_cleanup(void)
rtnl_unlock();
#ifdef CONFIG_IPV6_PRIVACY
if (likely(md5_tfm != NULL)) {
crypto_free_tfm(md5_tfm);
md5_tfm = NULL;
}
#endif
#ifdef CONFIG_PROC_FS
proc_net_remove("if_inet6");
#endif
......
......@@ -799,6 +799,13 @@ static int __init inet6_init(void)
addrconf_init();
sit_init();
/* Init v6 extention headers. */
ipv6_hopopts_init();
ipv6_rthdr_init();
ipv6_frag_init();
ipv6_nodata_init();
ipv6_destopt_init();
/* Init v6 transport protocols. */
udpv6_init();
tcpv6_init();
......
......@@ -18,6 +18,9 @@
/* Changes:
* yoshfuji : ensure not to overrun while parsing
* tlv options.
* Mitsuru KANDA @USAGI : Remove ipv6_parse_exthdrs().
* : Register inbound extention header
* : handlers as inet6_protocol{}.
*/
#include <linux/errno.h>
......@@ -43,20 +46,6 @@
#include <asm/uaccess.h>
/*
* Parsing inbound headers.
*
* Parsing function "func" returns offset wrt skb->nh of the place,
* where next nexthdr value is stored or NULL, if parsing
* failed. It should also update skb->h tp point at the next header.
*/
struct hdrtype_proc
{
int type;
int (*func) (struct sk_buff **, int offset);
};
/*
* Parsing tlv encoded headers.
*
......@@ -164,49 +153,77 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
{-1, NULL}
};
static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff)
static int ipv6_destopt_rcv(struct sk_buff **skbp)
{
struct sk_buff *skb=*skb_ptr;
struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
u8 nexthdr = 0;
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
kfree_skb(skb);
return -1;
return 0;
}
nexthdr = ((struct ipv6_destopt_hdr *)skb->h.raw)->nexthdr;
opt->dst1 = skb->h.raw - skb->nh.raw;
if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
skb->h.raw += ((skb->h.raw[1]+1)<<3);
return opt->dst1;
return -nexthdr;
}
return 0;
}
return -1;
static struct inet6_protocol destopt_protocol =
{
.handler = ipv6_destopt_rcv,
};
void __init ipv6_destopt_init(void)
{
if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
}
/********************************
NONE header. No data in packet.
********************************/
static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff)
static int ipv6_nodata_rcv(struct sk_buff **skbp)
{
kfree_skb(*skb_ptr);
return -1;
struct sk_buff *skb = *skbp;
kfree_skb(skb);
return 0;
}
static struct inet6_protocol nodata_protocol =
{
.handler = ipv6_nodata_rcv,
};
void __init ipv6_nodata_init(void)
{
if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
}
/********************************
Routing header.
********************************/
static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
static int ipv6_rthdr_rcv(struct sk_buff **skbp)
{
struct sk_buff *skb = *skb_ptr;
struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
struct in6_addr *addr;
struct in6_addr daddr;
int addr_type;
int n, i;
u8 nexthdr = 0;
struct ipv6_rt_hdr *hdr;
struct rt0_hdr *rthdr;
......@@ -215,15 +232,16 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
IP6_INC_STATS_BH(Ip6InHdrErrors);
kfree_skb(skb);
return -1;
return 0;
}
hdr = (struct ipv6_rt_hdr *) skb->h.raw;
nexthdr = hdr->nexthdr;
if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||
skb->pkt_type != PACKET_HOST) {
kfree_skb(skb);
return -1;
return 0;
}
looped_back:
......@@ -232,24 +250,24 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
skb->h.raw += (hdr->hdrlen + 1) << 3;
opt->dst0 = opt->dst1;
opt->dst1 = 0;
return (&hdr->nexthdr) - skb->nh.raw;
return -nexthdr;
}
if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
return -1;
return 0;
}
/*
* This is the routing header forwarding algorithm from
* RFC 1883, page 17.
* RFC 2460, page 16.
*/
n = hdr->hdrlen >> 1;
if (hdr->segments_left > n) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
return -1;
return 0;
}
/* We are about to mangle packet header. Be careful!
......@@ -259,8 +277,8 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
kfree_skb(skb);
if (skb2 == NULL)
return -1;
*skb_ptr = skb = skb2;
return 0;
*skbp = skb = skb2;
opt = (struct inet6_skb_parm *)skb2->cb;
hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
}
......@@ -278,7 +296,7 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
if (addr_type&IPV6_ADDR_MULTICAST) {
kfree_skb(skb);
return -1;
return 0;
}
ipv6_addr_copy(&daddr, addr);
......@@ -289,23 +307,34 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
ip6_route_input(skb);
if (skb->dst->error) {
dst_input(skb);
return -1;
return 0;
}
if (skb->dst->dev->flags&IFF_LOOPBACK) {
if (skb->nh.ipv6h->hop_limit <= 1) {
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
0, skb->dev);
kfree_skb(skb);
return -1;
return 0;
}
skb->nh.ipv6h->hop_limit--;
goto looped_back;
}
dst_input(skb);
return -1;
return 0;
}
static struct inet6_protocol rthdr_protocol =
{
.handler = ipv6_rthdr_rcv,
};
void __init ipv6_rthdr_init(void)
{
if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
};
/*
This function inverts received rthdr.
NOTE: specs allow to make it automatically only if
......@@ -371,97 +400,6 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
return opt;
}
/********************************
AUTH header.
********************************/
/*
rfc1826 said, that if a host does not implement AUTH header
it MAY ignore it. We use this hole 8)
Actually, now we can implement OSPFv6 without kernel IPsec.
Authentication for poors may be done in user space with the same success.
Yes, it means, that we allow application to send/receive
raw authentication header. Apparently, we suppose, that it knows
what it does and calculates authentication data correctly.
Certainly, it is possible only for udp and raw sockets, but not for tcp.
AUTH header has 4byte granular length, which kills all the idea
behind AUTOMATIC 64bit alignment of IPv6. Now we will lose
cpu ticks, checking that sender did not something stupid
and opt->hdrlen is even. Shit! --ANK (980730)
*/
static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff)
{
struct sk_buff *skb=*skb_ptr;
struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
int len;
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
goto fail;
/*
* RFC2402 2.2 Payload Length
* The 8-bit field specifies the length of AH in 32-bit words
* (4-byte units), minus "2".
* -- Noriaki Takamiya @USAGI Project
*/
len = (skb->h.raw[1]+2)<<2;
if (len&7)
goto fail;
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len))
goto fail;
opt->auth = skb->h.raw - skb->nh.raw;
skb->h.raw += len;
return opt->auth;
fail:
kfree_skb(skb);
return -1;
}
/* This list MUST NOT contain entry for NEXTHDR_HOP.
It is parsed immediately after packet received
and if it occurs somewhere in another place we must
generate error.
*/
static struct hdrtype_proc hdrproc_lst[] = {
{NEXTHDR_FRAGMENT, ipv6_reassembly},
{NEXTHDR_ROUTING, ipv6_routing_header},
{NEXTHDR_DEST, ipv6_dest_opt},
{NEXTHDR_NONE, ipv6_nodata},
{NEXTHDR_AUTH, ipv6_auth_hdr},
/*
{NEXTHDR_ESP, ipv6_esp_hdr},
*/
{-1, NULL}
};
int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff)
{
struct hdrtype_proc *hdrt;
u8 nexthdr = (*skb_in)->nh.raw[nhoff];
restart:
for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
if (hdrt->type == nexthdr) {
if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) {
nexthdr = (*skb_in)->nh.raw[nhoff];
goto restart;
}
return -1;
}
}
return nhoff;
}
/**********************************
Hop-by-hop options.
**********************************/
......@@ -532,6 +470,34 @@ int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
return -1;
}
/* This is fake. We have already parsed hopopts in ipv6_rcv(). -mk */
static int ipv6_hopopts_rcv(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
u8 nexthdr = 0;
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
kfree_skb(skb);
return 0;
}
nexthdr = ((struct ipv6_hopopt_hdr *)skb->h.raw)->nexthdr;
skb->h.raw += (skb->h.raw[1]+1)<<3;
return -nexthdr;
}
static struct inet6_protocol hopopts_protocol =
{
.handler = ipv6_hopopts_rcv,
};
void __init ipv6_hopopts_init(void)
{
if (inet6_add_protocol(&hopopts_protocol, IPPROTO_HOPOPTS) < 0)
printk(KERN_ERR "ipv6_hopopts_init: Could not register protocol\n");
}
/*
* Creating outbound headers.
*
......
......@@ -74,7 +74,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
static struct socket *__icmpv6_socket[NR_CPUS];
#define icmpv6_socket __icmpv6_socket[smp_processor_id()]
static int icmpv6_rcv(struct sk_buff *skb);
static int icmpv6_rcv(struct sk_buff **pskb);
static struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv,
......@@ -459,8 +459,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
* Handle icmp messages
*/
static int icmpv6_rcv(struct sk_buff *skb)
static int icmpv6_rcv(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct net_device *dev = skb->dev;
struct in6_addr *saddr, *daddr;
struct ipv6hdr *orig_hdr;
......
......@@ -15,6 +15,10 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
/* Changes
*
* Mitsuru KANDA @USAGI : Remove ipv6_parse_exthdrs().
*/
#include <linux/errno.h>
#include <linux/types.h>
......@@ -126,39 +130,11 @@ static inline int ip6_input_finish(struct sk_buff *skb)
struct ipv6hdr *hdr = skb->nh.ipv6h;
struct inet6_protocol *ipprot;
struct sock *raw_sk;
int nhoff;
int nexthdr;
int nexthdr = hdr->nexthdr;
u8 hash;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
/*
* Parse extension headers
*/
nexthdr = hdr->nexthdr;
nhoff = offsetof(struct ipv6hdr, nexthdr);
/* Skip hop-by-hop options, they are already parsed. */
if (nexthdr == NEXTHDR_HOP) {
nhoff = sizeof(struct ipv6hdr);
nexthdr = skb->h.raw[0];
skb->h.raw += (skb->h.raw[1]+1)<<3;
}
/* This check is sort of optimization.
It would be stupid to detect for optional headers,
which are missing with probability of 200%
*/
if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP &&
nexthdr != NEXTHDR_AUTH && nexthdr != NEXTHDR_ESP) {
nhoff = ipv6_parse_exthdrs(&skb, nhoff);
if (nhoff < 0)
return 0;
nexthdr = skb->nh.raw[nhoff];
hdr = skb->nh.ipv6h;
}
if (!pskb_pull(skb, skb->h.raw - skb->data))
goto discard;
......@@ -173,7 +149,7 @@ static inline int ip6_input_finish(struct sk_buff *skb)
hash = nexthdr & (MAX_INET_PROTOS - 1);
if ((ipprot = inet6_protos[hash]) != NULL) {
int ret = ipprot->handler(skb);
int ret = ipprot->handler(&skb);
if (ret < 0) {
nexthdr = -ret;
goto resubmit;
......@@ -182,7 +158,8 @@ static inline int ip6_input_finish(struct sk_buff *skb)
} else {
if (!raw_sk) {
IP6_INC_STATS_BH(Ip6InUnknownProtos);
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR,
offsetof(struct ipv6hdr, nexthdr));
} else {
IP6_INC_STATS_BH(Ip6InDelivers);
kfree_skb(skb);
......
......@@ -23,6 +23,7 @@
* Horst von Brand Add missing #include <linux/string.h>
* Alexey Kuznetsov SMP races, threading, cleanup.
* Patrick McHardy LRU queue of frag heads for evictor.
* Mitsuru KANDA @USAGI Register inet6_protocol{}.
*/
#include <linux/config.h>
#include <linux/errno.h>
......@@ -525,6 +526,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
int remove_fraghdr = 0;
int payload_len;
int nhoff;
u8 nexthdr = 0;
fq_kill(fq);
......@@ -535,6 +537,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
nhoff = head->h.raw - head->nh.raw;
nexthdr = ((struct frag_hdr*)head->h.raw)->nexthdr;
if (payload_len > 65535) {
payload_len -= 8;
if (payload_len > 65535)
......@@ -609,9 +613,12 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
if (head->ip_summed == CHECKSUM_HW)
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
if (!pskb_pull(head, head->h.raw - head->data))
goto out_fail;
IP6_INC_STATS_BH(Ip6ReasmOKs);
fq->fragments = NULL;
return nhoff;
return nexthdr;
out_oversize:
if (net_ratelimit())
......@@ -622,16 +629,18 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
out_fail:
IP6_INC_STATS_BH(Ip6ReasmFails);
return -1;
return 0;
}
int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
static int ipv6_frag_rcv(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
struct net_device *dev = skb->dev;
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr;
int nhoff = skb->h.raw - skb->nh.raw;
u8 nexthdr = 0;
hdr = skb->nh.ipv6h;
......@@ -640,15 +649,16 @@ int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
/* Jumbo payload inhibits frag. header */
if (hdr->payload_len==0) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
goto discard;
}
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
goto discard;
}
hdr = skb->nh.ipv6h;
fhdr = (struct frag_hdr *)skb->h.raw;
nexthdr = fhdr->nexthdr;
if (!(fhdr->frag_off & htons(0xFFF9))) {
/* It is not a fragmented frame */
......@@ -674,10 +684,22 @@ int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
spin_unlock(&fq->lock);
fq_put(fq);
return ret;
return -ret;
}
discard:
IP6_INC_STATS_BH(Ip6ReasmFails);
kfree_skb(skb);
return -1;
return 0;
}
static struct inet6_protocol frag_protocol =
{
.handler = ipv6_frag_rcv,
};
void __init ipv6_frag_init(void)
{
if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0)
printk(KERN_ERR "ipv6_frag_init: Could not register protocol\n");
}
......@@ -1591,8 +1591,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
static int tcp_v6_rcv(struct sk_buff *skb)
static int tcp_v6_rcv(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct tcphdr *th;
struct sock *sk;
int ret;
......
......@@ -641,8 +641,9 @@ static void udpv6_mcast_deliver(struct udphdr *uh,
read_unlock(&udp_hash_lock);
}
static int udpv6_rcv(struct sk_buff *skb)
static int udpv6_rcv(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct sock *sk;
struct udphdr *uh;
struct net_device *dev = skb->dev;
......
......@@ -123,8 +123,9 @@ int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
return nexthdr;
}
int xfrm6_rcv(struct sk_buff *skb)
int xfrm6_rcv(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
int err;
u32 spi, seq;
struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
......@@ -137,12 +138,8 @@ int xfrm6_rcv(struct sk_buff *skb)
u16 nh_offset = 0;
u8 nexthdr = 0;
if (hdr->nexthdr == IPPROTO_AH || hdr->nexthdr == IPPROTO_ESP) {
nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
hdr_len = sizeof(struct ipv6hdr);
} else {
hdr_len = skb->h.raw - skb->nh.raw;
}
nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
hdr_len = sizeof(struct ipv6hdr);
tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
if (!tmp_hdr)
......@@ -189,20 +186,6 @@ int xfrm6_rcv(struct sk_buff *skb)
xfrm_vec[xfrm_nr++] = x;
iph = skb->nh.ipv6h; /* ??? */
if (nexthdr == NEXTHDR_DEST) {
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
err = -EINVAL;
goto drop;
}
nexthdr = skb->h.raw[0];
nh_offset = skb->h.raw - skb->nh.raw;
skb_pull(skb, (skb->h.raw[1]+1)<<3);
skb->h.raw = skb->data;
}
if (x->props.mode) { /* XXX */
if (iph->nexthdr != IPPROTO_IPV6)
goto drop;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment