Commit ecfb7e4c authored by David S. Miller's avatar David S. Miller

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

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 7e8a4852 7f2cad70
......@@ -116,7 +116,7 @@ extern int ip_append_data(struct sock *sk,
struct ipcm_cookie *ipc,
struct rtable *rt,
unsigned int flags);
extern int generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb);
extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb);
extern ssize_t ip_append_page(struct sock *sk, struct page *page,
int offset, size_t size, int flags);
extern int ip_push_pending_frames(struct sock *sk);
......@@ -141,8 +141,7 @@ static inline void ip_tr_mc_map(u32 addr, char *buf)
}
struct ip_reply_arg {
struct iovec iov[2];
int n_iov; /* redundant */
struct iovec iov[1];
u32 csum;
int csumoffset; /* u16 offset of csum in iov[0].iov_base */
/* -1 if not needed */
......
......@@ -101,7 +101,6 @@ struct icmp_bxm {
int offset;
int data_len;
unsigned int csum;
struct {
struct icmphdr icmph;
__u32 times[3];
......@@ -356,39 +355,45 @@ static void icmp_out_count(int type)
* Checksum each fragment, and on the first include the headers and final
* checksum.
*/
static int icmp_glue_bits(const void *p, char *to, unsigned int offset,
unsigned int fraglen, struct sk_buff *skb)
int
icmp_glue_bits(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
{
struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
struct icmphdr *icmph;
struct icmp_bxm *icmp_param = (struct icmp_bxm *)from;
unsigned int csum;
skb->ip_summed = CHECKSUM_NONE;
csum = skb_copy_and_csum_bits(icmp_param->skb,
icmp_param->offset + offset,
to, len, 0);
if (offset) {
icmp_param->csum =
skb_copy_and_csum_bits(icmp_param->skb,
icmp_param->offset +
(offset - icmp_param->head_len),
to, fraglen, icmp_param->csum);
goto out;
}
skb->csum = csum_block_add(skb->csum, csum, odd);
return 0;
}
/*
* First fragment includes header. Note that we've done
* the other fragments first, so that we get the checksum
* for the whole packet here.
*/
static void
icmp_push_reply(struct icmp_bxm *icmp_param, struct ipcm_cookie *ipc, struct rtable *rt)
{
struct sk_buff *skb;
ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
icmp_param->head_len,
ipc, rt, MSG_DONTWAIT);
if ((skb = skb_peek(&icmp_socket->sk->write_queue)) != NULL) {
struct icmphdr *icmph = skb->h.icmph;
unsigned int csum = 0;
struct sk_buff *skb1;
skb_queue_walk(&icmp_socket->sk->write_queue, skb1) {
csum = csum_add(csum, skb1->csum);
}
csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
to, icmp_param->head_len,
icmp_param->csum);
csum = skb_copy_and_csum_bits(icmp_param->skb, icmp_param->offset,
to + icmp_param->head_len,
fraglen - icmp_param->head_len, csum);
icmph = (struct icmphdr *)to;
(char*)icmph, icmp_param->head_len,
csum);
icmph->checksum = csum_fold(csum);
out:
return 0;
skb->ip_summed = CHECKSUM_NONE;
ip_push_pending_frames(icmp_socket->sk);
}
}
/*
......@@ -408,7 +413,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
goto out;
icmp_param->data.icmph.checksum = 0;
icmp_param->csum = 0;
icmp_out_count(icmp_param->data.icmph.type);
inet->tos = skb->nh.iph->tos;
......@@ -429,11 +433,8 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
goto out_unlock;
}
if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
icmp_param->data.icmph.code)) {
ip_build_xmit(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
&ipc, rt, MSG_DONTWAIT);
}
icmp_param->data.icmph.code))
icmp_push_reply(icmp_param, &ipc, rt);
ip_rt_put(rt);
out_unlock:
icmp_xmit_unlock_bh();
......@@ -565,7 +566,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
icmp_param.data.icmph.code = code;
icmp_param.data.icmph.un.gateway = info;
icmp_param.data.icmph.checksum = 0;
icmp_param.csum = 0;
icmp_param.skb = skb_in;
icmp_param.offset = skb_in->nh.raw - skb_in->data;
icmp_out_count(icmp_param.data.icmph.type);
......@@ -599,9 +599,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
icmp_param.data_len = room;
icmp_param.head_len = sizeof(struct icmphdr);
ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param,
icmp_param.data_len + sizeof(struct icmphdr),
&ipc, rt, MSG_DONTWAIT);
icmp_push_reply(&icmp_param, &ipc, rt);
ende:
ip_rt_put(rt);
out_unlock:
......
......@@ -1003,7 +1003,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
}
int
generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
{
struct iovec *iov = from;
......@@ -1095,7 +1095,7 @@ int ip_append_data(struct sock *sk,
opt = ipc->opt;
if (opt) {
if (inet->cork.opt == NULL)
inet->cork.opt = kmalloc(sizeof(struct ip_options)+40, GFP_KERNEL);
inet->cork.opt = kmalloc(sizeof(struct ip_options)+40, sk->allocation);
memcpy(inet->cork.opt, opt, sizeof(struct ip_options)+opt->optlen);
inet->cork.flags |= IPCORK_OPT;
inet->cork.addr = ipc->addr;
......@@ -1129,7 +1129,6 @@ int ip_append_data(struct sock *sk,
return -EMSGSIZE;
}
#if 0 /* Not now */
/*
* transhdrlen > 0 means that this is the first fragment and we wish
* it won't be fragmented in the future.
......@@ -1139,7 +1138,6 @@ int ip_append_data(struct sock *sk,
rt->u.dst.dev->features&(NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) &&
!exthdrlen)
csummode = CHECKSUM_HW;
#endif
inet->cork.length += length;
......@@ -1151,6 +1149,7 @@ int ip_append_data(struct sock *sk,
char *data;
unsigned int datalen;
unsigned int fraglen;
unsigned int alloclen;
BUG_TRAP(copy == 0);
alloc_new_skb:
......@@ -1159,11 +1158,18 @@ int ip_append_data(struct sock *sk,
datalen = length;
fraglen = datalen + fragheaderlen;
if ((flags & MSG_MORE) &&
!(rt->u.dst.dev->features&NETIF_F_SG))
alloclen = maxfraglen;
else
alloclen = datalen + fragheaderlen;
if (!(flags & MSG_DONTWAIT) || transhdrlen) {
skb = sock_alloc_send_skb(sk, fraglen + hh_len + 15,
skb = sock_alloc_send_skb(sk,
alloclen + hh_len + 15,
(flags & MSG_DONTWAIT), &err);
} else {
skb = sock_wmalloc(sk, fraglen + hh_len + 15, 1,
skb = sock_wmalloc(sk,
alloclen + hh_len + 15, 1,
sk->allocation);
if (unlikely(skb == NULL))
err = -ENOBUFS;
......@@ -1206,20 +1212,15 @@ int ip_append_data(struct sock *sk,
continue;
}
if (copy > length)
copy = length;
if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
int off;
if (!((skb->len - fragheaderlen) & 7))
goto alloc_new_skb;
unsigned int off;
/*
* Align the start address of the next IP fragment
* on 8 byte boundary.
*/
copy = 8 - ((skb->len - fragheaderlen) & 7);
off = skb->len;
if (copy > length)
copy = length;
if (getfrag(from, skb_put(skb, copy), offset, copy, off, skb) < 0) {
if (getfrag(from, skb_put(skb, copy),
offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
err = -EFAULT;
goto error;
......@@ -1231,9 +1232,6 @@ int ip_append_data(struct sock *sk,
int off = inet->sndmsg_off;
unsigned int left;
if (copy > length)
copy = length;
if (page && (left = PAGE_SIZE - off) > 0) {
if (copy >= left)
copy = left;
......@@ -1518,38 +1516,13 @@ void ip_flush_pending_frames(struct sock *sk)
/*
* Fetch data from kernel space and fill in checksum if needed.
*/
static int ip_reply_glue_bits(const void *dptr, char *to, unsigned int offset,
unsigned int fraglen, struct sk_buff *skb)
static int ip_reply_glue_bits(void *dptr, char *to, int offset,
int len, int odd, struct sk_buff *skb)
{
struct ip_reply_arg *dp = (struct ip_reply_arg*)dptr;
u16 *pktp = (u16 *)to;
struct iovec *iov;
int len;
int hdrflag = 1;
iov = &dp->iov[0];
if (offset >= iov->iov_len) {
offset -= iov->iov_len;
iov++;
hdrflag = 0;
}
len = iov->iov_len - offset;
if (fraglen > len) { /* overlapping. */
dp->csum = csum_partial_copy_nocheck(iov->iov_base+offset, to, len,
dp->csum);
offset = 0;
fraglen -= len;
to += len;
iov++;
}
dp->csum = csum_partial_copy_nocheck(iov->iov_base+offset, to, fraglen,
dp->csum);
if (hdrflag && dp->csumoffset)
*(pktp + dp->csumoffset) = csum_fold(dp->csum); /* fill in checksum */
skb->ip_summed = CHECKSUM_NONE;
unsigned int csum;
csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0);
skb->csum = csum_block_add(skb->csum, csum, odd);
return 0;
}
......@@ -1606,7 +1579,15 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
inet->tos = skb->nh.iph->tos;
sk->priority = skb->priority;
sk->protocol = skb->nh.iph->protocol;
ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT);
ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
&ipc, rt, MSG_DONTWAIT);
if ((skb = skb_peek(&sk->write_queue)) != NULL) {
if (arg->csumoffset >= 0)
*((u16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum));
skb->ip_summed = CHECKSUM_NONE;
ip_push_pending_frames(sk);
}
bh_unlock_sock(sk);
ip_rt_put(rt);
......
......@@ -68,44 +68,42 @@ static char *ax2asc2(ax25_address *a, char *buf)
#endif /* CONFIG_AX25 */
struct arp_iter_state {
loff_t is_pneigh: 1,
bucket: 6,
pos: sizeof(loff_t) * 8 - 7;
int is_pneigh, bucket;
};
static __inline__ struct neighbour *neigh_get_bucket(loff_t *pos)
static __inline__ struct neighbour *neigh_get_bucket(struct seq_file *seq,
loff_t *pos)
{
struct neighbour *n = NULL;
struct arp_iter_state* state = (struct arp_iter_state *)pos;
loff_t l = state->pos;
int i, bucket = state->bucket;
struct arp_iter_state* state = seq->private;
loff_t l = *pos;
int i;
for (; bucket <= NEIGH_HASHMASK; ++bucket)
for (i = 0, n = arp_tbl.hash_buckets[bucket]; n;
for (; state->bucket <= NEIGH_HASHMASK; ++state->bucket)
for (i = 0, n = arp_tbl.hash_buckets[state->bucket]; n;
++i, n = n->next)
/* Do not confuse users "arp -a" with magic entries */
if ((n->nud_state & ~NUD_NOARP) && !l--) {
state->pos = i;
state->bucket = bucket;
*pos = i;
goto out;
}
out:
return n;
}
static __inline__ struct pneigh_entry *pneigh_get_bucket(loff_t *pos)
static __inline__ struct pneigh_entry *pneigh_get_bucket(struct seq_file *seq,
loff_t *pos)
{
struct pneigh_entry *n = NULL;
struct arp_iter_state* state = (struct arp_iter_state *)pos;
loff_t l = state->pos;
int i, bucket = state->bucket;
struct arp_iter_state* state = seq->private;
loff_t l = *pos;
int i;
for (; bucket <= PNEIGH_HASHMASK; ++bucket)
for (i = 0, n = arp_tbl.phash_buckets[bucket]; n;
for (; state->bucket <= PNEIGH_HASHMASK; ++state->bucket)
for (i = 0, n = arp_tbl.phash_buckets[state->bucket]; n;
++i, n = n->next)
if (!l--) {
state->pos = i;
state->bucket = bucket;
*pos = i;
goto out;
}
out:
......@@ -114,18 +112,16 @@ static __inline__ struct pneigh_entry *pneigh_get_bucket(loff_t *pos)
static __inline__ void *arp_get_bucket(struct seq_file *seq, loff_t *pos)
{
void *rc = neigh_get_bucket(pos);
void *rc = neigh_get_bucket(seq, pos);
if (!rc) {
struct arp_iter_state* state = (struct arp_iter_state *)pos;
struct arp_iter_state* state = seq->private;
read_unlock_bh(&arp_tbl.lock);
state->is_pneigh = 1;
state->bucket = 0;
state->pos = 0;
/* HACK: till there is state we can pass to seq_show... */
seq->private = (void *)1;
rc = pneigh_get_bucket(pos);
*pos = 0;
rc = pneigh_get_bucket(seq, pos);
}
return rc;
}
......@@ -146,33 +142,31 @@ static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
goto out;
}
state = (struct arp_iter_state *)pos;
state = seq->private;
if (!state->is_pneigh) {
struct neighbour *n = v;
rc = n = n->next;
if (n)
goto out;
state->pos = 0;
*pos = 0;
++state->bucket;
rc = neigh_get_bucket(pos);
rc = neigh_get_bucket(seq, pos);
if (rc)
goto out;
read_unlock_bh(&arp_tbl.lock);
/* HACK: till there is state we can pass to seq_show... */
seq->private = (void *)1;
state->is_pneigh = 1;
state->bucket = 0;
state->pos = 0;
rc = pneigh_get_bucket(pos);
*pos = 0;
rc = pneigh_get_bucket(seq, pos);
} else {
struct pneigh_entry *pn = v;
pn = pn->next;
if (!pn) {
++state->bucket;
state->pos = 0;
pn = pneigh_get_bucket(pos);
*pos = 0;
pn = pneigh_get_bucket(seq, pos);
}
rc = pn;
}
......@@ -183,7 +177,9 @@ static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void arp_seq_stop(struct seq_file *seq, void *v)
{
if (!seq->private)
struct arp_iter_state* state = seq->private;
if (!state->is_pneigh)
read_unlock_bh(&arp_tbl.lock);
}
......@@ -241,7 +237,9 @@ static int arp_seq_show(struct seq_file *seq, void *v)
seq_puts(seq, "IP address HW type Flags "
"HW address Mask Device\n");
else {
if (seq->private)
struct arp_iter_state* state = seq->private;
if (state->is_pneigh)
arp_format_pneigh_entry(seq, v);
else
arp_format_neigh_entry(seq, v);
......@@ -405,7 +403,35 @@ static struct seq_operations udp_seq_ops = {
static int arp_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &arp_seq_ops);
struct seq_file *seq;
int rc = -ENOMEM;
struct arp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &arp_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
static int arp_seq_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = (struct seq_file *)file->private_data;
kfree(seq->private);
seq->private = NULL;
return seq_release(inode, file);
}
static int fib_seq_open(struct inode *inode, struct file *file)
......@@ -422,7 +448,7 @@ static struct file_operations arp_seq_fops = {
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.release = arp_seq_release,
};
static struct file_operations fib_seq_fops = {
......
......@@ -1188,7 +1188,6 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
skb->nh.iph->saddr, /*XXX*/
sizeof(struct tcphdr), IPPROTO_TCP, 0);
arg.n_iov = 1;
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
inet_sk(tcp_socket->sk)->ttl = sysctl_ip_default_ttl;
......@@ -1217,7 +1216,6 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
arg.iov[0].iov_base = (unsigned char *)&rep;
arg.iov[0].iov_len = sizeof(rep.th);
arg.n_iov = 1;
if (ts) {
rep.tsopt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
(TCPOPT_TIMESTAMP << 8) |
......
......@@ -484,7 +484,7 @@ static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned i
if (skb->ip_summed == CHECKSUM_HW) {
skb->csum = offsetof(struct udphdr, check);
ufh->uh.check = ~csum_tcpudp_magic(ufh->saddr, ufh->daddr,
ntohs(ufh->uh.len), IPPROTO_UDP, ufh->wcheck);
ntohs(ufh->uh.len), IPPROTO_UDP, 0);
memcpy(to, ufh, sizeof(struct udphdr));
return memcpy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset,
fraglen-sizeof(struct udphdr));
......@@ -730,7 +730,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
do_append_data:
up->len += ulen;
err = ip_append_data(sk, generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), &ipc, rt, msg->msg_flags);
err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
sizeof(struct udphdr), &ipc, rt,
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
if (err)
udp_flush_pending_frames(sk);
else if (!corkreq)
......@@ -1122,7 +1124,9 @@ int udp_rcv(struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(struct udphdr)))
goto no_header;
ulen = ntohs(skb->h.uh->len);
uh = skb->h.uh;
ulen = ntohs(uh->len);
if (ulen > len || ulen < sizeof(*uh))
goto short_packet;
......@@ -1130,8 +1134,6 @@ int udp_rcv(struct sk_buff *skb)
if (pskb_trim(skb, ulen))
goto short_packet;
uh = skb->h.uh;
if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
goto csum_error;
......@@ -1161,7 +1163,14 @@ int udp_rcv(struct sk_buff *skb)
return(0);
short_packet:
NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
NETDEBUG(if (net_ratelimit())
printk(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
NIPQUAD(saddr),
ntohs(uh->source),
ulen,
len,
NIPQUAD(daddr),
ntohs(uh->dest)));
no_header:
UDP_INC_STATS_BH(UdpInErrors);
kfree_skb(skb);
......
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