Commit 01af8cb5 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents c7145bdd 4759dd67
......@@ -21,6 +21,7 @@
#include <linux/fs_struct.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <net/compat.h>
#include <asm/oplib.h>
#include <asm/delay.h>
......
......@@ -56,6 +56,7 @@
/* For SOCKET_I */
#include <linux/socket.h>
#include <net/sock.h>
#include <net/compat.h>
/* Use this to get at 32-bit user passed pointers. */
#define A(__x) \
......
......@@ -15,6 +15,7 @@
#include <linux/file.h>
#include <linux/net.h>
#include <linux/compat.h>
#include <net/compat.h>
#include <asm/uaccess.h>
#include <asm/string.h>
......
......@@ -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);
}
......
......@@ -43,11 +43,9 @@ extern int get_compat_timespec(struct timespec *, struct compat_timespec *);
extern int put_compat_timespec(struct timespec *, struct compat_timespec *);
struct compat_iovec {
u32 iov_base;
compat_uptr_t iov_base;
compat_size_t iov_len;
};
#else /* no CONFIG_COMPAT */
#define compat_size_t size_t
#endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */
......@@ -3,6 +3,7 @@
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
#include <linux/config.h> /* for CONFIG_COMPAT */
#include <linux/linkage.h>
#include <asm/socket.h> /* arch-dependent defines */
#include <linux/sockios.h> /* the SIOCxxx I/O controls */
......@@ -239,18 +240,10 @@ struct ucred {
#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
#else
#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
#define compat_msghdr msghdr /* Needed to avoid compiler hoops */
#endif
struct compat_msghdr;
extern int msghdr_from_user_compat_to_kern(struct msghdr *, struct compat_msghdr *);
extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int);
extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
char *optval, int *optlen);
......@@ -295,10 +288,6 @@ extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int le
extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
extern int put_cmsg_compat(struct msghdr*, int level, int type, int len, void *data);
extern void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr);
extern int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
unsigned char *stackbuf, int stackbuf_size);
#endif
#endif /* not kernel and not glibc */
......
......@@ -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);
}
......
#ifndef NET_COMPAT_H
#define NET_COMPAT_H
#include <linux/config.h>
#if defined(CONFIG_COMPAT)
#include <linux/compat.h>
struct compat_msghdr {
compat_uptr_t msg_name;
s32 msg_namelen;
compat_uptr_t msg_iov;
compat_size_t msg_iovlen;
compat_uptr_t msg_control;
compat_size_t msg_controllen;
u32 msg_flags;
};
struct compat_cmsghdr {
compat_size_t cmsg_len;
s32 cmsg_level;
s32 cmsg_type;
};
#else /* defined(CONFIG_COMPAT) */
#define compat_msghdr msghdr /* to avoid compiler warnings */
#endif /* defined(CONFIG_COMPAT) */
extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr *);
extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int);
extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long compat_sys_getsockopt(int, int, int, char *, int *);
extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
extern int put_compat_msg_controllen(struct msghdr *, struct compat_msghdr *,
unsigned long);
extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, unsigned char *,
int);
#endif /* NET_COMPAT_H */
#ifndef NET_COMPAT_SOCKET_H
#define NET_COMPAT_SOCKET_H 1
#include <linux/compat.h>
#if defined(CONFIG_COMPAT)
/* XXX This really belongs in some header file... -DaveM */
#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
16 for IP, 16 for IPX,
24 for IPv6,
about 80 for AX.25 */
struct compat_msghdr {
u32 msg_name;
int msg_namelen;
u32 msg_iov;
compat_size_t msg_iovlen;
u32 msg_control;
compat_size_t msg_controllen;
unsigned msg_flags;
};
struct compat_cmsghdr {
compat_size_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
/* Bleech... */
#define __CMSG_COMPAT_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg_compat_nxthdr((ctl),(len),(cmsg),(cmsglen))
#define CMSG_COMPAT_NXTHDR(mhdr, cmsg, cmsglen) cmsg_compat_nxthdr((mhdr), (cmsg), (cmsglen))
#define CMSG_COMPAT_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
#define CMSG_COMPAT_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))))
#define CMSG_COMPAT_SPACE(len) (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len))
#define CMSG_COMPAT_LEN(len) (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len))
#define __CMSG_COMPAT_FIRSTHDR(ctl,len) ((len) >= sizeof(struct compat_cmsghdr) ? \
(struct compat_cmsghdr *)(ctl) : \
(struct compat_cmsghdr *)NULL)
#define CMSG_COMPAT_FIRSTHDR(msg) __CMSG_COMPAT_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
static __inline__ struct compat_cmsghdr *__cmsg_compat_nxthdr(void *__ctl, __kernel_size_t __size,
struct compat_cmsghdr *__cmsg, int __cmsg_len)
{
struct compat_cmsghdr * __ptr;
__ptr = (struct compat_cmsghdr *)(((unsigned char *) __cmsg) +
CMSG_COMPAT_ALIGN(__cmsg_len));
if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
return NULL;
return __ptr;
}
static __inline__ struct compat_cmsghdr *cmsg_compat_nxthdr (struct msghdr *__msg,
struct compat_cmsghdr *__cmsg,
int __cmsg_len)
{
return __cmsg_compat_nxthdr(__msg->msg_control, __msg->msg_controllen,
__cmsg, __cmsg_len);
}
#endif /* CONFIG_COMPAT */
#endif
......@@ -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);
......
This diff is collapsed.
......@@ -30,6 +30,7 @@
#include <net/protocol.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/compat.h>
#include <net/scm.h>
......
......@@ -24,7 +24,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
{
int offset, offset_seq;
switch (skb->nh.iph->protocol) {
switch (nexthdr) {
case IPPROTO_AH:
offset = offsetof(struct ip_auth_hdr, spi);
offset_seq = offsetof(struct ip_auth_hdr, seq_no);
......
......@@ -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 -1;
return 0;
}
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;
}
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;
......
......@@ -672,8 +672,13 @@ static struct inet_protosw sctpv6_stream_protosw = {
.flags = SCTP_PROTOSW_FLAG
};
static int sctp6_rcv(struct sk_buff **pskb)
{
return sctp_rcv(*pskb);
}
static struct inet6_protocol sctpv6_protocol = {
.handler = sctp_rcv,
.handler = sctp6_rcv,
.err_handler = sctp_v6_err,
};
......
......@@ -89,7 +89,7 @@
#endif /* CONFIG_NET_RADIO */
#include <asm/uaccess.h>
#include <net/compat_socket.h>
#include <net/compat.h>
#include <net/sock.h>
#include <linux/netfilter.h>
......@@ -1558,7 +1558,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
err = -EFAULT;
if (MSG_CMSG_COMPAT & flags) {
if (msghdr_from_user_compat_to_kern(&msg_sys, msg_compat))
if (get_compat_msghdr(&msg_sys, msg_compat))
return -EFAULT;
} else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
......@@ -1652,7 +1652,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
int *uaddr_len;
if (MSG_CMSG_COMPAT & flags) {
if (msghdr_from_user_compat_to_kern(&msg_sys, msg_compat))
if (get_compat_msghdr(&msg_sys, msg_compat))
return -EFAULT;
} else
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
......@@ -1708,15 +1708,9 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg));
if (err)
goto out_freeiov;
if (MSG_CMSG_COMPAT & flags) {
unsigned long ucmsg_ptr;
compat_size_t uclen;
if((unsigned long) msg_sys.msg_control != cmsg_ptr)
cmsg_compat_recvmsg_fixup(&msg_sys, cmsg_ptr);
ucmsg_ptr = ((unsigned long)msg_sys.msg_control);
uclen = (compat_size_t) (ucmsg_ptr - cmsg_ptr);
err = __put_user(uclen, &msg_compat->msg_controllen);
} else
if (MSG_CMSG_COMPAT & flags)
err = put_compat_msg_controllen(&msg_sys, msg_compat, cmsg_ptr);
else
err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
&msg->msg_controllen);
if (err)
......
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