Skip to content

Commit

Permalink
[IPV6] MIP6: Add receiving mobility header functions through raw socket.
Browse files Browse the repository at this point in the history
Like ICMPv6, mobility header is handled through raw socket.
In inbound case, check only whether ICMPv6 error should be sent as a reply
or not by kernel.
Based on MIPL2 kernel patch.

This patch was also written by: Ville Nuorvala <vnuorval@tcs.hut.fi>
This patch was also written by: Antti Tuominen <anttit@tcs.hut.fi>

Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Masahide NAKAMURA authored and David S. Miller committed Sep 22, 2006
1 parent 2b74165 commit 7be96f7
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
4 changes: 4 additions & 0 deletions include/net/mip6.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#ifndef _NET_MIP6_H
#define _NET_MIP6_H

#include <linux/skbuff.h>
#include <net/sock.h>

#define MIP6_OPT_PAD_1 0
#define MIP6_OPT_PAD_N 1

Expand Down Expand Up @@ -53,5 +56,6 @@ struct ip6_mh {

extern int mip6_init(void);
extern void mip6_fini(void);
extern int mip6_mh_filter(struct sock *sk, struct sk_buff *skb);

#endif
83 changes: 83 additions & 0 deletions net/ipv6/mip6.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <net/sock.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
#include <net/xfrm.h>
#include <net/mip6.h>

Expand Down Expand Up @@ -55,6 +58,86 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen)
return data + padlen;
}

static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos)
{
icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
}

static int mip6_mh_len(int type)
{
int len = 0;

switch (type) {
case IP6_MH_TYPE_BRR:
len = 0;
break;
case IP6_MH_TYPE_HOTI:
case IP6_MH_TYPE_COTI:
case IP6_MH_TYPE_BU:
case IP6_MH_TYPE_BACK:
len = 1;
break;
case IP6_MH_TYPE_HOT:
case IP6_MH_TYPE_COT:
case IP6_MH_TYPE_BERROR:
len = 2;
break;
}
return len;
}

int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
{
struct ip6_mh *mh;
int mhlen;

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)))
return -1;

mh = (struct ip6_mh *)skb->h.raw;

if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n",
mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type));
mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw);
return -1;
}
mhlen = (mh->ip6mh_hdrlen + 1) << 3;

if (skb->ip_summed == CHECKSUM_COMPLETE) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
&skb->nh.ipv6h->daddr,
mhlen, IPPROTO_MH,
skb->csum)) {
LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n");
skb->ip_summed = CHECKSUM_NONE;
}
}
if (skb->ip_summed == CHECKSUM_NONE) {
if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
&skb->nh.ipv6h->daddr,
mhlen, IPPROTO_MH,
skb_checksum(skb, 0, mhlen, 0))) {
LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
NIP6(skb->nh.ipv6h->saddr),
NIP6(skb->nh.ipv6h->daddr));
return -1;
}
skb->ip_summed = CHECKSUM_UNNECESSARY;
}

if (mh->ip6mh_proto != IPPROTO_NONE) {
LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
mh->ip6mh_proto);
mip6_param_prob(skb, 0, (&mh->ip6mh_proto) - skb->nh.raw);
return -1;
}

return 0;
}

static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct ipv6hdr *iph = skb->nh.ipv6h;
Expand Down
29 changes: 28 additions & 1 deletion net/ipv6/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
#include <net/udp.h>
#include <net/inet_common.h>
#include <net/tcp_states.h>
#ifdef CONFIG_IPV6_MIP6
#include <net/mip6.h>
#endif

#include <net/rawv6.h>
#include <net/xfrm.h>
Expand Down Expand Up @@ -169,8 +172,32 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);

while (sk) {
int filtered;

delivered = 1;
if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
switch (nexthdr) {
case IPPROTO_ICMPV6:
filtered = icmpv6_filter(sk, skb);
break;
#ifdef CONFIG_IPV6_MIP6
case IPPROTO_MH:
/* XXX: To validate MH only once for each packet,
* this is placed here. It should be after checking
* xfrm policy, however it doesn't. The checking xfrm
* policy is placed in rawv6_rcv() because it is
* required for each socket.
*/
filtered = mip6_mh_filter(sk, skb);
break;
#endif
default:
filtered = 0;
break;
}

if (filtered < 0)
break;
if (filtered == 0) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);

/* Not releasing hash table! */
Expand Down

0 comments on commit 7be96f7

Please sign in to comment.