Commit 4cc42719 authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge us.ibm.com:/home/sridhar/BK/linux-2.5.56

into us.ibm.com:/home/sridhar/BK/lksctp-2.5.56
parents efa0596f ea5d287f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
*
* This file is part of the SCTP kernel reference Implementation
......@@ -37,6 +37,7 @@
* Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -147,7 +148,9 @@ extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
/*
* sctp_crc32c.c
*/
extern __u32 count_crc(__u8 *ptr, __u16 count);
extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
extern __u32 sctp_end_cksum(__u32 cksum);
/*
* sctp_input.c
......
......@@ -100,6 +100,14 @@ enum sctp_optname {
#define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM
SCTP_SOCKOPT_PEELOFF, /* peel off association. */
#define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF
SCTP_GET_PEER_ADDRS_NUM, /* Get number of peer addresss. */
#define SCTP_GET_PEER_ADDRS_NUM SCTP_GET_PEER_ADDRS_NUM
SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */
#define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS
SCTP_GET_LOCAL_ADDRS_NUM, /* Get number of local addresss. */
#define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM
SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
};
......@@ -576,6 +584,15 @@ struct sctp_setstrm_timeout {
__u16 ssto_streamid_end;
};
/*
* 8.3 8.5 get all peer/local addresses on a socket
* This parameter struct is for getsockopt
*/
struct sctp_getaddrs {
sctp_assoc_t assoc_id;
int addr_num;
struct sockaddr_storage *addrs;
};
/* These are bit fields for msghdr->msg_flags. See section 5.1. */
/* On user space Linux, these live in <bits/socket.h> as an enum. */
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -36,6 +37,7 @@
* Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -122,7 +124,7 @@ unsigned long update_adler32(unsigned long adler,
return (s2 << 16) + s1;
}
__u32 count_crc(__u8 *ptr, __u16 count)
__u32 sctp_start_cksum(__u8 *ptr, __u16 count)
{
/*
* Update a running Adler-32 checksum with the bytes
......@@ -146,3 +148,15 @@ __u32 count_crc(__u8 *ptr, __u16 count)
return adler;
}
__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler)
{
adler = update_adler32(adler, ptr, count);
return adler;
}
__u32 sctp_end_cksum(__u32 adler)
{
return adler;
}
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -33,6 +33,7 @@
* Written or modified by:
* Dinakaran Joseph
* Jon Grimm <jgrimm@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -135,11 +136,10 @@ __u32 crc_c[256] = {
0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
};
__u32 count_crc(__u8 *buffer, __u16 length)
__u32 sctp_start_cksum(__u8 *buffer, __u16 length)
{
__u32 crc32 = ~(__u32) 0;
__u32 i, result;
__u8 byte0, byte1, byte2, byte3;
__u32 i;
/* Optimize this routine to be SCTP specific, knowing how
* to skip the checksum field of the SCTP header.
......@@ -157,6 +157,24 @@ __u32 count_crc(__u8 *buffer, __u16 length)
for (i = sizeof(struct sctphdr); i < length ; i++)
CRC32C(crc32, buffer[i]);
return crc32;
}
__u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32)
{
__u32 i;
for (i = 0; i < length ; i++)
CRC32C(crc32, buffer[i]);
return crc32;
}
__u32 sctp_end_cksum(__u32 crc32)
{
__u32 result;
__u8 byte0, byte1, byte2, byte3;
result = ~crc32;
/* result now holds the negated polynomial remainder;
......@@ -183,5 +201,3 @@ __u32 count_crc(__u8 *buffer, __u16 length)
byte3);
return crc32;
}
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
......@@ -72,10 +72,19 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
{
struct sctphdr *sh;
__u32 cmp, val;
struct sk_buff *list = skb_shinfo(skb)->frag_list;
sh = (struct sctphdr *) skb->h.raw;
cmp = ntohl(sh->checksum);
val = count_crc((__u8 *)sh, skb->len);
val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb));
for (; list; list = list->next)
val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list),
val);
val = sctp_end_cksum(val);
if (val != cmp) {
/* CRC failure, dump it. */
return -1;
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -62,7 +62,6 @@
#include <net/sctp/sm.h>
/* Forward declarations for private helpers. */
__u32 count_crc(__u8 *ptr, __u16 count);
static void sctp_packet_reset(sctp_packet_t *packet);
static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
sctp_chunk_t *chunk);
......@@ -358,7 +357,8 @@ int sctp_packet_transmit(sctp_packet_t *packet)
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32 = count_crc((__u8 *)sh, nskb->len);
crc32 = sctp_start_cksum((__u8 *)sh, nskb->len);
crc32 = sctp_end_cksum(crc32);
/* 3) Put the resultant value into the checksum field in the
* common header, and leave the rest of the bits unchanged.
......
......@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
* Copyright (c) 2001-2003 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -374,6 +374,18 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
continue;
}
#endif
/* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the
* way and into a 'transmitted' queue and skip to the
* next chunk.
*/
if (chunk->tsn_gap_acked) {
list_add_tail(lchunk, &transport->transmitted);
lchunk = sctp_list_dequeue(lqueue);
continue;
}
/* Attempt to append this chunk to the packet. */
status = (*q->append_output)(pkt, chunk);
......
......@@ -49,7 +49,7 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
sctp_sm_table_entry_t bug = {
static sctp_sm_table_entry_t bug = {
.fn = sctp_sf_bug,
.name = "sctp_sf_bug"
};
......
/* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001-2003 Intel Corp.
* Copyright (c) 2001-2002 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
......@@ -47,6 +47,7 @@
* Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <samudrala@us.ibm.com>
* Inaky Perez-Gonzalez <inaky.gonzalez@intel.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -1091,18 +1092,25 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
static int sctp_skb_pull(struct sk_buff *skb, int len)
{
struct sk_buff *list;
int skb_len = skb_headlen(skb);
int rlen;
if (len <= skb->len) {
if (len <= skb_len) {
__skb_pull(skb, len);
return 0;
}
len -= skb->len;
__skb_pull(skb, skb->len);
len -= skb_len;
__skb_pull(skb, skb_len);
for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
len = sctp_skb_pull(list, len);
if (!len)
rlen = sctp_skb_pull(list, len);
skb->len -= (len-rlen);
skb->data_len -= (len-rlen);
if (!rlen)
return 0;
len = rlen;
}
return len;
......@@ -1130,7 +1138,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
{
sctp_ulpevent_t *event = NULL;
sctp_opt_t *sp = sctp_sk(sk);
struct sk_buff *skb, *list;
struct sk_buff *skb;
int copied;
int err = 0;
int skb_len;
......@@ -1154,8 +1162,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
* frag_list.
*/
skb_len = skb->len;
for (list = skb_shinfo(skb)->frag_list; list; list = list->next)
skb_len += list->len;
copied = skb_len;
if (copied > len)
......@@ -1932,6 +1938,166 @@ static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval
return 0;
}
static inline int sctp_getsockopt_get_peer_addrs_num(struct sock *sk, int len,
char *optval, int *optlen)
{
sctp_assoc_t id;
sctp_association_t *asoc;
struct list_head *pos;
int cnt = 0;
if (len != sizeof(sctp_assoc_t))
return -EINVAL;
if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
return -EFAULT;
/*
* For UDP-style sockets, id specifies the association to query.
*/
asoc = sctp_id2assoc(sk, id);
if (!asoc)
return -EINVAL;
list_for_each(pos, &asoc->peer.transport_addr_list) {
cnt ++;
}
if (copy_to_user(optval, &cnt, sizeof(int)))
return -EFAULT;
return 0;
}
static inline int sctp_getsockopt_get_peer_addrs(struct sock *sk, int len,
char *optval, int *optlen)
{
sctp_association_t *asoc;
struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs getaddrs;
sctp_transport_t *from;
struct sockaddr_storage *to;
if (len != sizeof(struct sctp_getaddrs))
return -EINVAL;
if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
return -EFAULT;
if (getaddrs.addr_num <= 0) return -EINVAL;
/*
* For UDP-style sockets, id specifies the association to query.
*/
asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc)
return -EINVAL;
to = getaddrs.addrs;
list_for_each(pos, &asoc->peer.transport_addr_list) {
from = list_entry(pos, sctp_transport_t, transports);
if (copy_to_user(to, &from->ipaddr, sizeof(from->ipaddr)))
return -EFAULT;
to ++;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
}
getaddrs.addr_num = cnt;
if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
return -EFAULT;
return 0;
}
static inline int sctp_getsockopt_get_local_addrs_num(struct sock *sk, int len,
char *optval, int *optlen)
{
sctp_assoc_t id;
sctp_bind_addr_t *bp;
sctp_association_t *asoc;
struct list_head *pos;
int cnt = 0;
if (len != sizeof(sctp_assoc_t))
return -EINVAL;
if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
return -EFAULT;
/*
* For UDP-style sockets, id specifies the association to query.
* If the id field is set to the value '0' then the locally bound
* addresses are returned without regard to any particular
* association.
*/
if (0 == id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
} else {
asoc = sctp_id2assoc(sk, id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
}
list_for_each(pos, &bp->address_list) {
cnt ++;
}
if (copy_to_user(optval, &cnt, sizeof(int)))
return -EFAULT;
return 0;
}
static inline int sctp_getsockopt_get_local_addrs(struct sock *sk, int len,
char *optval, int *optlen)
{
sctp_bind_addr_t *bp;
sctp_association_t *asoc;
struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs getaddrs;
struct sockaddr_storage_list *from;
struct sockaddr_storage *to;
if (len != sizeof(struct sctp_getaddrs))
return -EINVAL;
if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
return -EFAULT;
if (getaddrs.addr_num <= 0) return -EINVAL;
/*
* For UDP-style sockets, id specifies the association to query.
* If the id field is set to the value '0' then the locally bound
* addresses are returned without regard to any particular
* association.
*/
if (0 == getaddrs.assoc_id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
} else {
asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
}
to = getaddrs.addrs;
list_for_each(pos, &bp->address_list) {
from = list_entry(pos,
struct sockaddr_storage_list,
list);
if (copy_to_user(to, &from->a, sizeof(from->a)))
return -EFAULT;
to ++;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
}
getaddrs.addr_num = cnt;
if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
return -EFAULT;
return 0;
}
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char *optval, int *optlen)
{
......@@ -1989,6 +2155,26 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
break;
case SCTP_GET_PEER_ADDRS_NUM:
retval = sctp_getsockopt_get_peer_addrs_num(sk, len, optval,
optlen);
break;
case SCTP_GET_LOCAL_ADDRS_NUM:
retval = sctp_getsockopt_get_local_addrs_num(sk, len, optval,
optlen);
break;
case SCTP_GET_PEER_ADDRS:
retval = sctp_getsockopt_get_peer_addrs(sk, len, optval,
optlen);
break;
case SCTP_GET_LOCAL_ADDRS:
retval = sctp_getsockopt_get_local_addrs(sk, len, optval,
optlen);
break;
default:
retval = -ENOPROTOOPT;
break;
......
......@@ -606,9 +606,9 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_chunk_t *chunk, int priority)
{
sctp_ulpevent_t *event;
sctp_ulpevent_t *event, *levent;
struct sctp_sndrcvinfo *info;
struct sk_buff *skb;
struct sk_buff *skb, *list;
size_t padding, len;
/* Clone the original skb, sharing the data. */
......@@ -647,6 +647,16 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
event->malloced = 1;
for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
sctp_ulpevent_set_owner_r(list, asoc);
/* Initialize event with flags 0. */
levent = sctp_ulpevent_init(event, skb, 0);
if (!levent)
goto fail_init;
levent->malloced = 1;
}
info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo;
/* Sockets API Extensions for SCTP
......@@ -764,6 +774,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
sctp_ulpevent_t *event;
sctp_chunk_t *sack;
struct timer_list *timer;
int skb_len = skb_headlen(skb);
/* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as
......@@ -774,18 +785,18 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
event = (sctp_ulpevent_t *) skb->cb;
asoc = event->asoc;
if (asoc->rwnd_over) {
if (asoc->rwnd_over >= skb->len) {
asoc->rwnd_over -= skb->len;
if (asoc->rwnd_over >= skb_len) {
asoc->rwnd_over -= skb_len;
} else {
asoc->rwnd += (skb->len - asoc->rwnd_over);
asoc->rwnd += (skb_len - asoc->rwnd_over);
asoc->rwnd_over = 0;
}
} else {
asoc->rwnd += skb->len;
asoc->rwnd += skb_len;
}
SCTP_DEBUG_PRINTK("rwnd increased by %d to (%u, %u) - %u\n",
skb->len, asoc->rwnd, asoc->rwnd_over, asoc->a_rwnd);
skb_len, asoc->rwnd, asoc->rwnd_over, asoc->a_rwnd);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
......@@ -824,6 +835,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc)
{
sctp_ulpevent_t *event;
int skb_len = skb_headlen(skb);
/* The current stack structures assume that the rcv buffer is
* per socket. For UDP-style sockets this is not true as
......@@ -840,14 +852,14 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
SCTP_ASSERT(asoc->rwnd, "rwnd zero", return);
SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return);
if (asoc->rwnd >= skb->len) {
asoc->rwnd -= skb->len;
if (asoc->rwnd >= skb_len) {
asoc->rwnd -= skb_len;
} else {
asoc->rwnd_over = skb->len - asoc->rwnd;
asoc->rwnd_over = skb_len - asoc->rwnd;
asoc->rwnd = 0;
}
SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n",
skb->len, asoc->rwnd, asoc->rwnd_over);
skb_len, asoc->rwnd, asoc->rwnd_over);
}
/* A simple destructor to give up the reference to the association. */
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
......@@ -233,16 +233,30 @@ static inline void sctp_ulpqueue_store_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpeven
/* Helper function to return an event corresponding to the reassembled
* datagram.
* This routine creates a re-assembled skb given the first and last skb's
* as stored in the reassembly queue. The skb's may be non-linear if the sctp
* payload was fragmented on the way and ip had to reassemble them.
* We add the rest of skb's to the first skb's fraglist.
*/
static inline sctp_ulpevent_t *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag)
{
struct sk_buff *pos;
sctp_ulpevent_t *event;
struct sk_buff *pnext;
struct sk_buff *pnext, *last;
struct sk_buff *list = skb_shinfo(f_frag)->frag_list;
/* Store the pointer to the 2nd skb */
pos = f_frag->next;
/* Set the first fragment's frag_list to point to the 2nd fragment. */
/* Get the last skb in the f_frag's frag_list if present. */
for (last = list; list; last = list,list = list->next);
/* Add the list of remaining fragments to the first fragments
* frag_list.
*/
if (last)
last->next = pos;
else
skb_shinfo(f_frag)->frag_list = pos;
/* Remove the first fragment from the reassembly queue. */
......@@ -250,6 +264,10 @@ static inline sctp_ulpevent_t *sctp_make_reassembled_event(struct sk_buff *f_fra
do {
pnext = pos->next;
/* Update the len and data_len fields of the first fragment. */
f_frag->len += pos->len;
f_frag->data_len += pos->len;
/* Remove the fragment from the reassembly queue. */
__skb_unlink(pos, pos->list);
......
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