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 @@ ...@@ -21,6 +21,7 @@
#include <linux/fs_struct.h> #include <linux/fs_struct.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <net/compat.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/delay.h> #include <asm/delay.h>
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
/* For SOCKET_I */ /* For SOCKET_I */
#include <linux/socket.h> #include <linux/socket.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/compat.h>
/* Use this to get at 32-bit user passed pointers. */ /* Use this to get at 32-bit user passed pointers. */
#define A(__x) \ #define A(__x) \
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/file.h> #include <linux/file.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <net/compat.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/string.h> #include <asm/string.h>
......
...@@ -152,10 +152,7 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ...@@ -152,10 +152,7 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
void crypto_free_tfm(struct crypto_tfm *tfm) void crypto_free_tfm(struct crypto_tfm *tfm)
{ {
if (crypto_tfm_alg_type(tfm) == CRYPTO_ALG_TYPE_CIPHER) crypto_exit_ops(tfm);
if (tfm->crt_cipher.cit_iv)
kfree(tfm->crt_cipher.cit_iv);
crypto_alg_put(tfm->__crt_alg); crypto_alg_put(tfm->__crt_alg);
kfree(tfm); kfree(tfm);
} }
......
...@@ -43,11 +43,9 @@ extern int get_compat_timespec(struct timespec *, struct compat_timespec *); ...@@ -43,11 +43,9 @@ extern int get_compat_timespec(struct timespec *, struct compat_timespec *);
extern int put_compat_timespec(struct timespec *, struct compat_timespec *); extern int put_compat_timespec(struct timespec *, struct compat_timespec *);
struct compat_iovec { struct compat_iovec {
u32 iov_base; compat_uptr_t iov_base;
compat_size_t iov_len; compat_size_t iov_len;
}; };
#else /* no CONFIG_COMPAT */
#define compat_size_t size_t
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */ #endif /* _LINUX_COMPAT_H */
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
#include <linux/config.h> /* for CONFIG_COMPAT */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/socket.h> /* arch-dependent defines */ #include <asm/socket.h> /* arch-dependent defines */
#include <linux/sockios.h> /* the SIOCxxx I/O controls */ #include <linux/sockios.h> /* the SIOCxxx I/O controls */
...@@ -239,18 +240,10 @@ struct ucred { ...@@ -239,18 +240,10 @@ struct ucred {
#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */ #define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
#else #else
#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ #define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
#define compat_msghdr msghdr /* Needed to avoid compiler hoops */
#endif #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_sendmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage long sys_recvmsg(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 ...@@ -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_user(void *kaddr, int klen, void *uaddr, int *ulen);
extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr); 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(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
#endif /* not kernel and not glibc */ #endif /* not kernel and not glibc */
......
...@@ -175,7 +175,7 @@ extern void addrconf_forwarding_on(void); ...@@ -175,7 +175,7 @@ extern void addrconf_forwarding_on(void);
* Hash function taken from net_alias.c * 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; __u32 word;
...@@ -195,7 +195,7 @@ static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr) ...@@ -195,7 +195,7 @@ static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr)
* compute link-local solicited-node multicast address * 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) struct in6_addr *solicited)
{ {
ipv6_addr_set(solicited, ipv6_addr_set(solicited,
...@@ -219,7 +219,7 @@ static inline void ipv6_addr_all_routers(struct in6_addr *addr) ...@@ -219,7 +219,7 @@ static inline void ipv6_addr_all_routers(struct in6_addr *addr)
__constant_htonl(0x2)); __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); 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, ...@@ -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 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_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 struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
extern int ip6_frag_nqueues; extern int ip6_frag_nqueues;
...@@ -226,21 +222,21 @@ typedef int (*inet_getfrag_t) (const void *data, ...@@ -226,21 +222,21 @@ typedef int (*inet_getfrag_t) (const void *data,
unsigned int, unsigned int); 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; 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 #ifndef __HAVE_ARCH_ADDR_SET
...@@ -255,7 +251,7 @@ static inline void ipv6_addr_set(struct in6_addr *addr, ...@@ -255,7 +251,7 @@ static inline void ipv6_addr_set(struct in6_addr *addr,
} }
#endif #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] | return ((a->s6_addr32[0] | a->s6_addr32[1] |
a->s6_addr32[2] | a->s6_addr32[3] ) == 0); a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
......
...@@ -44,7 +44,7 @@ struct inet_protocol ...@@ -44,7 +44,7 @@ struct inet_protocol
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct inet6_protocol struct inet6_protocol
{ {
int (*handler)(struct sk_buff *skb); int (*handler)(struct sk_buff **skbp);
void (*err_handler)(struct sk_buff *skb, void (*err_handler)(struct sk_buff *skb,
struct inet6_skb_parm *opt, struct inet6_skb_parm *opt,
......
...@@ -15,6 +15,14 @@ extern struct proto tcpv6_prot; ...@@ -15,6 +15,14 @@ extern struct proto tcpv6_prot;
struct flowi; 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 rawv6_init(void);
extern void udpv6_init(void); extern void udpv6_init(void);
extern void tcpv6_init(void); extern void tcpv6_init(void);
......
...@@ -730,7 +730,7 @@ extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); ...@@ -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 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 xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
extern int xfrm4_rcv(struct sk_buff *skb); 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 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); extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
......
...@@ -25,14 +25,10 @@ ...@@ -25,14 +25,10 @@
#include <net/scm.h> #include <net/scm.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/compat_socket.h> #include <net/compat.h>
#define AA(__x) ((unsigned long)(__x)) #define AA(__x) ((unsigned long)(__x))
extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
void * optval, int *optlen);
static inline int iov_from_user_compat_to_kern(struct iovec *kiov, static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
struct compat_iovec *uiov32, struct compat_iovec *uiov32,
int niov) int niov)
...@@ -40,7 +36,8 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, ...@@ -40,7 +36,8 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
int tot_len = 0; int tot_len = 0;
while(niov > 0) { while(niov > 0) {
u32 len, buf; compat_uptr_t buf;
compat_size_t len;
if(get_user(len, &uiov32->iov_len) || if(get_user(len, &uiov32->iov_len) ||
get_user(buf, &uiov32->iov_base)) { get_user(buf, &uiov32->iov_base)) {
...@@ -57,27 +54,23 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, ...@@ -57,27 +54,23 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
return tot_len; return tot_len;
} }
int msghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct compat_msghdr *umsg) int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr *umsg)
{ {
compat_uptr_t tmp1, tmp2, tmp3; compat_uptr_t tmp1, tmp2, tmp3;
int err;
err = get_user(tmp1, &umsg->msg_name); if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
err |= __get_user(tmp2, &umsg->msg_iov); __get_user(tmp1, &umsg->msg_name) ||
err |= __get_user(tmp3, &umsg->msg_control); __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
if (err) __get_user(tmp2, &umsg->msg_iov) ||
__get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) ||
__get_user(tmp3, &umsg->msg_control) ||
__get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
__get_user(kmsg->msg_flags, &umsg->msg_flags))
return -EFAULT; return -EFAULT;
kmsg->msg_name = compat_ptr(tmp1); kmsg->msg_name = compat_ptr(tmp1);
kmsg->msg_iov = compat_ptr(tmp2); kmsg->msg_iov = compat_ptr(tmp2);
kmsg->msg_control = compat_ptr(tmp3); kmsg->msg_control = compat_ptr(tmp3);
return 0;
err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
return err;
} }
/* I've named the args so it is easy to tell whose space the pointers are in. */ /* I've named the args so it is easy to tell whose space the pointers are in. */
...@@ -116,6 +109,34 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, ...@@ -116,6 +109,34 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
return tot_len; return tot_len;
} }
/* Bleech... */
#define CMSG_COMPAT_ALIGN(len) ALIGN((len), sizeof(s32))
#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(msg) \
(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
(struct compat_cmsghdr *)((msg)->msg_control) : \
(struct compat_cmsghdr *)NULL)
static inline struct compat_cmsghdr *cmsg_compat_nxthdr(struct msghdr *msg,
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 *)msg->msg_control) >
msg->msg_controllen)
return NULL;
return ptr;
}
/* There is a lot of hair here because the alignment rules (and /* There is a lot of hair here because the alignment rules (and
* thus placement) of cmsg headers and length are different for * thus placement) of cmsg headers and length are different for
* 32-bit apps. -DaveM * 32-bit apps. -DaveM
...@@ -146,7 +167,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, ...@@ -146,7 +167,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr))); CMSG_ALIGN(sizeof(struct cmsghdr)));
kcmlen += tmp; kcmlen += tmp;
ucmsg = CMSG_COMPAT_NXTHDR(kmsg, ucmsg, ucmlen); ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
} }
if(kcmlen == 0) if(kcmlen == 0)
return -EINVAL; return -EINVAL;
...@@ -180,7 +201,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, ...@@ -180,7 +201,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
/* Advance. */ /* Advance. */
kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
ucmsg = CMSG_COMPAT_NXTHDR(kmsg, ucmsg, ucmlen); ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
} }
/* Ok, looks like we made it. Hook it up and return success. */ /* Ok, looks like we made it. Hook it up and return success. */
...@@ -303,7 +324,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) ...@@ -303,7 +324,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
* IPV6_RTHDR ipv6 routing exthdr 32-bit clean * IPV6_RTHDR ipv6 routing exthdr 32-bit clean
* IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean
*/ */
void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) static void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
{ {
unsigned char *workbuf, *wp; unsigned char *workbuf, *wp;
unsigned long bufsz, space_avail; unsigned long bufsz, space_avail;
...@@ -364,112 +385,133 @@ void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr ...@@ -364,112 +385,133 @@ void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr
kmsg->msg_control = (void *) orig_cmsg_uptr; kmsg->msg_control = (void *) orig_cmsg_uptr;
} }
int put_compat_msg_controllen(struct msghdr *msg_sys,
struct compat_msghdr *msg_compat, unsigned long cmsg_ptr)
{
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);
return __put_user(uclen, &msg_compat->msg_controllen);
}
extern asmlinkage long sys_setsockopt(int fd, int level, int optname, extern asmlinkage long sys_setsockopt(int fd, int level, int optname,
char *optval, int optlen); char *optval, int optlen);
/*
* For now, we assume that the compatibility and native version
* of struct ipt_entry are the same - sfr. FIXME
*/
struct compat_ipt_replace {
char name[IPT_TABLE_MAXNAMELEN];
u32 valid_hooks;
u32 num_entries;
u32 size;
u32 hook_entry[NF_IP_NUMHOOKS];
u32 underflow[NF_IP_NUMHOOKS];
u32 num_counters;
compat_uptr_t counters; /* struct ipt_counters * */
struct ipt_entry entries[0];
};
static int do_netfilter_replace(int fd, int level, int optname, static int do_netfilter_replace(int fd, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct ipt_replace32 { struct compat_ipt_replace *urepl = (struct compat_ipt_replace *)optval;
char name[IPT_TABLE_MAXNAMELEN];
__u32 valid_hooks;
__u32 num_entries;
__u32 size;
__u32 hook_entry[NF_IP_NUMHOOKS];
__u32 underflow[NF_IP_NUMHOOKS];
__u32 num_counters;
__u32 counters;
struct ipt_entry entries[0];
} *repl32 = (struct ipt_replace32 *)optval;
struct ipt_replace *krepl; struct ipt_replace *krepl;
struct ipt_counters *counters32; u32 origsize;
__u32 origsize; unsigned int kreplsize;
unsigned int kreplsize, kcountersize;
mm_segment_t old_fs; mm_segment_t old_fs;
int ret; int ret;
int i;
compat_uptr_t ucntrs;
if (optlen < sizeof(repl32)) if (get_user(origsize, &urepl->size))
return -EINVAL;
if (copy_from_user(&origsize,
&repl32->size,
sizeof(origsize)))
return -EFAULT; return -EFAULT;
kreplsize = sizeof(*krepl) + origsize;
kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
/* Hack: Causes ipchains to give correct error msg --RR */ /* Hack: Causes ipchains to give correct error msg --RR */
if (optlen != kreplsize) if (optlen != sizeof(*urepl) + origsize)
return -ENOPROTOOPT; return -ENOPROTOOPT;
/* XXX Assumes that size of ipt_entry is the same both in
* native and compat environments.
*/
kreplsize = sizeof(*krepl) + origsize;
krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL); krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
if (krepl == NULL) if (krepl == NULL)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(krepl, optval, kreplsize)) { ret = -EFAULT;
kfree(krepl); krepl->size = origsize;
return -EFAULT; if (!access_ok(VERIFY_READ, urepl, optlen) ||
__copy_from_user(krepl->name, urepl->name, sizeof(urepl->name)) ||
__get_user(krepl->valid_hooks, &urepl->valid_hooks) ||
__get_user(krepl->num_entries, &urepl->num_entries) ||
__get_user(krepl->num_counters, &urepl->num_counters) ||
__get_user(ucntrs, &urepl->counters) ||
__copy_from_user(krepl->entries, &urepl->entries, origsize))
goto out_free;
for (i = 0; i < NF_IP_NUMHOOKS; i++) {
if (__get_user(krepl->hook_entry[i], &urepl->hook_entry[i]) ||
__get_user(krepl->underflow[i], &urepl->underflow[i]))
goto out_free;
} }
counters32 = (struct ipt_counters *)AA( /*
((struct ipt_replace32 *)krepl)->counters); * Since struct ipt_counters just contains two u_int64_t members
* we can just do the access_ok check here and pass the (converted)
kcountersize = krepl->num_counters * sizeof(struct ipt_counters); * pointer into the standard syscall. We hope that the pointer is
krepl->counters = (struct ipt_counters *)kmalloc( * not misaligned ...
kcountersize, GFP_KERNEL); */
if (krepl->counters == NULL) { krepl->counters = compat_ptr(ucntrs);
kfree(krepl); if (!access_ok(VERIFY_WRITE, krepl->counters,
return -ENOMEM; krepl->num_counters * sizeof(struct ipt_counters)))
} goto out_free;
old_fs = get_fs(); old_fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
ret = sys_setsockopt(fd, level, optname, ret = sys_setsockopt(fd, level, optname, (char *)krepl, kreplsize);
(char *)krepl, kreplsize);
set_fs(old_fs); set_fs(old_fs);
if (ret == 0 && out_free:
copy_to_user(counters32, krepl->counters, kcountersize))
ret = -EFAULT;
kfree(krepl->counters);
kfree(krepl); kfree(krepl);
return ret; return ret;
} }
/*
* A struct sock_filter is architecture independent.
*/
struct compat_sock_fprog {
u16 len;
compat_uptr_t filter; /* struct sock_filter * */
};
static int do_set_attach_filter(int fd, int level, int optname, static int do_set_attach_filter(int fd, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sock_fprog32 { struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval;
__u16 len;
__u32 filter;
} *fprog32 = (struct sock_fprog32 *)optval;
struct sock_fprog kfprog; struct sock_fprog kfprog;
struct sock_filter *kfilter;
unsigned int fsize;
mm_segment_t old_fs; mm_segment_t old_fs;
compat_uptr_t uptr; compat_uptr_t uptr;
int ret; int ret;
if (get_user(kfprog.len, &fprog32->len) || if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
__get_user(kfprog.len, &fprog32->len) ||
__get_user(uptr, &fprog32->filter)) __get_user(uptr, &fprog32->filter))
return -EFAULT; return -EFAULT;
kfprog.filter = compat_ptr(uptr); kfprog.filter = compat_ptr(uptr);
fsize = kfprog.len * sizeof(struct sock_filter); /*
* Since struct sock_filter is architecure independent,
kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); * we can just do the access_ok check and pass the
if (kfilter == NULL) * same pointer to the real syscall.
return -ENOMEM; */
if (!access_ok(VERIFY_READ, kfprog.filter,
if (copy_from_user(kfilter, kfprog.filter, fsize)) { kfprog.len * sizeof(struct sock_filter)))
kfree(kfilter);
return -EFAULT; return -EFAULT;
}
kfprog.filter = kfilter;
old_fs = get_fs(); old_fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
...@@ -477,8 +519,6 @@ static int do_set_attach_filter(int fd, int level, int optname, ...@@ -477,8 +519,6 @@ static int do_set_attach_filter(int fd, int level, int optname,
(char *)&kfprog, sizeof(kfprog)); (char *)&kfprog, sizeof(kfprog));
set_fs(old_fs); set_fs(old_fs);
kfree(kfilter);
return ret; return ret;
} }
...@@ -489,10 +529,11 @@ static int do_set_icmpv6_filter(int fd, int level, int optname, ...@@ -489,10 +529,11 @@ static int do_set_icmpv6_filter(int fd, int level, int optname,
mm_segment_t old_fs; mm_segment_t old_fs;
int ret, i; int ret, i;
if (optlen < sizeof(kfilter))
return -EINVAL;
if (copy_from_user(&kfilter, optval, sizeof(kfilter))) if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
return -EFAULT; return -EFAULT;
for (i = 0; i < 8; i += 2) { for (i = 0; i < 8; i += 2) {
u32 tmp = kfilter.data[i]; u32 tmp = kfilter.data[i];
...@@ -518,7 +559,8 @@ static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int ...@@ -518,7 +559,8 @@ static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int
if (optlen < sizeof(*up)) if (optlen < sizeof(*up))
return -EINVAL; return -EINVAL;
if (get_user(ktime.tv_sec, &up->tv_sec) || if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
__get_user(ktime.tv_sec, &up->tv_sec) ||
__get_user(ktime.tv_usec, &up->tv_usec)) __get_user(ktime.tv_usec, &up->tv_usec))
return -EFAULT; return -EFAULT;
old_fs = get_fs(); old_fs = get_fs();
...@@ -547,7 +589,11 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, ...@@ -547,7 +589,11 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
return sys_setsockopt(fd, level, optname, optval, optlen); return sys_setsockopt(fd, level, optname, optval, optlen);
} }
static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int *optlen) extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
void * optval, int *optlen);
static int do_get_sock_timeout(int fd, int level, int optname, char *optval,
int *optlen)
{ {
struct compat_timeval *up = (struct compat_timeval *) optval; struct compat_timeval *up = (struct compat_timeval *) optval;
struct timeval ktime; struct timeval ktime;
...@@ -566,7 +612,8 @@ static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int ...@@ -566,7 +612,8 @@ static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int
if (!err) { if (!err) {
if (put_user(sizeof(*up), optlen) || if (put_user(sizeof(*up), optlen) ||
put_user(ktime.tv_sec, &up->tv_sec) || !access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
__put_user(ktime.tv_sec, &up->tv_sec) ||
__put_user(ktime.tv_usec, &up->tv_usec)) __put_user(ktime.tv_usec, &up->tv_usec))
err = -EFAULT; err = -EFAULT;
} }
...@@ -588,27 +635,21 @@ static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), ...@@ -588,27 +635,21 @@ static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
#undef AL #undef AL
extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); extern asmlinkage long sys_bind(int, struct sockaddr *, int);
extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, extern asmlinkage long sys_connect(int, struct sockaddr *, int);
int addrlen); extern asmlinkage long sys_accept(int, struct sockaddr *, int *);
extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, extern asmlinkage long sys_getsockname(int, struct sockaddr *, int *);
int *upeer_addrlen); extern asmlinkage long sys_getpeername(int, struct sockaddr *, int *);
extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, extern asmlinkage long sys_send(int, void *, size_t, unsigned);
int *usockaddr_len); extern asmlinkage long sys_sendto(int, void *, size_t, unsigned,
extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, struct sockaddr *, int);
int *usockaddr_len); extern asmlinkage long sys_recv(int, void *, size_t, unsigned);
extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags); extern asmlinkage long sys_recvfrom(int, void *, size_t, unsigned,
extern asmlinkage long sys_sendto(int fd, u32 buff, compat_size_t len, struct sockaddr *, int *);
unsigned flags, u32 addr, int addr_len); extern asmlinkage long sys_socket(int, int, int);
extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags); extern asmlinkage long sys_socketpair(int, int, int, int [2]);
extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, compat_size_t size, extern asmlinkage long sys_shutdown(int, int);
unsigned flags, u32 addr, u32 addr_len); extern asmlinkage long sys_listen(int, int);
extern asmlinkage long sys_socket(int family, int type, int protocol);
extern asmlinkage long sys_socketpair(int family, int type, int protocol,
int usockvec[2]);
extern asmlinkage long sys_shutdown(int fd, int how);
extern asmlinkage long sys_listen(int fd, int backlog);
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr *msg, unsigned flags) asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr *msg, unsigned flags)
{ {
...@@ -662,13 +703,13 @@ asmlinkage long compat_sys_socketcall(int call, u32 *args) ...@@ -662,13 +703,13 @@ asmlinkage long compat_sys_socketcall(int call, u32 *args)
ret = sys_send(a0, compat_ptr(a1), a[2], a[3]); ret = sys_send(a0, compat_ptr(a1), a[2], a[3]);
break; break;
case SYS_SENDTO: case SYS_SENDTO:
ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]); ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
break; break;
case SYS_RECV: case SYS_RECV:
ret = sys_recv(a0, compat_ptr(a1), a[2], a[3]); ret = sys_recv(a0, compat_ptr(a1), a[2], a[3]);
break; break;
case SYS_RECVFROM: case SYS_RECVFROM:
ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); ret = sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), compat_ptr(a[5]));
break; break;
case SYS_SHUTDOWN: case SYS_SHUTDOWN:
ret = sys_shutdown(a0,a1); ret = sys_shutdown(a0,a1);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <net/protocol.h> #include <net/protocol.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/compat.h>
#include <net/scm.h> #include <net/scm.h>
......
...@@ -24,7 +24,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) ...@@ -24,7 +24,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
{ {
int offset, offset_seq; int offset, offset_seq;
switch (skb->nh.iph->protocol) { switch (nexthdr) {
case IPPROTO_AH: case IPPROTO_AH:
offset = offsetof(struct ip_auth_hdr, spi); offset = offsetof(struct ip_auth_hdr, spi);
offset_seq = offsetof(struct ip_auth_hdr, seq_no); 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 ...@@ -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 void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ; static int desync_factor = MAX_DESYNC_FACTOR * HZ;
static struct crypto_tfm *md5_tfm;
static spinlock_t md5_tfm_lock = SPIN_LOCK_UNLOCKED;
#endif #endif
static int ipv6_count_addresses(struct inet6_dev *idev); static int ipv6_count_addresses(struct inet6_dev *idev);
...@@ -172,7 +174,7 @@ static struct ipv6_devconf ipv6_devconf_dflt = ...@@ -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_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_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; int type;
u32 st; u32 st;
...@@ -426,8 +428,7 @@ static void dev_forward_change(struct inet6_dev *idev) ...@@ -426,8 +428,7 @@ static void dev_forward_change(struct inet6_dev *idev)
} }
for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
ipv6_addr_prefix(&addr, &ifa->addr, ifa->prefix_len); ipv6_addr_prefix(&addr, &ifa->addr, ifa->prefix_len);
if (addr.s6_addr32[0] == 0 && addr.s6_addr32[1] == 0 && if (ipv6_addr_any(&addr))
addr.s6_addr32[2] == 0 && addr.s6_addr32[3] == 0)
continue; continue;
if (idev->cnf.forwarding) if (idev->cnf.forwarding)
ipv6_dev_ac_inc(idev->dev, &addr); ipv6_dev_ac_inc(idev->dev, &addr);
...@@ -486,7 +487,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) ...@@ -486,7 +487,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
/* On success it returns ifp with increased reference count */ /* On success it returns ifp with increased reference count */
static struct inet6_ifaddr * 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) int scope, unsigned flags)
{ {
struct inet6_ifaddr *ifa; struct inet6_ifaddr *ifa;
...@@ -1046,7 +1047,6 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev) ...@@ -1046,7 +1047,6 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
struct net_device *dev; struct net_device *dev;
u8 eui64[8]; u8 eui64[8];
u8 digest[16]; u8 digest[16];
struct crypto_tfm *tfm;
struct scatterlist sg[2]; struct scatterlist sg[2];
sg[0].page = virt_to_page(idev->entropy); sg[0].page = virt_to_page(idev->entropy);
...@@ -1068,18 +1068,16 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev) ...@@ -1068,18 +1068,16 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
get_random_bytes(eui64, sizeof(eui64)); get_random_bytes(eui64, sizeof(eui64));
} }
regen: regen:
tfm = crypto_alloc_tfm("md5", 0); spin_lock(&md5_tfm_lock);
if (tfm == NULL) { if (unlikely(md5_tfm == NULL)) {
if (net_ratelimit()) spin_unlock(&md5_tfm_lock);
printk(KERN_WARNING
"failed to load transform for md5\n");
in6_dev_put(idev); in6_dev_put(idev);
return -1; return -1;
} }
crypto_digest_init(tfm); crypto_digest_init(md5_tfm);
crypto_digest_update(tfm, sg, 2); crypto_digest_update(md5_tfm, sg, 2);
crypto_digest_final(tfm, digest); crypto_digest_final(md5_tfm, digest);
crypto_free_tfm(tfm); spin_unlock(&md5_tfm_lock);
memcpy(idev->rndid, &digest[0], 8); memcpy(idev->rndid, &digest[0], 8);
idev->rndid[0] &= ~0x02; idev->rndid[0] &= ~0x02;
...@@ -1107,6 +1105,9 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev) ...@@ -1107,6 +1105,9 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
goto regen; 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)) { if (time_before(idev->regen_timer.expires, jiffies)) {
idev->regen_timer.expires = 0; idev->regen_timer.expires = 0;
printk(KERN_WARNING printk(KERN_WARNING
...@@ -1646,7 +1647,6 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) ...@@ -1646,7 +1647,6 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
static void init_loopback(struct net_device *dev) static void init_loopback(struct net_device *dev)
{ {
struct in6_addr addr;
struct inet6_dev *idev; struct inet6_dev *idev;
struct inet6_ifaddr * ifp; struct inet6_ifaddr * ifp;
...@@ -1654,15 +1654,12 @@ static void init_loopback(struct net_device *dev) ...@@ -1654,15 +1654,12 @@ static void init_loopback(struct net_device *dev)
ASSERT_RTNL(); ASSERT_RTNL();
memset(&addr, 0, sizeof(struct in6_addr));
addr.s6_addr[15] = 1;
if ((idev = ipv6_find_idev(dev)) == NULL) { if ((idev = ipv6_find_idev(dev)) == NULL) {
printk(KERN_DEBUG "init loopback: add_dev failed\n"); printk(KERN_DEBUG "init loopback: add_dev failed\n");
return; 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) { if (ifp) {
spin_lock_bh(&ifp->lock); spin_lock_bh(&ifp->lock);
ifp->flags &= ~IFA_F_TENTATIVE; ifp->flags &= ~IFA_F_TENTATIVE;
...@@ -2034,8 +2031,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) ...@@ -2034,8 +2031,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
struct in6_addr addr; struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (addr.s6_addr32[0] || addr.s6_addr32[1] || if (!ipv6_addr_any(&addr))
addr.s6_addr32[2] || addr.s6_addr32[3])
ipv6_dev_ac_inc(ifp->idev->dev, &addr); ipv6_dev_ac_inc(ifp->idev->dev, &addr);
} }
} }
...@@ -2372,8 +2368,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) ...@@ -2372,8 +2368,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
struct in6_addr addr; struct in6_addr addr;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
if (addr.s6_addr32[0] || addr.s6_addr32[1] || if (!ipv6_addr_any(&addr))
addr.s6_addr32[2] || addr.s6_addr32[3])
ipv6_dev_ac_dec(ifp->idev->dev, &addr); ipv6_dev_ac_dec(ifp->idev->dev, &addr);
} }
if (!ipv6_chk_addr(&ifp->addr, NULL)) if (!ipv6_chk_addr(&ifp->addr, NULL))
...@@ -2654,7 +2649,16 @@ void __init addrconf_init(void) ...@@ -2654,7 +2649,16 @@ void __init addrconf_init(void)
{ {
#ifdef MODULE #ifdef MODULE
struct net_device *dev; 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. */ /* This takes sense only during module load. */
rtnl_lock(); rtnl_lock();
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
...@@ -2739,6 +2743,13 @@ void addrconf_cleanup(void) ...@@ -2739,6 +2743,13 @@ void addrconf_cleanup(void)
rtnl_unlock(); rtnl_unlock();
#ifdef CONFIG_IPV6_PRIVACY
if (likely(md5_tfm != NULL)) {
crypto_free_tfm(md5_tfm);
md5_tfm = NULL;
}
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_net_remove("if_inet6"); proc_net_remove("if_inet6");
#endif #endif
......
...@@ -799,6 +799,13 @@ static int __init inet6_init(void) ...@@ -799,6 +799,13 @@ static int __init inet6_init(void)
addrconf_init(); addrconf_init();
sit_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. */ /* Init v6 transport protocols. */
udpv6_init(); udpv6_init();
tcpv6_init(); tcpv6_init();
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
/* Changes: /* Changes:
* yoshfuji : ensure not to overrun while parsing * yoshfuji : ensure not to overrun while parsing
* tlv options. * tlv options.
* Mitsuru KANDA @USAGI : Remove ipv6_parse_exthdrs().
* : Register inbound extention header
* : handlers as inet6_protocol{}.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
...@@ -43,20 +46,6 @@ ...@@ -43,20 +46,6 @@
#include <asm/uaccess.h> #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. * Parsing tlv encoded headers.
* *
...@@ -164,49 +153,77 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = { ...@@ -164,49 +153,77 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
{-1, NULL} {-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; 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) || 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))) { !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
kfree_skb(skb); kfree_skb(skb);
return -1; return 0;
} }
nexthdr = ((struct ipv6_destopt_hdr *)skb->h.raw)->nexthdr;
opt->dst1 = skb->h.raw - skb->nh.raw; opt->dst1 = skb->h.raw - skb->nh.raw;
if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
skb->h.raw += ((skb->h.raw[1]+1)<<3); 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. 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); struct sk_buff *skb = *skbp;
return -1;
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. 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 inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
struct in6_addr *addr; struct in6_addr *addr;
struct in6_addr daddr; struct in6_addr daddr;
int addr_type; int addr_type;
int n, i; int n, i;
u8 nexthdr = 0;
struct ipv6_rt_hdr *hdr; struct ipv6_rt_hdr *hdr;
struct rt0_hdr *rthdr; struct rt0_hdr *rthdr;
...@@ -215,15 +232,16 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) ...@@ -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))) { !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
IP6_INC_STATS_BH(Ip6InHdrErrors); IP6_INC_STATS_BH(Ip6InHdrErrors);
kfree_skb(skb); kfree_skb(skb);
return -1; return 0;
} }
hdr = (struct ipv6_rt_hdr *) skb->h.raw; hdr = (struct ipv6_rt_hdr *) skb->h.raw;
nexthdr = hdr->nexthdr;
if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) || if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||
skb->pkt_type != PACKET_HOST) { skb->pkt_type != PACKET_HOST) {
kfree_skb(skb); kfree_skb(skb);
return -1; return 0;
} }
looped_back: looped_back:
...@@ -232,24 +250,24 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) ...@@ -232,24 +250,24 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
skb->h.raw += (hdr->hdrlen + 1) << 3; skb->h.raw += (hdr->hdrlen + 1) << 3;
opt->dst0 = opt->dst1; opt->dst0 = opt->dst1;
opt->dst1 = 0; opt->dst1 = 0;
return (&hdr->nexthdr) - skb->nh.raw; return -nexthdr;
} }
if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) { 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); 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 * This is the routing header forwarding algorithm from
* RFC 1883, page 17. * RFC 2460, page 16.
*/ */
n = hdr->hdrlen >> 1; n = hdr->hdrlen >> 1;
if (hdr->segments_left > n) { if (hdr->segments_left > n) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw); 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! /* 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) ...@@ -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); struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
kfree_skb(skb); kfree_skb(skb);
if (skb2 == NULL) if (skb2 == NULL)
return -1; return 0;
*skb_ptr = skb = skb2; *skbp = skb = skb2;
opt = (struct inet6_skb_parm *)skb2->cb; opt = (struct inet6_skb_parm *)skb2->cb;
hdr = (struct ipv6_rt_hdr *) skb2->h.raw; hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
} }
...@@ -278,7 +296,7 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) ...@@ -278,7 +296,7 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
if (addr_type&IPV6_ADDR_MULTICAST) { if (addr_type&IPV6_ADDR_MULTICAST) {
kfree_skb(skb); kfree_skb(skb);
return -1; return 0;
} }
ipv6_addr_copy(&daddr, addr); ipv6_addr_copy(&daddr, addr);
...@@ -289,23 +307,34 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff) ...@@ -289,23 +307,34 @@ static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
ip6_route_input(skb); ip6_route_input(skb);
if (skb->dst->error) { if (skb->dst->error) {
dst_input(skb); dst_input(skb);
return -1; return 0;
} }
if (skb->dst->dev->flags&IFF_LOOPBACK) { if (skb->dst->dev->flags&IFF_LOOPBACK) {
if (skb->nh.ipv6h->hop_limit <= 1) { if (skb->nh.ipv6h->hop_limit <= 1) {
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
0, skb->dev); 0, skb->dev);
kfree_skb(skb); kfree_skb(skb);
return -1; return 0;
} }
skb->nh.ipv6h->hop_limit--; skb->nh.ipv6h->hop_limit--;
goto looped_back; goto looped_back;
} }
dst_input(skb); 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. This function inverts received rthdr.
NOTE: specs allow to make it automatically only if NOTE: specs allow to make it automatically only if
...@@ -371,97 +400,6 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr) ...@@ -371,97 +400,6 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
return opt; 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. Hop-by-hop options.
**********************************/ **********************************/
...@@ -532,6 +470,34 @@ int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) ...@@ -532,6 +470,34 @@ int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
return -1; 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. * Creating outbound headers.
* *
......
...@@ -74,7 +74,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); ...@@ -74,7 +74,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
static struct socket *__icmpv6_socket[NR_CPUS]; static struct socket *__icmpv6_socket[NR_CPUS];
#define icmpv6_socket __icmpv6_socket[smp_processor_id()] #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 = { static struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv, .handler = icmpv6_rcv,
...@@ -459,8 +459,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) ...@@ -459,8 +459,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
* Handle icmp messages * 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 net_device *dev = skb->dev;
struct in6_addr *saddr, *daddr; struct in6_addr *saddr, *daddr;
struct ipv6hdr *orig_hdr; struct ipv6hdr *orig_hdr;
......
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later 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/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -126,39 +130,11 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -126,39 +130,11 @@ static inline int ip6_input_finish(struct sk_buff *skb)
struct ipv6hdr *hdr = skb->nh.ipv6h; struct ipv6hdr *hdr = skb->nh.ipv6h;
struct inet6_protocol *ipprot; struct inet6_protocol *ipprot;
struct sock *raw_sk; struct sock *raw_sk;
int nhoff; int nexthdr = hdr->nexthdr;
int nexthdr;
u8 hash; u8 hash;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr); 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)) if (!pskb_pull(skb, skb->h.raw - skb->data))
goto discard; goto discard;
...@@ -173,7 +149,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -173,7 +149,7 @@ static inline int ip6_input_finish(struct sk_buff *skb)
hash = nexthdr & (MAX_INET_PROTOS - 1); hash = nexthdr & (MAX_INET_PROTOS - 1);
if ((ipprot = inet6_protos[hash]) != NULL) { if ((ipprot = inet6_protos[hash]) != NULL) {
int ret = ipprot->handler(skb); int ret = ipprot->handler(&skb);
if (ret < 0) { if (ret < 0) {
nexthdr = -ret; nexthdr = -ret;
goto resubmit; goto resubmit;
...@@ -182,7 +158,8 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -182,7 +158,8 @@ static inline int ip6_input_finish(struct sk_buff *skb)
} else { } else {
if (!raw_sk) { if (!raw_sk) {
IP6_INC_STATS_BH(Ip6InUnknownProtos); 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 { } else {
IP6_INC_STATS_BH(Ip6InDelivers); IP6_INC_STATS_BH(Ip6InDelivers);
kfree_skb(skb); kfree_skb(skb);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
* Horst von Brand Add missing #include <linux/string.h> * Horst von Brand Add missing #include <linux/string.h>
* Alexey Kuznetsov SMP races, threading, cleanup. * Alexey Kuznetsov SMP races, threading, cleanup.
* Patrick McHardy LRU queue of frag heads for evictor. * Patrick McHardy LRU queue of frag heads for evictor.
* Mitsuru KANDA @USAGI Register inet6_protocol{}.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -525,6 +526,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -525,6 +526,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
int remove_fraghdr = 0; int remove_fraghdr = 0;
int payload_len; int payload_len;
int nhoff; int nhoff;
u8 nexthdr = 0;
fq_kill(fq); fq_kill(fq);
...@@ -535,6 +537,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -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; payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
nhoff = head->h.raw - head->nh.raw; nhoff = head->h.raw - head->nh.raw;
nexthdr = ((struct frag_hdr*)head->h.raw)->nexthdr;
if (payload_len > 65535) { if (payload_len > 65535) {
payload_len -= 8; payload_len -= 8;
if (payload_len > 65535) if (payload_len > 65535)
...@@ -609,9 +613,12 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -609,9 +613,12 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
if (head->ip_summed == CHECKSUM_HW) if (head->ip_summed == CHECKSUM_HW)
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); 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); IP6_INC_STATS_BH(Ip6ReasmOKs);
fq->fragments = NULL; fq->fragments = NULL;
return nhoff; return nexthdr;
out_oversize: out_oversize:
if (net_ratelimit()) if (net_ratelimit())
...@@ -622,16 +629,18 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, ...@@ -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"); printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
out_fail: out_fail:
IP6_INC_STATS_BH(Ip6ReasmFails); 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 sk_buff *skb = *skbp;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct frag_hdr *fhdr; struct frag_hdr *fhdr;
struct frag_queue *fq; struct frag_queue *fq;
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
int nhoff = skb->h.raw - skb->nh.raw;
u8 nexthdr = 0;
hdr = skb->nh.ipv6h; hdr = skb->nh.ipv6h;
...@@ -640,15 +649,16 @@ int ipv6_reassembly(struct sk_buff **skbp, int nhoff) ...@@ -640,15 +649,16 @@ int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
/* Jumbo payload inhibits frag. header */ /* Jumbo payload inhibits frag. header */
if (hdr->payload_len==0) { if (hdr->payload_len==0) {
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw); 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))) { 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); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1; goto discard;
} }
hdr = skb->nh.ipv6h; hdr = skb->nh.ipv6h;
fhdr = (struct frag_hdr *)skb->h.raw; fhdr = (struct frag_hdr *)skb->h.raw;
nexthdr = fhdr->nexthdr;
if (!(fhdr->frag_off & htons(0xFFF9))) { if (!(fhdr->frag_off & htons(0xFFF9))) {
/* It is not a fragmented frame */ /* It is not a fragmented frame */
...@@ -674,10 +684,22 @@ int ipv6_reassembly(struct sk_buff **skbp, int nhoff) ...@@ -674,10 +684,22 @@ int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
spin_unlock(&fq->lock); spin_unlock(&fq->lock);
fq_put(fq); fq_put(fq);
return ret; return -ret;
} }
discard:
IP6_INC_STATS_BH(Ip6ReasmFails); IP6_INC_STATS_BH(Ip6ReasmFails);
kfree_skb(skb); 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) ...@@ -1591,8 +1591,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0; 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 tcphdr *th;
struct sock *sk; struct sock *sk;
int ret; int ret;
......
...@@ -641,8 +641,9 @@ static void udpv6_mcast_deliver(struct udphdr *uh, ...@@ -641,8 +641,9 @@ static void udpv6_mcast_deliver(struct udphdr *uh,
read_unlock(&udp_hash_lock); 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 sock *sk;
struct udphdr *uh; struct udphdr *uh;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
......
...@@ -123,8 +123,9 @@ int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir) ...@@ -123,8 +123,9 @@ int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
return nexthdr; return nexthdr;
} }
int xfrm6_rcv(struct sk_buff *skb) int xfrm6_rcv(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb;
int err; int err;
u32 spi, seq; u32 spi, seq;
struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
...@@ -137,12 +138,8 @@ int xfrm6_rcv(struct sk_buff *skb) ...@@ -137,12 +138,8 @@ int xfrm6_rcv(struct sk_buff *skb)
u16 nh_offset = 0; u16 nh_offset = 0;
u8 nexthdr = 0; u8 nexthdr = 0;
if (hdr->nexthdr == IPPROTO_AH || hdr->nexthdr == IPPROTO_ESP) {
nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw; nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
hdr_len = sizeof(struct ipv6hdr); hdr_len = sizeof(struct ipv6hdr);
} else {
hdr_len = skb->h.raw - skb->nh.raw;
}
tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC); tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
if (!tmp_hdr) if (!tmp_hdr)
...@@ -189,20 +186,6 @@ int xfrm6_rcv(struct sk_buff *skb) ...@@ -189,20 +186,6 @@ int xfrm6_rcv(struct sk_buff *skb)
xfrm_vec[xfrm_nr++] = x; 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 (x->props.mode) { /* XXX */
if (iph->nexthdr != IPPROTO_IPV6) if (iph->nexthdr != IPPROTO_IPV6)
goto drop; goto drop;
......
...@@ -672,8 +672,13 @@ static struct inet_protosw sctpv6_stream_protosw = { ...@@ -672,8 +672,13 @@ static struct inet_protosw sctpv6_stream_protosw = {
.flags = SCTP_PROTOSW_FLAG .flags = SCTP_PROTOSW_FLAG
}; };
static int sctp6_rcv(struct sk_buff **pskb)
{
return sctp_rcv(*pskb);
}
static struct inet6_protocol sctpv6_protocol = { static struct inet6_protocol sctpv6_protocol = {
.handler = sctp_rcv, .handler = sctp6_rcv,
.err_handler = sctp_v6_err, .err_handler = sctp_v6_err,
}; };
......
...@@ -89,7 +89,7 @@ ...@@ -89,7 +89,7 @@
#endif /* CONFIG_NET_RADIO */ #endif /* CONFIG_NET_RADIO */
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/compat_socket.h> #include <net/compat.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
...@@ -1558,7 +1558,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) ...@@ -1558,7 +1558,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
err = -EFAULT; err = -EFAULT;
if (MSG_CMSG_COMPAT & flags) { 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; return -EFAULT;
} else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT; return -EFAULT;
...@@ -1652,7 +1652,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) ...@@ -1652,7 +1652,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
int *uaddr_len; int *uaddr_len;
if (MSG_CMSG_COMPAT & flags) { 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; return -EFAULT;
} else } else
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) 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) ...@@ -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)); err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg));
if (err) if (err)
goto out_freeiov; goto out_freeiov;
if (MSG_CMSG_COMPAT & flags) { if (MSG_CMSG_COMPAT & flags)
unsigned long ucmsg_ptr; err = put_compat_msg_controllen(&msg_sys, msg_compat, cmsg_ptr);
compat_size_t uclen; else
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
err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
&msg->msg_controllen); &msg->msg_controllen);
if (err) 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