diff options
| author | Sridhar Samudrala <sridhar@dyn9-47-18-140.beaverton.ibm.com> | 2002-12-09 23:38:17 -0800 |
|---|---|---|
| committer | Sridhar Samudrala <sridhar@dyn9-47-18-140.beaverton.ibm.com> | 2002-12-09 23:38:17 -0800 |
| commit | d12add250df948e7e24068a62ba729daf4073ace (patch) | |
| tree | 68dc47fbc0e5e8181216ecd0c46d3711dfc38b0f | |
| parent | 8b4ad80b8236a20584f7956ff42c7a3bdf1d018e (diff) | |
| parent | 8051ff93f063e1fc5808c72d5f49087f8c2eefe5 (diff) | |
Merge dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/linux-2.5.51
into dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/lksctp-2.5.51
| -rw-r--r-- | include/linux/sysctl.h | 3 | ||||
| -rw-r--r-- | include/net/sctp/sctp.h | 4 | ||||
| -rw-r--r-- | include/net/sctp/sm.h | 13 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 26 | ||||
| -rw-r--r-- | net/sctp/associola.c | 7 | ||||
| -rw-r--r-- | net/sctp/bind_addr.c | 4 | ||||
| -rw-r--r-- | net/sctp/input.c | 9 | ||||
| -rw-r--r-- | net/sctp/ipv6.c | 188 | ||||
| -rw-r--r-- | net/sctp/protocol.c | 150 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 60 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 28 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 194 | ||||
| -rw-r--r-- | net/sctp/sm_statetable.c | 2 | ||||
| -rw-r--r-- | net/sctp/socket.c | 346 | ||||
| -rw-r--r-- | net/sctp/sysctl.c | 5 | ||||
| -rw-r--r-- | net/sctp/transport.c | 2 |
16 files changed, 608 insertions, 433 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index e70fc2ef0856..47d74c442191 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -543,7 +543,8 @@ enum { NET_SCTP_PATH_MAX_RETRANS = 8, NET_SCTP_MAX_INIT_RETRANSMITS = 9, NET_SCTP_HB_INTERVAL = 10, - NET_SCTP_MAX_BURST = 11, + NET_SCTP_PRESERVE_ENABLE = 11, + NET_SCTP_MAX_BURST = 12, }; /* CTL_PROC names: */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 73c948813e72..f12e54cd4919 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -123,8 +123,8 @@ extern sctp_protocol_t sctp_proto; extern struct sock *sctp_get_ctl_sock(void); extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, sctp_scope_t, int priority, int flags); -extern sctp_pf_t *sctp_get_pf_specific(int family); -extern void sctp_set_pf_specific(int family, sctp_pf_t *); +extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); +extern int sctp_register_pf(struct sctp_pf *, sa_family_t); /* * sctp_socket.c diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index e811bf37e4ca..68af144ef56c 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -140,6 +140,8 @@ sctp_state_fn_t sctp_sf_do_5_2_2_dupinit; sctp_state_fn_t sctp_sf_do_5_2_4_dupcook; sctp_state_fn_t sctp_sf_unk_chunk; sctp_state_fn_t sctp_sf_do_8_5_1_E_sa; +sctp_state_fn_t sctp_sf_cookie_echoed_err; +sctp_state_fn_t sctp_sf_do_5_2_6_stale; /* Prototypes for primitive event state functions. */ sctp_state_fn_t sctp_sf_do_prm_asoc; @@ -175,7 +177,6 @@ sctp_state_fn_t sctp_sf_autoclose_timer_expire; */ /* Prototypes for chunk state functions. Not in use. */ -sctp_state_fn_t sctp_sf_do_5_2_6_stale; sctp_state_fn_t sctp_sf_do_9_2_reshutack; sctp_state_fn_t sctp_sf_do_9_2_reshut; sctp_state_fn_t sctp_sf_do_9_2_shutack; @@ -211,7 +212,7 @@ void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); /* Prototypes for chunk-building functions. */ sctp_chunk_t *sctp_make_init(const sctp_association_t *, const sctp_bind_addr_t *, - int priority); + int priority, int vparam_len); sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, const sctp_chunk_t *, const int priority, @@ -322,9 +323,15 @@ sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, const __u8 *, int addrs_len); sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, const sctp_association_t *, - sctp_chunk_t *, int priority, int *err); + sctp_chunk_t *, int priority, int *err, + sctp_chunk_t **err_chk_p); int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, struct sockaddr_storage*, int); +void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_chunk_t *err_chunk); /* 3rd level prototypes */ __u32 sctp_generate_tag(const sctp_endpoint_t *); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index d7b5674bdbdc..fc4a3f1a3b4c 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -42,6 +42,7 @@ * Sridhar Samudrala <sri@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com> * Dajiang Zhang <dajiang.zhang@nokia.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. @@ -182,6 +183,9 @@ struct SCTP_protocol { /* Valid.Cookie.Life - 60 seconds */ int valid_cookie_life; + + /* Whether Cookie Preservative is enabled(1) or not(0) */ + int cookie_preserve_enable; /* Association.Max.Retrans - 10 attempts * Path.Max.Retrans - 5 attempts (per destination address) @@ -234,7 +238,7 @@ struct SCTP_protocol { * Pointers to address related SCTP functions. * (i.e. things that depend on the address family.) */ -typedef struct sctp_func { +struct sctp_af { int (*queue_xmit) (struct sk_buff *skb); int (*setsockopt) (struct sock *sk, int level, @@ -259,27 +263,34 @@ typedef struct sctp_func { void (*from_skb) (union sctp_addr *, struct sk_buff *skb, int saddr); + void (*from_sk) (union sctp_addr *, + struct sock *sk); + void (*to_sk) (union sctp_addr *, + struct sock *sk); int (*addr_valid) (union sctp_addr *); sctp_scope_t (*scope) (union sctp_addr *); void (*inaddr_any) (union sctp_addr *, unsigned short); int (*is_any) (const union sctp_addr *); + int (*available) (const union sctp_addr *); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; struct list_head list; -} sctp_func_t; +}; -sctp_func_t *sctp_get_af_specific(sa_family_t); +struct sctp_af *sctp_get_af_specific(sa_family_t); +int sctp_register_af(struct sctp_af *); /* Protocol family functions. */ typedef struct sctp_pf { void (*event_msgname)(sctp_ulpevent_t *, char *, int *); - void (*skb_msgname)(struct sk_buff *, char *, int *); - int (*af_supported)(sa_family_t); + void (*skb_msgname) (struct sk_buff *, char *, int *); + int (*af_supported) (sa_family_t); int (*cmp_addr) (const union sctp_addr *, const union sctp_addr *, struct sctp_opt *); - struct sctp_func *af; + int (*bind_verify) (struct sctp_opt *, union sctp_addr *); + struct sctp_af *af; } sctp_pf_t; /* SCTP Socket type: UDP or TCP style. */ @@ -623,7 +634,7 @@ struct SCTP_transport { union sctp_addr ipaddr; /* These are the functions we call to handle LLP stuff. */ - sctp_func_t *af_specific; + struct sctp_af *af_specific; /* Which association do we belong to? */ sctp_association_t *asoc; @@ -1271,7 +1282,6 @@ struct SCTP_association { /* The cookie life I award for any cookie. */ struct timeval cookie_life; - __u32 cookie_preserve; /* Overall : The overall association error count. * Error Count : [Clear this any time I get something.] diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 7736677f2d22..e61cf97204f3 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -128,8 +128,9 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, asoc->state_timestamp = jiffies; /* Set things that have constant value. */ - asoc->cookie_life.tv_sec = SCTP_DEFAULT_COOKIE_LIFE_SEC; - asoc->cookie_life.tv_usec = SCTP_DEFAULT_COOKIE_LIFE_USEC; + asoc->cookie_life.tv_sec = sctp_proto.valid_cookie_life / HZ; + asoc->cookie_life.tv_usec = (sctp_proto.valid_cookie_life % HZ) * + 1000000L / HZ; asoc->pmtu = 0; asoc->frag_point = 0; @@ -642,7 +643,7 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) int sctp_cmp_addr_exact(const union sctp_addr *ss1, const union sctp_addr *ss2) { - struct sctp_func *af; + struct sctp_af *af; af = sctp_get_af_specific(ss1->sa.sa_family); if (!af) diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 7a78fdb5d7ff..2ae655f2c775 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -327,7 +327,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, /* Is this a wildcard address? */ int sctp_is_any(const union sctp_addr *addr) { - struct sctp_func *af = sctp_get_af_specific(addr->sa.sa_family); + struct sctp_af *af = sctp_get_af_specific(addr->sa.sa_family); if (!af) return 0; return af->is_any(addr); @@ -362,7 +362,7 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) /* What is the scope of 'addr'? */ sctp_scope_t sctp_scope(const union sctp_addr *addr) { - struct sctp_func *af; + struct sctp_af *af; af = sctp_get_af_specific(addr->sa.sa_family); if (!af) diff --git a/net/sctp/input.c b/net/sctp/input.c index cf9e54b99283..d6e64da75733 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -42,6 +42,7 @@ * Hui Huang <hui.huang@nokia.com> * Daisy Chang <daisyc@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.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. @@ -96,7 +97,7 @@ int sctp_rcv(struct sk_buff *skb) struct sctphdr *sh; union sctp_addr src; union sctp_addr dest; - struct sctp_func *af; + struct sctp_af *af; int ret = 0; if (skb->pkt_type!=PACKET_HOST) @@ -279,6 +280,7 @@ int sctp_rcv_ootb(struct sk_buff *skb) { sctp_chunkhdr_t *ch; __u8 *ch_end; + sctp_errhdr_t *err; ch = (sctp_chunkhdr_t *) skb->data; @@ -308,8 +310,9 @@ int sctp_rcv_ootb(struct sk_buff *skb) goto discard; if (ch->type == SCTP_CID_ERROR) { - /* FIXME - Need to check the "Stale cookie" ERROR. */ - goto discard; + err = (sctp_errhdr_t *)(ch + sizeof(sctp_chunkhdr_t)); + if (SCTP_ERROR_STALE_COOKIE == err->cause) + goto discard; } ch = (sctp_chunkhdr_t *) ch_end; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 1391167e9709..6c48dcc3ef50 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -76,8 +76,19 @@ #include <asm/uaccess.h> -/* FIXME: Cleanup so we don't need TEST_FRAME here. */ -#ifndef TEST_FRAME +extern struct notifier_block sctp_inetaddr_notifier; + +/* FIXME: This macro needs to be moved to a common header file. */ +#define NIP6(addr) \ + ntohs((addr)->s6_addr16[0]), \ + ntohs((addr)->s6_addr16[1]), \ + ntohs((addr)->s6_addr16[2]), \ + ntohs((addr)->s6_addr16[3]), \ + ntohs((addr)->s6_addr16[4]), \ + ntohs((addr)->s6_addr16[5]), \ + ntohs((addr)->s6_addr16[6]), \ + ntohs((addr)->s6_addr16[7]) + /* FIXME: Comments. */ static inline void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, @@ -92,13 +103,38 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) struct sock *sk = skb->sk; struct ipv6_pinfo *np = inet6_sk(sk); struct flowi fl; - struct dst_entry *dst; + struct dst_entry *dst = skb->dst; + struct rt6_info *rt6 = (struct rt6_info *)dst; struct in6_addr saddr; - int err = 0; + int err; fl.proto = sk->protocol; - fl.fl6_dst = &np->daddr; - fl.fl6_src = NULL; + fl.fl6_dst = &rt6->rt6i_dst.addr; + + /* FIXME: Currently, ip6_route_output() doesn't fill in the source + * address in the returned route entry. So we call ipv6_get_saddr() + * to get an appropriate source address. It is possible that this address + * may not be part of the bind address list of the association. + * Once ip6_route_ouput() is fixed so that it returns a route entry + * with an appropriate source address, the following if condition can + * be removed. With ip6_route_output() returning a source address filled + * route entry, sctp_transport_route() can do real source address + * selection for v6. + */ + if (ipv6_addr_any(&rt6->rt6i_src.addr)) { + err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); + + if (err) { + printk(KERN_ERR "%s: No saddr available for " + "DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + __FUNCTION__, NIP6(fl.fl6_src)); + return err; + } + + fl.fl6_src = &saddr; + } else { + fl.fl6_src = &rt6->rt6i_src.addr; + } fl.fl6_flowlabel = np->flow_label; IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); @@ -111,63 +147,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) fl.nl_u.ip6_u.daddr = rt0->addr; } - dst = __sk_dst_check(sk, np->dst_cookie); - - if (dst == NULL) { - dst = ip6_route_output(sk, &fl); - - if (dst->error) { - sk->err_soft = -dst->error; - dst_release(dst); - return -sk->err_soft; - } - ip6_dst_store(sk, dst, NULL); - } - - skb->dst = dst_clone(dst); - - /* FIXME: This is all temporary until real source address - * selection is done. - */ - if (ipv6_addr_any(&np->saddr)) { - err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); - - if (err) - printk(KERN_ERR "sctp_v6_xmit: no saddr available\n"); - - /* FIXME: This is a workaround until we get - * real source address selection done. This is here - * to disallow loopback when the scoping rules have - * not bound loopback to the endpoint. - */ - if (sctp_ipv6_addr_type(&saddr) & IPV6_ADDR_LOOPBACK) { - if (!(sctp_ipv6_addr_type(&np->daddr) & - IPV6_ADDR_LOOPBACK)) { - ipv6_addr_copy(&saddr, &np->daddr); - } - } - fl.fl6_src = &saddr; - } else { - fl.fl6_src = &np->saddr; - } - - /* Restore final destination back after routing done */ - fl.nl_u.ip6_u.daddr = &np->daddr; - return ip6_xmit(sk, skb, &fl, np->opt); } -#endif /* TEST_FRAME */ - -/* FIXME: This macro needs to be moved to a common header file. */ -#define NIP6(addr) \ - ntohs((addr)->s6_addr16[0]), \ - ntohs((addr)->s6_addr16[1]), \ - ntohs((addr)->s6_addr16[2]), \ - ntohs((addr)->s6_addr16[3]), \ - ntohs((addr)->s6_addr16[4]), \ - ntohs((addr)->s6_addr16[5]), \ - ntohs((addr)->s6_addr16[6]), \ - ntohs((addr)->s6_addr16[7]) /* Returns the dst cache entry for the given source and destination ip * addresses. @@ -176,7 +157,7 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, union sctp_addr *saddr) { struct dst_entry *dst; - struct flowi fl = { + struct flowi fl = { .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } }; @@ -261,6 +242,20 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, ipv6_addr_copy(&addr->v6.sin6_addr, from); } +/* Initialize an sctp_addr from a socket. */ +static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) +{ + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = inet_sk(sk)->num; + addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr; +} + +/* Initialize sk->rcv_saddr from sctp_addr. */ +static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk) +{ + inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; +} + /* Initialize a sctp_addr from a dst_entry. */ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst) { @@ -270,15 +265,15 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst) } /* Compare addresses exactly. Well.. almost exactly; ignore scope_id - * for now. FIXME. + * for now. FIXME: v4-mapped-v6. */ -static int sctp_v6_cmp_addr(const union sctp_addr *addr1, +static int sctp_v6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2) { int match; if (addr1->sa.sa_family != addr2->sa.sa_family) return 0; - match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr, + match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr, (struct in6_addr *)&addr2->v6.sin6_addr); return match; @@ -300,6 +295,22 @@ static int sctp_v6_is_any(const union sctp_addr *addr) return IPV6_ADDR_ANY == type; } +/* Should this be available for binding? */ +static int sctp_v6_available(const union sctp_addr *addr) +{ + int type; + struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; + + type = ipv6_addr_type(in6); + if (IPV6_ADDR_ANY == type) + return 1; + if (!(type & IPV6_ADDR_UNICAST)) + return 0; + + return ipv6_chk_addr(in6, NULL); +} + + /* This function checks if the address is a valid address to be used for * SCTP. * @@ -309,7 +320,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) */ static int sctp_v6_addr_valid(union sctp_addr *addr) { - int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); + int ret = ipv6_addr_type(&addr->v6.sin6_addr); /* FIXME: v4-mapped-v6 address support. */ @@ -442,14 +453,14 @@ static int sctp_inet6_af_supported(sa_family_t family) /* Address matching with wildcards allowed. This extra level * of indirection lets us choose whether a PF_INET6 should - * disallow any v4 addresses if we so choose. + * disallow any v4 addresses if we so choose. */ -static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, +static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2, struct sctp_opt *opt) { - struct sctp_func *af1, *af2; - + struct sctp_af *af1, *af2; + af1 = sctp_get_af_specific(addr1->sa.sa_family); af2 = sctp_get_af_specific(addr2->sa.sa_family); @@ -461,11 +472,25 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, if (addr1->sa.sa_family != addr2->sa.sa_family) return 0; - + return af1->cmp_addr(addr1, addr2); } +/* Verify that the provided sockaddr looks bindable. Common verification, + * has already been taken care of. + */ +static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) +{ + struct sctp_af *af; + + /* ASSERT: address family has already been verified. */ + if (addr->sa.sa_family != AF_INET6) { + af = sctp_get_af_specific(addr->sa.sa_family); + } else + af = opt->pf->af; + return af->available(addr); +} static struct proto_ops inet6_seqpacket_ops = { .family = PF_INET6, @@ -501,29 +526,33 @@ static struct inet6_protocol sctpv6_protocol = { .err_handler = sctp_v6_err, }; -static sctp_func_t sctp_ipv6_specific = { +static struct sctp_af sctp_ipv6_specific = { .queue_xmit = sctp_v6_xmit, - .setsockopt = ipv6_setsockopt, + .setsockopt = ipv6_setsockopt, .getsockopt = ipv6_getsockopt, .get_dst = sctp_v6_get_dst, .copy_addrlist = sctp_v6_copy_addrlist, .from_skb = sctp_v6_from_skb, + .from_sk = sctp_v6_from_sk, + .to_sk = sctp_v6_to_sk, .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, .inaddr_any = sctp_v6_inaddr_any, .is_any = sctp_v6_is_any, + .available = sctp_v6_available, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, }; -static sctp_pf_t sctp_pf_inet6_specific = { +static struct sctp_pf sctp_pf_inet6_specific = { .event_msgname = sctp_inet6_event_msgname, .skb_msgname = sctp_inet6_skb_msgname, .af_supported = sctp_inet6_af_supported, .cmp_addr = sctp_inet6_cmp_addr, + .bind_verify = sctp_inet6_bind_verify, .af = &sctp_ipv6_specific, }; @@ -538,11 +567,13 @@ int sctp_v6_init(void) inet6_register_protosw(&sctpv6_protosw); /* Register the SCTP specfic PF_INET6 functions. */ - sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific); + sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6); + + /* Register the SCTP specfic AF_INET6 functions. */ + sctp_register_af(&sctp_ipv6_specific); - /* Fill in address family info. */ - INIT_LIST_HEAD(&sctp_ipv6_specific.list); - list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families); + /* Register notifier for inet6 address additions/deletions. */ + register_inet6addr_notifier(&sctp_inetaddr_notifier); return 0; } @@ -553,4 +584,5 @@ void sctp_v6_exit(void) list_del(&sctp_ipv6_specific.list); inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP); inet6_unregister_protosw(&sctpv6_protosw); + unregister_inet6addr_notifier(&sctp_inetaddr_notifier); } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index cc45fe85c46d..fde475e70359 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -40,6 +40,7 @@ * Jon Grimm <jgrimm@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com> * Daisy Chang <daisyc@us.ibm.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. @@ -67,8 +68,10 @@ struct sctp_mib sctp_statistics[NR_CPUS * 2]; */ static struct socket *sctp_ctl_socket; -static sctp_pf_t *sctp_pf_inet6_specific; -static sctp_pf_t *sctp_pf_inet_specific; +static struct sctp_pf *sctp_pf_inet6_specific; +static struct sctp_pf *sctp_pf_inet_specific; +static struct sctp_af *sctp_af_v4_specific; +static struct sctp_af *sctp_af_v6_specific; extern struct net_proto_family inet_family_ops; @@ -140,12 +143,12 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto) { struct net_device *dev; struct list_head *pos; - struct sctp_func *af; + struct sctp_af *af; read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { list_for_each(pos, &proto->address_families) { - af = list_entry(pos, sctp_func_t, list); + af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&proto->local_addr_list, dev); } } @@ -251,7 +254,6 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr, return &rt->u.dst; } - /* Initialize a sctp_addr from in incoming skb. */ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, int is_saddr) @@ -274,6 +276,21 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr)); } +/* Initialize an sctp_addr from a socket. */ +static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = inet_sk(sk)->num; + addr->v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; +} + +/* Initialize sk->rcv_saddr from sctp_addr. */ +static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk) +{ + inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr; +} + + /* Initialize a sctp_addr from a dst_entry. */ static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst) { @@ -311,7 +328,7 @@ static int sctp_v4_is_any(const union sctp_addr *addr) } /* This function checks if the address is a valid address to be used for - * SCTP. + * SCTP binding. * * Output: * Return 0 - If the address is a non-unicast or an illegal address. @@ -326,6 +343,18 @@ static int sctp_v4_addr_valid(union sctp_addr *addr) return 1; } +/* Should this be available for binding? */ +static int sctp_v4_available(const union sctp_addr *addr) +{ + int ret = inet_addr_type(addr->v4.sin_addr.s_addr); + + /* FIXME: ip_nonlocal_bind sysctl support. */ + + if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL) + return 0; + return 1; +} + /* Checking the loopback, private and other address scopes as defined in * RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4 * scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>. @@ -365,11 +394,11 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) return retval; } -/* Event handler for inet device events. +/* Event handler for inet address addition/deletion events. * Basically, whenever there is an event, we re-build our local address list. */ -static int sctp_netdev_event(struct notifier_block *this, unsigned long event, - void *ptr) +static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event, + void *ptr) { long flags __attribute__ ((unused)); @@ -405,29 +434,42 @@ int sctp_ctl_sock_init(void) return 0; } +/* Register address family specific functions. */ +int sctp_register_af(struct sctp_af *af) +{ + switch (af->sa_family) { + case AF_INET: + if (sctp_af_v4_specific) + return 0; + sctp_af_v4_specific = af; + break; + case AF_INET6: + if (sctp_af_v6_specific) + return 0; + sctp_af_v6_specific = af; + break; + default: + return 0; + } + + INIT_LIST_HEAD(&af->list); + list_add_tail(&af->list, &sctp_proto.address_families); + return 1; +} + /* Get the table of functions for manipulating a particular address * family. */ -sctp_func_t *sctp_get_af_specific(sa_family_t family) +struct sctp_af *sctp_get_af_specific(sa_family_t family) { - struct list_head *pos; - sctp_protocol_t *proto = sctp_get_protocol(); - struct sctp_func *retval, *af; - - retval = NULL; - - /* Cycle through all AF specific functions looking for a - * match. - */ - list_for_each(pos, &proto->address_families) { - af = list_entry(pos, sctp_func_t, list); - if (family == af->sa_family) { - retval = af; - break; - } + switch (family) { + case AF_INET: + return sctp_af_v4_specific; + case AF_INET6: + return sctp_af_v6_specific; + default: + return NULL; } - - return retval; } /* Common code to initialize a AF_INET msg_name. */ @@ -495,21 +537,28 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1, return 0; } +/* Verify that provided sockaddr looks bindable. Common verification has + * already been taken care of. + */ +static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) +{ + return sctp_v4_available(addr); +} -struct sctp_func sctp_ipv4_specific; +struct sctp_af sctp_ipv4_specific; -static sctp_pf_t sctp_pf_inet = { +static struct sctp_pf sctp_pf_inet = { .event_msgname = sctp_inet_event_msgname, .skb_msgname = sctp_inet_skb_msgname, .af_supported = sctp_inet_af_supported, .cmp_addr = sctp_inet_cmp_addr, + .bind_verify = sctp_inet_bind_verify, .af = &sctp_ipv4_specific, }; - -/* Registration for netdev events. */ -struct notifier_block sctp_netdev_notifier = { - .notifier_call = sctp_netdev_event, +/* Notifier for inetaddr addition/deletion events. */ +struct notifier_block sctp_inetaddr_notifier = { + .notifier_call = sctp_inetaddr_event, }; /* Socket operations. */ @@ -551,25 +600,28 @@ static struct inet_protocol sctp_protocol = { }; /* IPv4 address related functions. */ -struct sctp_func sctp_ipv4_specific = { +struct sctp_af sctp_ipv4_specific = { .queue_xmit = ip_queue_xmit, .setsockopt = ip_setsockopt, .getsockopt = ip_getsockopt, .get_dst = sctp_v4_get_dst, .copy_addrlist = sctp_v4_copy_addrlist, .from_skb = sctp_v4_from_skb, + .from_sk = sctp_v4_from_sk, + .to_sk = sctp_v4_to_sk, .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, .inaddr_any = sctp_v4_inaddr_any, .is_any = sctp_v4_is_any, + .available = sctp_v4_available, .scope = sctp_v4_scope, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), .sa_family = AF_INET, }; -sctp_pf_t *sctp_get_pf_specific(int family) { +struct sctp_pf *sctp_get_pf_specific(sa_family_t family) { switch (family) { case PF_INET: @@ -581,20 +633,24 @@ sctp_pf_t *sctp_get_pf_specific(int family) { } } -/* Set the PF specific function table. */ -void sctp_set_pf_specific(int family, sctp_pf_t *pf) +/* Register the PF specific function table. */ +int sctp_register_pf(struct sctp_pf *pf, sa_family_t family) { switch (family) { case PF_INET: + if (sctp_pf_inet_specific) + return 0; sctp_pf_inet_specific = pf; break; case PF_INET6: + if (sctp_pf_inet6_specific) + return 0; sctp_pf_inet6_specific = pf; break; default: - BUG(); - break; + return 0; } + return 1; } /* Initialize the universe into something sensible. */ @@ -617,7 +673,7 @@ int sctp_init(void) sctp_dbg_objcnt_init(); /* Initialize the SCTP specific PF functions. */ - sctp_set_pf_specific(PF_INET, &sctp_pf_inet); + sctp_register_pf(&sctp_pf_inet, PF_INET); /* * 14. Suggested SCTP Protocol Parameter Values */ @@ -636,6 +692,9 @@ int sctp_init(void) /* Valid.Cookie.Life - 60 seconds */ sctp_proto.valid_cookie_life = 60 * HZ; + /* Whether Cookie Preservative is enabled(1) or not(0) */ + sctp_proto.cookie_preserve_enable = 1; + /* Max.Burst - 4 */ sctp_proto.max_burst = SCTP_MAX_BURST; @@ -709,8 +768,7 @@ int sctp_init(void) sctp_sysctl_register(); INIT_LIST_HEAD(&sctp_proto.address_families); - INIT_LIST_HEAD(&sctp_ipv4_specific.list); - list_add_tail(&sctp_ipv4_specific.list, &sctp_proto.address_families); + sctp_register_af(&sctp_ipv4_specific); status = sctp_v6_init(); if (status) @@ -727,7 +785,9 @@ int sctp_init(void) INIT_LIST_HEAD(&sctp_proto.local_addr_list); sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; - register_inetaddr_notifier(&sctp_netdev_notifier); + /* Register notifier for inet address additions/deletions. */ + register_inetaddr_notifier(&sctp_inetaddr_notifier); + sctp_get_local_addr_list(&sctp_proto); return 0; @@ -757,8 +817,10 @@ void sctp_exit(void) * up all the remaining associations and all that memory. */ + /* Unregister notifier for inet address additions/deletions. */ + unregister_inetaddr_notifier(&sctp_inetaddr_notifier); + /* Free the local address list. */ - unregister_inetaddr_notifier(&sctp_netdev_notifier); sctp_free_local_addr_list(&sctp_proto); /* Free the control endpoint. */ diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 288f4ec6edb4..0681874c23a9 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -77,13 +77,18 @@ static const sctp_supported_addrs_param_t sat_param = { { SCTP_PARAM_SUPPORTED_ADDRESS_TYPES, __constant_htons(SCTP_SAT_LEN), - }, - { /* types[] */ - SCTP_PARAM_IPV4_ADDRESS, - SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) } }; +/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above + * structure is split and the address types array is initialized using a + * fixed length array. + */ +static const __u16 sat_addr_types[2] = { + SCTP_PARAM_IPV4_ADDRESS, + SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) +}; + /* RFC 2960 3.3.2 Initiation (INIT) (1) * * Note 2: The ECN capable field is reserved for future use of @@ -163,7 +168,7 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, */ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, const sctp_bind_addr_t *bp, - int priority) + int priority, int vparam_len) { sctp_inithdr_t init; union sctp_params addrs; @@ -192,6 +197,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN; chunksize += sizeof(ecap_param); + chunksize += vparam_len; /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -213,7 +219,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, sctp_addto_chunk(retval, sizeof(init), &init); retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); - sctp_addto_chunk(retval, SCTP_SAT_LEN, &sat_param); + + sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &sat_param); + sctp_addto_chunk(retval, sizeof(sat_addr_types), sat_addr_types); + sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); nodata: @@ -1337,7 +1346,7 @@ nodata: sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, const sctp_association_t *asoc, sctp_chunk_t *chunk, int priority, - int *error) + int *error, sctp_chunk_t **err_chk_p) { sctp_association_t *retval = NULL; sctp_signed_cookie_t *cookie; @@ -1394,7 +1403,29 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, * for init collision case of lost COOKIE ACK. */ if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) { - *error = -SCTP_IERROR_STALE_COOKIE; + /* + * Section 3.3.10.3 Stale Cookie Error (3) + * + * Cause of error + * --------------- + * Stale Cookie Error: Indicates the receipt of a valid State + * Cookie that has expired. + */ + *err_chk_p = sctp_make_op_error_space(asoc, chunk, + ntohs(chunk->chunk_hdr->length)); + if (*err_chk_p) { + suseconds_t usecs = (chunk->skb->stamp.tv_sec - + bear_cookie->expiration.tv_sec) * 1000000L + + chunk->skb->stamp.tv_usec - + bear_cookie->expiration.tv_usec; + + usecs = htonl(usecs); + sctp_init_cause(*err_chk_p, SCTP_ERROR_STALE_COOKIE, + &usecs, sizeof(usecs)); + *error = -SCTP_IERROR_STALE_COOKIE; + } else + *error = -SCTP_IERROR_NOMEM; + goto fail; } @@ -1751,6 +1782,7 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param, __u16 sat; int retval = 1; sctp_scope_t scope; + time_t stale; /* We maintain all INIT parameters in network byte order all the * time. This allows us to not worry about whether the parameters @@ -1770,8 +1802,16 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param, break; case SCTP_PARAM_COOKIE_PRESERVATIVE: - asoc->cookie_preserve = - ntohl(param.life->lifespan_increment); + if (!sctp_proto.cookie_preserve_enable) + break; + + stale = ntohl(param.life->lifespan_increment); + + /* Suggested Cookie Life span increment's unit is msec, + * (1/1000sec). + */ + asoc->cookie_life.tv_sec += stale / 1000; + asoc->cookie_life.tv_usec += (stale % 1000) * 1000; break; case SCTP_PARAM_HOST_NAME_ADDRESS: diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 69ca9dccc364..a979d06c4825 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -68,7 +68,8 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, sctp_transport_t *transport); static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc, - sctp_event_t event_type, sctp_chunk_t *chunk); + sctp_event_t event_type, sctp_subtype_t stype, + sctp_chunk_t *chunk); static int sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, sctp_chunk_t *chunk, sctp_init_chunk_t *peer_init, @@ -517,7 +518,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_ASSOC_FAILED: sctp_cmd_assoc_failed(commands, asoc, event_type, - chunk); + subtype, chunk); break; case SCTP_CMD_COUNTER_INC: @@ -1046,18 +1047,27 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc, sctp_event_t event_type, + sctp_subtype_t subtype, sctp_chunk_t *chunk) { sctp_ulpevent_t *event; __u16 error = 0; - if (event_type == SCTP_EVENT_T_PRIMITIVE) - error = SCTP_ERROR_USER_ABORT; - - if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) && - (ntohs(chunk->chunk_hdr->length) >= (sizeof(struct sctp_chunkhdr) + - sizeof(struct sctp_errhdr)))) { - error = ((sctp_errhdr_t *)chunk->skb->data)->cause; + switch(event_type) { + case SCTP_EVENT_T_PRIMITIVE: + if (SCTP_PRIMITIVE_ABORT == subtype.primitive) + error = SCTP_ERROR_USER_ABORT; + break; + case SCTP_EVENT_T_CHUNK: + if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) && + (ntohs(chunk->chunk_hdr->length) >= + (sizeof(struct sctp_chunkhdr) + + sizeof(struct sctp_errhdr)))) { + error = ((sctp_errhdr_t *)chunk->skb->data)->cause; + } + break; + default: + break; } event = sctp_ulpevent_make_assoc_change(asoc, diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 6825e088ed7e..0ef43f61a9c8 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2,6 +2,7 @@ * 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) 2002 Nokia Corp. * * This file is part of the SCTP kernel reference Implementation @@ -502,6 +503,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, sctp_chunk_t *repl; sctp_ulpevent_t *ev; int error = 0; + sctp_chunk_t *err_chk_p; /* If the packet is an OOTB packet which is temporarily on the * control endpoint, responding with an ABORT. @@ -521,7 +523,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, * "Z" will reply with a COOKIE ACK chunk after building a TCB * and moving to the ESTABLISHED state. */ - new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error, + &err_chk_p); /* FIXME: * If the re-build failed, what is the proper error path @@ -537,6 +540,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, case -SCTP_IERROR_NOMEM: goto nomem; + case -SCTP_IERROR_STALE_COOKIE: + sctp_send_stale_cookie_err(ep, asoc, chunk, commands, + err_chk_p); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + case -SCTP_IERROR_BAD_SIG: default: return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -862,8 +870,8 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, /* Check if the timestamp looks valid. */ if (time_after(hbinfo->sent_at, jiffies) || time_after(jiffies, hbinfo->sent_at + max_interval)) { - SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp - received for transport: %p\n", + SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp" + "received for transport: %p\n", __FUNCTION__, link); return SCTP_DISPOSITION_DISCARD; } @@ -1562,6 +1570,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, sctp_association_t *new_asoc; int error = 0; char action; + sctp_chunk_t *err_chk_p; /* "Decode" the chunk. We have no optional parameters so we * are in good shape. @@ -1575,7 +1584,8 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, * current association, consider the State Cookie valid even if * the lifespan is exceeded. */ - new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error, + &err_chk_p); /* FIXME: * If the re-build failed, what is the proper error path @@ -1591,6 +1601,12 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, case -SCTP_IERROR_NOMEM: goto nomem; + case -SCTP_IERROR_STALE_COOKIE: + sctp_send_stale_cookie_err(ep, asoc, chunk, commands, + err_chk_p); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + break; case -SCTP_IERROR_BAD_SIG: default: return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1706,7 +1722,47 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep, return sctp_sf_shutdown_sent_abort(ep, asoc, type, arg, commands); } -#if 0 +/* + * Handle an Error received in COOKIE_ECHOED state. + * + * Only handle the error type of stale COOKIE Error, the other errors will + * be ignored. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_errhdr_t *err; + + /* If we have gotten too many failures, give up. */ + if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] > + asoc->max_init_attempts) { + /* INIT_FAILED will issue an ulpevent. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + err = (sctp_errhdr_t *)(chunk->skb->data); + + /* Process the error here */ + switch (err->cause) { + case SCTP_ERROR_STALE_COOKIE: + return sctp_sf_do_5_2_6_stale(ep, asoc, type, arg, commands); + default: + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } +} + /* * Handle a Stale COOKIE Error * @@ -1732,47 +1788,30 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep, * * The return value is the disposition of the chunk. */ -sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { sctp_chunk_t *chunk = arg; + time_t stale; + sctp_cookie_preserve_param_t bht; + sctp_errhdr_t *err; + struct list_head *pos; + sctp_transport_t *t; + sctp_chunk_t *reply; + sctp_bind_addr_t *bp; + int attempts; - /* This is not a real chunk type. It is a subtype of the - * ERROR chunk type. The ERROR chunk processing will bring us - * here. - */ - sctp_chunk_t *in_packet; - stp_chunk_t *reply; - sctp_inithdr_t initack; - __u8 *addrs; - int addrs_len; - time_t rtt; - struct sctpCookiePreserve bht; + attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; - /* If we have gotten too many failures, give up. */ - if (1 + asoc->counters[SctpCounterInits] > asoc->max_init_attempts) { - /* FIXME: Move to new ulpevent. */ - retval->event_up = sctp_make_ulp_init_timeout(asoc); - if (!retval->event_up) - goto nomem; - sctp_add_cmd_sf(retval->commands, SCTP_CMD_DELETE_TCB, - SCTP_NULL()); + if (attempts >= asoc->max_init_attempts) { + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; } - retval->counters[0] = SCTP_COUNTER_INCR; - retval->counters[0] = SctpCounterInits; - retval->counters[1] = 0; - retval->counters[1] = 0; - - /* Calculate the RTT in ms. */ - /* BUG--we should get the send time of the HEARTBEAT REQUEST. */ - in_packet = chunk; - rtt = 1000 * timeval_sub(in_packet->skb->stamp, - asoc->c.state_timestamp); + err = (sctp_errhdr_t *)(chunk->skb->data); /* When calculating the time extension, an implementation * SHOULD use the RTT information measured based on the @@ -1780,28 +1819,48 @@ sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep, * more than 1 second beyond the measured RTT, due to long * State Cookie lifetimes making the endpoint more subject to * a replay attack. + * Measure of Staleness's unit is usec. (1/1000000 sec) + * Suggested Cookie Life-span Increment's unit is msec. + * (1/1000 sec) + * In general, if you use the suggested cookie life, the value + * found in the field of measure of staleness should be doubled + * to give ample time to retransmit the new cookie and thus + * yield a higher probability of success on the reattempt. */ - bht.p = {SCTP_COOKIE_PRESERVE, 8}; - bht.extraTime = htonl(rtt + 1000); + stale = ntohl(*(suseconds_t *)((u8 *)err + sizeof(sctp_errhdr_t))); + stale = stale << 1 / 1000; - initack.init_tag = htonl(asoc->c.my_vtag); - initack.a_rwnd = htonl(atomic_read(&asoc->rnwd)); - initack.num_outbound_streams = htons(asoc->streamoutcnt); - initack.num_inbound_streams = htons(asoc->streamincnt); - initack.initial_tsn = htonl(asoc->c.initSeqNumber); - - sctp_get_my_addrs(asoc, &addrs, &addrs_len); + bht.param_hdr.type = SCTP_PARAM_COOKIE_PRESERVATIVE; + bht.param_hdr.length = htons(sizeof(bht)); + bht.lifespan_increment = htonl(stale); /* Build that new INIT chunk. */ - reply = sctp_make_chunk(SCTP_INITIATION, 0, - sizeof(initack) - + sizeof(bht) - + addrs_len); + bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht)); if (!reply) goto nomem; - sctp_addto_chunk(reply, sizeof(initack), &initack); + sctp_addto_chunk(reply, sizeof(bht), &bht); - sctp_addto_chunk(reply, addrs_len, addrs); + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC, + SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); + + /* If we've sent any data bundled with COOKIE-ECHO we need to resend. */ + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(t)); + } + + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_COOKIE_WAIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); return SCTP_DISPOSITION_CONSUME; @@ -1809,7 +1868,6 @@ sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep, nomem: return SCTP_DISPOSITION_NOMEM; } -#endif /* 0 */ /* * Process an ABORT. @@ -3220,7 +3278,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, * 1 to 4294967295 (see 5.3.1 for Tag value selection). ... */ - repl = sctp_make_init(asoc, bp, GFP_ATOMIC); + repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); if (!repl) goto nomem; @@ -3992,7 +4050,7 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, switch (timer) { case SCTP_EVENT_TIMEOUT_T1_INIT: bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; - repl = sctp_make_init(asoc, bp, GFP_ATOMIC); + repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); break; case SCTP_EVENT_TIMEOUT_T1_COOKIE: @@ -4334,3 +4392,25 @@ void sctp_ootb_pkt_free(sctp_packet_t *packet) sctp_transport_free(packet->transport); sctp_packet_free(packet); } + +/* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */ +void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_chunk_t *err_chunk) +{ + sctp_packet_t *packet; + + if (err_chunk) { + packet = sctp_ootb_pkt_new(asoc, chunk); + if (packet) { + /* Set the skb to the belonging sock for accounting. */ + err_chunk->skb->sk = ep->base.sk; + sctp_packet_append_chunk(packet, err_chunk); + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); + } else + sctp_free_chunk (err_chunk); + } +} diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index e0744f1f463a..fc603bba8cda 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -295,7 +295,7 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_COOKIE_WAIT */ \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ /* SCTP_STATE_COOKIE_ECHOED */ \ - {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ + {.fn = sctp_sf_cookie_echoed_err, .name = "sctp_sf_cookie_echoed_err"}, \ /* SCTP_STATE_ESTABLISHED */ \ {.fn = sctp_sf_operr_notify, .name = "sctp_sf_operr_notify"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 54e06e12395c..fe1244e22449 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -87,12 +87,7 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p); -static inline void sctp_sk_addr_set(struct sock *, - const union sctp_addr *newaddr, - union sctp_addr *saveaddr); -static inline void sctp_sk_addr_restore(struct sock *, - const union sctp_addr *); -static inline int sctp_verify_addr(struct sock *, struct sockaddr *, int); +static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); static int sctp_do_bind(struct sock *, union sctp_addr *, int); @@ -133,101 +128,75 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) return retval; } -static long sctp_get_port_local(struct sock *, unsigned short); +static long sctp_get_port_local(struct sock *, union sctp_addr *); -/* Bind a local address either to an endpoint or to an association. */ -SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr, - int addr_len) +/* Verify this is a valid sockaddr. */ +static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, + union sctp_addr *addr, int len) { - sctp_opt_t *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; - sctp_bind_addr_t *bp = &ep->base.bind_addr; - unsigned short sa_family = newaddr->sa.sa_family; - union sctp_addr tmpaddr, saveaddr; - unsigned short *snum; - int ret = 0; + struct sctp_af *af; - SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)\n", - sk, newaddr, addr_len); - - /* FIXME: This function needs to handle v4-mapped-on-v6 - * addresses! - */ - if (PF_INET == sk->family) { - if (sa_family != AF_INET) - return -EINVAL; - } + /* Check minimum size. */ + if (len < sizeof (struct sockaddr)) + return NULL; - /* Make a local copy of the new address. */ - tmpaddr = *newaddr; + /* Does this PF support this AF? */ + if (!opt->pf->af_supported(addr->sa.sa_family)) + return NULL; - switch (sa_family) { - case AF_INET: - if (addr_len < sizeof(struct sockaddr_in)) - return -EINVAL; + /* If we get this far, af is valid. */ + af = sctp_get_af_specific(addr->sa.sa_family); - ret = inet_addr_type(newaddr->v4.sin_addr.s_addr); + if (len < af->sockaddr_len) + return NULL; - /* FIXME: - * Should we allow apps to bind to non-local addresses by - * checking the IP sysctl parameter "ip_nonlocal_bind"? - */ - if (newaddr->v4.sin_addr.s_addr != INADDR_ANY && - ret != RTN_LOCAL) - return -EADDRNOTAVAIL; + return af; +} - tmpaddr.v4.sin_port = htons(tmpaddr.v4.sin_port); - snum = &tmpaddr.v4.sin_port; - break; - case AF_INET6: - SCTP_V6( - /* FIXME: Hui, please verify this. Looking at - * the ipv6 code I see a SIN6_LEN_RFC2133 check. - * I'm guessing that scope_id is a newer addition. - */ - if (addr_len < sizeof(struct sockaddr_in6)) - return -EINVAL; +/* Bind a local address either to an endpoint or to an association. */ +SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_af *af; + unsigned short snum; + int ret = 0; - /* FIXME - The support for IPv6 multiple types - * of addresses need to be added later. - */ - ret = sctp_ipv6_addr_type(&newaddr->v6.sin6_addr); - tmpaddr.v6.sin6_port = htons(tmpaddr.v6.sin6_port); - snum = &tmpaddr.v6.sin6_port; - break; - ) + SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d)\n", + sk, addr, len); - default: + /* Common sockaddr verification. */ + af = sctp_sockaddr_af(sp, addr, len); + if (!af) return -EINVAL; - }; + + /* PF specific bind() address verification. */ + if (!sp->pf->bind_verify(sp, addr)) + return -EADDRNOTAVAIL; + + snum= ntohs(addr->v4.sin_port); SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n", - bp->port, *snum); + bp->port, snum); /* We must either be unbound, or bind to the same port. */ - if (bp->port && (*snum != bp->port)) { + if (bp->port && (snum != bp->port)) { SCTP_DEBUG_PRINTK("sctp_do_bind:" " New port %d does not match existing port " - "%d.\n", *snum, bp->port); + "%d.\n", snum, bp->port); return -EINVAL; } - if (*snum && *snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; - /* FIXME - Make socket understand that there might be multiple bind - * addresses and there will be multiple source addresses involved in - * routing and failover decisions. - */ - sctp_sk_addr_set(sk, &tmpaddr, &saveaddr); - /* Make sure we are allowed to bind here. * The function sctp_get_port_local() does duplicate address * detection. */ - if ((ret = sctp_get_port_local(sk, *snum))) { - sctp_sk_addr_restore(sk, &saveaddr); + if ((ret = sctp_get_port_local(sk, addr))) { if (ret == (long) sk) { /* This endpoint has a conflicting address. */ return -EINVAL; @@ -237,25 +206,32 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr, } /* Refresh ephemeral port. */ - if (!*snum) - *snum = inet_sk(sk)->num; + if (!snum) + snum = inet_sk(sk)->num; + + - /* The getsockname() API depends on 'sport' being set. */ - inet_sk(sk)->sport = htons(inet_sk(sk)->num); /* Add the address to the bind address list. */ sctp_local_bh_disable(); sctp_write_lock(&ep->base.addr_lock); /* Use GFP_ATOMIC since BHs are disabled. */ - if ((ret = sctp_add_bind_addr(bp, &tmpaddr, GFP_ATOMIC))) { - sctp_sk_addr_restore(sk, &saveaddr); - } else if (!bp->port) { - bp->port = *snum; - } + addr->v4.sin_port = ntohs(addr->v4.sin_port); + ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC); + addr->v4.sin_port = htons(addr->v4.sin_port); + if (!ret && !bp->port) + bp->port = snum; sctp_write_unlock(&ep->base.addr_lock); sctp_local_bh_enable(); + + /* Copy back into socket for getsockname() use. */ + if (!ret) { + inet_sk(sk)->sport = htons(inet_sk(sk)->num); + af->to_sk(addr, sk); + } + return ret; } @@ -735,7 +711,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, int size) + struct msghdr *msg, int msg_len) { sctp_opt_t *sp; sctp_endpoint_t *ep; @@ -750,13 +726,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, sctp_assoc_t associd = NULL; sctp_cmsgs_t cmsgs = { 0 }; int err; - size_t msg_len; sctp_scope_t scope; long timeo; __u16 sinfo_flags = 0; - SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, " - "size: %d)\n", sk, msg, size); + SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", + sk, msg, msg_len); err = 0; sp = sctp_sk(sk); @@ -778,12 +753,16 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, * For a peeled-off socket, msg_name is ignored. */ if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { - err = sctp_verify_addr(sk, (struct sockaddr *)msg->msg_name, - msg->msg_namelen); + int msg_namelen = msg->msg_namelen; + + err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name, + msg_namelen); if (err) return err; - memcpy(&to, msg->msg_name, msg->msg_namelen); + if (msg_namelen > sizeof(to)) + msg_namelen = sizeof(to); + memcpy(&to, msg->msg_name, msg_namelen); SCTP_DEBUG_PRINTK("Just memcpy'd. msg_name is " "0x%x:%u.\n", to.v4.sin_addr.s_addr, to.v4.sin_port); @@ -792,8 +771,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, msg_name = msg->msg_name; } - msg_len = get_user_iov_size(msg->msg_iov, msg->msg_iovlen); - sinfo = cmsgs.info; sinit = cmsgs.init; @@ -1216,9 +1193,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr * Otherwise, set MSG_EOR indicating the end of a message. */ if (skb_len > copied) { + msg->msg_flags &= ~MSG_EOR; + if (flags & MSG_PEEK) + goto out_free; sctp_skb_pull(skb, copied); skb_queue_head(&sk->receive_queue, skb); - msg->msg_flags &= ~MSG_EOR; goto out; } else { msg->msg_flags |= MSG_EOR; @@ -1335,6 +1314,16 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk, return 0; } +static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, + int optlen) +{ + if (optlen != sizeof(struct sctp_initmsg)) + return -EINVAL; + if (copy_from_user(&sctp_sk(sk)->initmsg, optval, optlen)) + return -EFAULT; + return 0; +} + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -1355,13 +1344,10 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk, * optlen - the size of the buffer. */ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, - char *optval, int optlen) + char *optval, int optlen) { int retval = 0; char *tmp; - sctp_protocol_t *proto = sctp_get_protocol(); - struct list_head *pos; - sctp_func_t *af; SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", sk, optname); @@ -1373,14 +1359,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, * are at all well-founded. */ if (level != SOL_SCTP) { - list_for_each(pos, &proto->address_families) { - af = list_entry(pos, sctp_func_t, list); - - retval = af->setsockopt(sk, level, optname, optval, - optlen); - if (retval < 0) - goto out_nounlock; - } + struct sctp_af *af = sctp_sk(sk)->pf->af; + retval = af->setsockopt(sk, level, optname, optval, optlen); + goto out_nounlock; } sctp_lock_sock(sk); @@ -1430,6 +1411,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, optlen); break; + case SCTP_INITMSG: + retval = sctp_setsockopt_initmsg(sk, optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -1484,7 +1469,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, goto out_unlock; } - err = sctp_verify_addr(sk, uaddr, addr_len); + err = sctp_verify_addr(sk, (union sctp_addr *)uaddr, addr_len); if (err) goto out_unlock; @@ -1938,13 +1923,19 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk, return 0; } +static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) +{ + if (len != sizeof(struct sctp_initmsg)) + return -EINVAL; + if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) + return -EFAULT; + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { int retval = 0; - sctp_protocol_t *proto = sctp_get_protocol(); - sctp_func_t *af; - struct list_head *pos; int len; SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk); @@ -1956,13 +1947,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, * are at all well-founded. */ if (level != SOL_SCTP) { - list_for_each(pos, &proto->address_families) { - af = list_entry(pos, sctp_func_t, list); - retval = af->getsockopt(sk, level, optname, - optval, optlen); - if (retval < 0) - return retval; - } + struct sctp_af *af = sctp_sk(sk)->pf->af; + + retval = af->getsockopt(sk, level, optname, optval, optlen); + return retval; } if (get_user(len, optlen)) @@ -1997,6 +1985,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, optlen); break; + case SCTP_INITMSG: + retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -2030,12 +2022,17 @@ static void sctp_unhash(struct sock *sk) */ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum); -static long sctp_get_port_local(struct sock *sk, unsigned short snum) +static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) { sctp_bind_hashbucket_t *head; /* hash list */ sctp_bind_bucket_t *pp; /* hash list port iterator */ sctp_protocol_t *sctp = sctp_get_protocol(); + unsigned short snum; int ret; + + /* NOTE: Remember to put this back to net order. */ + addr->v4.sin_port = ntohs(addr->v4.sin_port); + snum = addr->v4.sin_port; SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum); @@ -2101,6 +2098,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) } } + if (pp != NULL && pp->sk != NULL) { /* We had a port hash table hit - there is an * available port (pp != NULL) and it is being @@ -2108,7 +2106,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) * socket is going to be sk2. */ int sk_reuse = sk->reuse; - union sctp_addr tmpaddr; struct sock *sk2 = pp->sk; SCTP_DEBUG_PRINTK("sctp_get_port() found a " @@ -2116,27 +2113,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) if (pp->fastreuse != 0 && sk->reuse != 0) goto success; - /* FIXME - multiple addresses need to be supported - * later. - */ - switch (sk->family) { - case PF_INET: - tmpaddr.v4.sin_family = AF_INET; - tmpaddr.v4.sin_port = snum; - tmpaddr.v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; - break; - - case PF_INET6: - SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6; - tmpaddr.v6.sin6_port = snum; - tmpaddr.v6.sin6_addr = inet6_sk(sk)->rcv_saddr; - ) - break; - - default: - break; - }; - /* Run through the list of sockets bound to the port * (pp->port) [via the pointers bind_next and * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, @@ -2154,8 +2130,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) if (sk_reuse && sk2->reuse) continue; - if (sctp_bind_addr_match(&ep2->base.bind_addr, - &tmpaddr, + if (sctp_bind_addr_match(&ep2->base.bind_addr, addr, sctp_sk(sk))) goto found; } @@ -2207,12 +2182,25 @@ fail: sctp_local_bh_enable(); SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret); + addr->v4.sin_port = htons(addr->v4.sin_port); return ret; } +/* Assign a 'snum' port to the socket. If snum == 0, an ephemeral + * port is requested. + */ static int sctp_get_port(struct sock *sk, unsigned short snum) { - long ret = sctp_get_port_local(sk, snum); + long ret; + union sctp_addr addr; + struct sctp_af *af = sctp_sk(sk)->pf->af; + + /* Set up a dummy address struct from the sk. */ + af->from_sk(&addr, sk); + addr.v4.sin_port = htons(snum); + + /* Note: sk->num gets filled in if ephemeral port request. */ + ret = sctp_get_port_local(sk, &addr); return (ret ? 1 : 0); } @@ -2413,7 +2401,7 @@ void sctp_put_port(struct sock *sk) static int sctp_autobind(struct sock *sk) { union sctp_addr autoaddr; - struct sctp_func *af; + struct sctp_af *af; unsigned short port; /* Initialize a local sockaddr structure to INADDR_ANY. */ @@ -2537,58 +2525,6 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, return 0; } -/* Setup sk->rcv_saddr before calling get_port(). */ -static inline void sctp_sk_addr_set(struct sock *sk, - const union sctp_addr *newaddr, - union sctp_addr *saveaddr) -{ - struct inet_opt *inet = inet_sk(sk); - - saveaddr->sa.sa_family = newaddr->sa.sa_family; - - switch (newaddr->sa.sa_family) { - case AF_INET: - saveaddr->v4.sin_addr.s_addr = inet->rcv_saddr; - inet->rcv_saddr = inet->saddr = newaddr->v4.sin_addr.s_addr; - break; - - case AF_INET6: - SCTP_V6({ - struct ipv6_pinfo *np = inet6_sk(sk); - - saveaddr->v6.sin6_addr = np->rcv_saddr; - np->rcv_saddr = np->saddr = newaddr->v6.sin6_addr; - break; - }) - - default: - break; - }; -} - -/* Restore sk->rcv_saddr after failing get_port(). */ -static inline void sctp_sk_addr_restore(struct sock *sk, const union sctp_addr *addr) -{ - struct inet_opt *inet = inet_sk(sk); - - switch (addr->sa.sa_family) { - case AF_INET: - inet->rcv_saddr = inet->saddr = addr->v4.sin_addr.s_addr; - break; - - case AF_INET6: - SCTP_V6({ - struct ipv6_pinfo *np = inet6_sk(sk); - - np->rcv_saddr = np->saddr = addr->v6.sin6_addr; - break; - }) - - default: - break; - }; -} - /* * Wait for a packet.. * Note: This function is the same function as in core/datagram.c @@ -2711,27 +2647,15 @@ no_packet: } /* Verify that this is a valid address. */ -static int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int len) +static int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len) { - struct sctp_func *af; - - /* Check minimum size. */ - if (len < sizeof (struct sockaddr)) - return -EINVAL; + struct sctp_af *af; - /* Do we support this address family in general? */ - af = sctp_get_af_specific(addr->sa_family); + /* Verify basic sockaddr. */ + af = sctp_sockaddr_af(sctp_sk(sk), addr, len); if (!af) return -EINVAL; - /* Does this PF support this AF? */ - if (!sctp_sk(sk)->pf->af_supported(addr->sa_family)) - return -EINVAL; - - /* Verify the minimum for this AF sockaddr. */ - if (len < af->sockaddr_len) - return -EINVAL; - /* Is this a valid SCTP address? */ if (!af->addr_valid((union sctp_addr *)addr)) return -EINVAL; diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 11b3bb63d241..75eee265cbfc 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -1,5 +1,6 @@ /* SCTP kernel reference Implementation * Copyright (c) 2002 International Business Machines Corp. + * Copyright (c) 2002 Intel Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -32,6 +33,7 @@ * Written or modified by: * Mingqin Liu <liuming@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.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. @@ -70,6 +72,9 @@ static ctl_table sctp_table[] = { { NET_SCTP_HB_INTERVAL, "hb_interval", &sctp_proto.hb_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_PRESERVE_ENABLE, "cookie_preserve_enable", + &sctp_proto.cookie_preserve_enable, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, { NET_SCTP_RTO_ALPHA, "rto_alpha_exp_divisor", &sctp_proto.rto_alpha, sizeof(int), 0644, NULL, &proc_dointvec }, diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 4fba07425349..303c33852b99 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -207,7 +207,7 @@ void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr, struct sctp_opt *opt) { sctp_association_t *asoc = transport->asoc; - struct sctp_func *af = transport->af_specific; + struct sctp_af *af = transport->af_specific; union sctp_addr *daddr = &transport->ipaddr; sctp_bind_addr_t *bp; rwlock_t *addr_lock; |
