diff options
Diffstat (limited to 'sys/netinet')
42 files changed, 2670 insertions, 2483 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 3f11e82..bf1ebae 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -41,7 +41,9 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/priv.h> #include <sys/socket.h> +#include <sys/jail.h> #include <sys/kernel.h> +#include <sys/proc.h> #include <sys/sysctl.h> #include <sys/vimage.h> @@ -261,13 +263,19 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) if (iap->ia_ifp == ifp && iap->ia_addr.sin_addr.s_addr == dst.s_addr) { - ia = iap; + if (td == NULL || prison_check_ip4( + td->td_ucred, &dst) == 0) + ia = iap; break; } if (ia == NULL) TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { iap = ifatoia(ifa); if (iap->ia_addr.sin_family == AF_INET) { + if (td != NULL && + prison_check_ip4(td->td_ucred, + &iap->ia_addr.sin_addr) != 0) + continue; ia = iap; break; } @@ -995,9 +1003,6 @@ in_purgemaddrs(struct ifnet *ifp) struct in_multi *inm; struct in_multi *oinm; -#ifdef DIAGNOSTIC - printf("%s: purging ifp %p\n", __func__, ifp); -#endif IFF_LOCKGIANT(ifp); IN_MULTI_LOCK(); LIST_FOREACH_SAFE(inm, &V_in_multihead, inm_link, oinm) { @@ -1106,9 +1111,10 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add hashkey = sin->sin_addr.s_addr; lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; LIST_FOREACH(lle, lleh, lle_next) { + struct sockaddr_in *sa2 = (struct sockaddr_in *)L3_ADDR(lle); if (lle->la_flags & LLE_DELETED) continue; - if (bcmp(L3_ADDR(lle), l3addr, sizeof(struct sockaddr_in)) == 0) + if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr) break; } if (lle == NULL) { @@ -1153,7 +1159,7 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add lle = (void *)-1; } - if (lle != NULL && lle != (void *)-1) { + if (LLE_IS_VALID(lle)) { if (flags & LLE_EXCLUSIVE) LLE_WLOCK(lle); else @@ -1192,6 +1198,9 @@ in_lltable_dump(struct lltable *llt, struct sysctl_req *wr) /* skip deleted entries */ if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) continue; + /* Skip if jailed and not a valid IP of the prison. */ + if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0) + continue; /* * produce a msg made of: * struct rt_msghdr; @@ -1200,6 +1209,10 @@ in_lltable_dump(struct lltable *llt, struct sysctl_req *wr) */ bzero(&arpc, sizeof(arpc)); arpc.rtm.rtm_msglen = sizeof(arpc); + arpc.rtm.rtm_version = RTM_VERSION; + arpc.rtm.rtm_type = RTM_GET; + arpc.rtm.rtm_flags = RTF_UP; + arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; arpc.sin.sin_family = AF_INET; arpc.sin.sin_len = sizeof(arpc.sin); arpc.sin.sin_addr.s_addr = SIN(lle)->sin_addr.s_addr; diff --git a/sys/netinet/in.h b/sys/netinet/in.h index b969bdf..591e766 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -441,6 +441,8 @@ __END_DECLS #define IP_FAITH 22 /* bool; accept FAITH'ed connections */ #define IP_ONESBCAST 23 /* bool: send all-ones broadcast */ +#define IP_NONLOCALOK 24 /* bool: allow bind to spoof non-local addresses; + requires kernel compile option IP_NONLOCALBIND */ #define IP_FW_TABLE_ADD 40 /* add entry */ #define IP_FW_TABLE_DEL 41 /* delete entry */ diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 6d1c2aa..3014bc3 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" +#include "opt_inet.h" #include "opt_ipsec.h" #include "opt_inet6.h" #include "opt_mac.h" @@ -312,7 +313,10 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, return (EINVAL); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) wild = INPLOOKUP_WILDCARD; - if (nam) { + if (nam == NULL) { + if ((error = prison_local_ip4(cred, &laddr)) != 0) + return (error); + } else { sin = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sin)) return (EINVAL); @@ -324,8 +328,9 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); #endif - if (prison_local_ip4(cred, &sin->sin_addr)) - return (EINVAL); + error = prison_local_ip4(cred, &sin->sin_addr); + if (error) + return (error); if (sin->sin_port != *lportp) { /* Don't allow the port to change. */ if (*lportp != 0) @@ -346,7 +351,16 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, } else if (sin->sin_addr.s_addr != INADDR_ANY) { sin->sin_port = 0; /* yech... */ bzero(&sin->sin_zero, sizeof(sin->sin_zero)); - if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) + /* + * Is the address a local IP address? + * If INP_NONLOCALOK is set, then the socket may be bound + * to any endpoint address, local or not. + */ + if ( +#if defined(IP_NONLOCALBIND) + ((inp->inp_flags & INP_NONLOCALOK) == 0) && +#endif + (ifa_ifwithaddr((struct sockaddr *)sin) == 0)) return (EADDRNOTAVAIL); } laddr = sin->sin_addr; @@ -381,8 +395,6 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, t->inp_cred->cr_uid)) return (EADDRINUSE); } - if (prison_local_ip4(cred, &sin->sin_addr)) - return (EADDRNOTAVAIL); t = in_pcblookup_local(pcbinfo, sin->sin_addr, lport, wild, cred); if (t && (t->inp_vflag & INP_TIMEWAIT)) { @@ -416,9 +428,6 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, u_short first, last, aux; int count; - if (prison_local_ip4(cred, &laddr)) - return (EINVAL); - if (inp->inp_flags & INP_HIGHPORT) { first = V_ipport_hifirstauto; /* sysctl */ last = V_ipport_hilastauto; @@ -483,8 +492,6 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, } while (in_pcblookup_local(pcbinfo, laddr, lport, wild, cred)); } - if (prison_local_ip4(cred, &laddr)) - return (EINVAL); *laddrp = laddr.s_addr; *lportp = lport; return (0); @@ -604,7 +611,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, if (sa->sa_family != AF_INET) continue; sin = (struct sockaddr_in *)sa; - if (prison_check_ip4(cred, &sin->sin_addr)) { + if (prison_check_ip4(cred, &sin->sin_addr) == 0) { ia = (struct in_ifaddr *)ifa; break; } @@ -615,8 +622,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, } /* 3. As a last resort return the 'default' jail address. */ - if (prison_getip4(cred, laddr) != 0) - error = EADDRNOTAVAIL; + error = prison_get_ip4(cred, laddr); goto done; } @@ -641,7 +647,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, /* Jailed. */ /* 1. Check if the iface address belongs to the jail. */ sin = (struct sockaddr_in *)sro.ro_rt->rt_ifa->ifa_addr; - if (prison_check_ip4(cred, &sin->sin_addr)) { + if (prison_check_ip4(cred, &sin->sin_addr) == 0) { ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; laddr->s_addr = ia->ia_addr.sin_addr.s_addr; goto done; @@ -657,7 +663,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, if (sa->sa_family != AF_INET) continue; sin = (struct sockaddr_in *)sa; - if (prison_check_ip4(cred, &sin->sin_addr)) { + if (prison_check_ip4(cred, &sin->sin_addr) == 0) { ia = (struct in_ifaddr *)ifa; break; } @@ -668,8 +674,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, } /* 3. As a last resort return the 'default' jail address. */ - if (prison_getip4(cred, laddr) != 0) - error = EADDRNOTAVAIL; + error = prison_get_ip4(cred, laddr); goto done; } @@ -719,7 +724,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, if (sa->sa_family != AF_INET) continue; sin = (struct sockaddr_in *)sa; - if (prison_check_ip4(cred, &sin->sin_addr)) { + if (prison_check_ip4(cred, + &sin->sin_addr) == 0) { ia = (struct in_ifaddr *)ifa; break; } @@ -731,8 +737,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, } /* 3. As a last resort return the 'default' jail address. */ - if (prison_getip4(cred, laddr) != 0) - error = EADDRNOTAVAIL; + error = prison_get_ip4(cred, laddr); goto done; } @@ -766,7 +771,7 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, struct sockaddr_in *sin = (struct sockaddr_in *)nam; struct in_ifaddr *ia; struct inpcb *oinp; - struct in_addr laddr, faddr, jailia; + struct in_addr laddr, faddr; u_short lport, fport; int error; @@ -799,15 +804,11 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, * choose the broadcast address for that interface. */ if (faddr.s_addr == INADDR_ANY) { - if (cred != NULL && jailed(cred)) { - if (prison_getip4(cred, &jailia) != 0) - return (EADDRNOTAVAIL); - faddr.s_addr = jailia.s_addr; - } else { - faddr = - IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))-> - sin_addr; - } + faddr = + IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; + if (cred != NULL && + (error = prison_get_ip4(cred, &faddr)) != 0) + return (error); } else if (faddr.s_addr == (u_long)INADDR_BROADCAST && (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST)) @@ -1365,7 +1366,8 @@ in_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in_addr faddr, injail = jailed(inp->inp_cred); if (injail) { - if (!prison_check_ip4(inp->inp_cred, &laddr)) + if (prison_check_ip4(inp->inp_cred, + &laddr) != 0) continue; } else { if (local_exact != NULL) diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 01636fe..acc6404 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -411,6 +411,8 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp, #define INP_FAITH 0x200 /* accept FAITH'ed connections */ #define INP_RECVTTL 0x400 /* receive incoming IP TTL */ #define INP_DONTFRAG 0x800 /* don't fragment packet */ +#define INP_NONLOCALOK 0x1000 /* Allow bind to spoof any address */ + /* - requires options IP_NONLOCALBIND */ #define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */ diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index d6eb16f..c2e3191 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_ipfw.h" #include "opt_mac.h" +#include "opt_sctp.h" #ifndef INET #error "IPDIVERT requires INET." #endif @@ -76,6 +77,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip_var.h> #include <netinet/ip_fw.h> #include <netinet/vinet.h> +#ifdef SCTP +#include <netinet/sctp_crc32.h> +#endif #include <security/mac/mac_framework.h> @@ -222,7 +226,14 @@ divert_packet(struct mbuf *m, int incoming) m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; ip->ip_len = htons(ip->ip_len); } - +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) { + ip->ip_len = ntohs(ip->ip_len); + sctp_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_SCTP; + ip->ip_len = htons(ip->ip_len); + } +#endif /* * Record receive interface address, if any. * But only for incoming packets. diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 1f2e67d..133166e 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -197,6 +197,7 @@ SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD, NULL, IPFW_DEFAULT_RULE, "The default/max possible rule number."); SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD, NULL, IPFW_TABLES_MAX, "The maximum number of tables."); +#endif /* SYSCTL_NODE */ /* * Description of dynamic rules. @@ -277,6 +278,7 @@ static u_int32_t dyn_count; /* # of dynamic rules */ static u_int32_t dyn_max; /* max # of dynamic rules */ #endif /* VIMAGE_GLOBALS */ +#ifdef SYSCTL_NODE SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, dyn_buckets, CTLFLAG_RW, dyn_buckets, 0, "Number of dyn. buckets"); SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, @@ -302,18 +304,19 @@ SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, "Lifetime of dyn. rules for other situations"); SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW, dyn_keepalive, 0, "Enable keepalives for dyn. rules"); - +#endif /* SYSCTL_NODE */ #ifdef INET6 /* * IPv6 specific variables */ +#ifdef SYSCTL_NODE SYSCTL_DECL(_net_inet6_ip6); +#endif /* SYSCTL_NODE */ static struct sysctl_ctx_list ip6_fw_sysctl_ctx; static struct sysctl_oid *ip6_fw_sysctl_tree; #endif /* INET6 */ -#endif /* SYSCTL_NODE */ #ifdef VIMAGE_GLOBALS static int fw_deny_unknown_exthdrs; @@ -2251,6 +2254,7 @@ ipfw_chk(struct ip_fw_args *args) if (m->m_flags & M_SKIP_FIREWALL) return (IP_FW_PASS); /* accept */ + dst_ip.s_addr = 0; /* make sure it is initialized */ pktlen = m->m_pkthdr.len; args->f_id.fib = M_GETFIB(m); /* note mbuf not altered) */ proto = args->f_id.proto = 0; /* mark f_id invalid */ @@ -2708,7 +2712,7 @@ check_body: uint32_t a = (cmd->opcode == O_IP_DST_LOOKUP) ? dst_ip.s_addr : src_ip.s_addr; - uint32_t v; + uint32_t v = 0; match = lookup_table(chain, cmd->arg1, a, &v); diff --git a/sys/netinet/ip_fw_nat.c b/sys/netinet/ip_fw_nat.c index 332c026..6ba0412 100644 --- a/sys/netinet/ip_fw_nat.c +++ b/sys/netinet/ip_fw_nat.c @@ -326,12 +326,10 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) else retval = LibAliasOut(t->lib, c, mcl->m_len + M_TRAILINGSPACE(mcl)); -#ifdef _ALIAS_SCTP if (retval == PKT_ALIAS_RESPOND) { m->m_flags |= M_SKIP_FIREWALL; retval = PKT_ALIAS_OK; } -#endif if (retval != PKT_ALIAS_OK && retval != PKT_ALIAS_FOUND_HEADER_FRAGMENT) { /* XXX - should i add some logging? */ @@ -407,7 +405,6 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) } args->m = mcl; - return (IP_FW_NAT); } diff --git a/sys/netinet/ip_ipsec.c b/sys/netinet/ip_ipsec.c index a1e082b..77e9aa7 100644 --- a/sys/netinet/ip_ipsec.c +++ b/sys/netinet/ip_ipsec.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include "opt_ipsec.h" +#include "opt_sctp.h" #include <sys/param.h> #include <sys/systm.h> @@ -56,6 +57,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip_options.h> #include <netinet/ip_ipsec.h> #include <netinet/vinet.h> +#ifdef SCTP +#include <netinet/sctp_crc32.h> +#endif #include <machine/in_cksum.h> @@ -328,7 +332,12 @@ ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error, in_delayed_cksum(*m); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } - +#ifdef SCTP + if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP) { + sctp_delayed_cksum(*m); + (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP; + } +#endif ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 6cda8aa..feacb51 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -33,10 +33,12 @@ __FBSDID("$FreeBSD$"); #include "opt_ipfw.h" +#include "opt_inet.h" #include "opt_ipsec.h" #include "opt_mac.h" #include "opt_mbuf_stress_test.h" #include "opt_mpath.h" +#include "opt_sctp.h" #include <sys/param.h> #include <sys/systm.h> @@ -69,6 +71,10 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip_var.h> #include <netinet/ip_options.h> #include <netinet/vinet.h> +#ifdef SCTP +#include <netinet/sctp.h> +#include <netinet/sctp_crc32.h> +#endif #ifdef IPSEC #include <netinet/ip_ipsec.h> @@ -95,6 +101,12 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, mbuf_frag_size, CTLFLAG_RW, &mbuf_frag_size, 0, "Fragment outgoing mbufs to this size"); #endif +#if defined(IP_NONLOCALBIND) +static int ip_nonlocalok = 0; +SYSCTL_INT(_net_inet_ip, OID_AUTO, nonlocalok, + CTLFLAG_RW|CTLFLAG_SECURE, &ip_nonlocalok, 0, ""); +#endif + static void ip_mloopback (struct ifnet *, struct mbuf *, struct sockaddr_in *, int); @@ -478,7 +490,10 @@ sendit: } m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; - +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; +#endif error = netisr_queue(NETISR_IP, m); goto done; } else @@ -495,6 +510,10 @@ sendit: CSUM_DATA_VALID | CSUM_PSEUDO_HDR; m->m_pkthdr.csum_data = 0xffff; } +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; +#endif m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; @@ -529,6 +548,12 @@ passout: in_delayed_cksum(m); sw_csum &= ~CSUM_DELAY_DATA; } +#ifdef SCTP + if (sw_csum & CSUM_SCTP) { + sctp_delayed_cksum(m); + sw_csum &= ~CSUM_SCTP; + } +#endif m->m_pkthdr.csum_flags &= ifp->if_hwassist; /* @@ -663,7 +688,13 @@ ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, in_delayed_cksum(m0); m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } - +#ifdef SCTP + if (m0->m_pkthdr.csum_flags & CSUM_SCTP && + (if_hwassist_flags & CSUM_IP_FRAGS) == 0) { + sctp_delayed_cksum(m0); + m0->m_pkthdr.csum_flags &= ~CSUM_SCTP; + } +#endif if (len > PAGE_SIZE) { /* * Fragment large datagrams such that each segment @@ -866,6 +897,14 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) return (error); } +#if defined(IP_NONLOCALBIND) + case IP_NONLOCALOK: + if (! ip_nonlocalok) { + error = ENOPROTOOPT; + break; + } + /* FALLTHROUGH */ +#endif case IP_TOS: case IP_TTL: case IP_MINTTL: @@ -892,7 +931,7 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) break; case IP_MINTTL: - if (optval > 0 && optval <= MAXTTL) + if (optval >= 0 && optval <= MAXTTL) inp->inp_ip_minttl = optval; else error = EINVAL; @@ -937,6 +976,11 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_DONTFRAG: OPTSET(INP_DONTFRAG); break; +#if defined(IP_NONLOCALBIND) + case IP_NONLOCALOK: + OPTSET(INP_NONLOCALOK); + break; +#endif } break; #undef OPTSET diff --git a/sys/netinet/libalias/alias.c b/sys/netinet/libalias/alias.c index cfef491..9d80da9 100644 --- a/sys/netinet/libalias/alias.c +++ b/sys/netinet/libalias/alias.c @@ -111,13 +111,6 @@ __FBSDID("$FreeBSD$"); See HISTORY file for additional revisions. */ -/** - * Modifications to add sctp functionality by David A. Hayes - * $Id: alias.c 122 2008-06-25 06:50:47Z dhayes $ - * All are inclosed in #ifdef _ALIAS_SCTP - * - */ - #ifdef _KERNEL #include <sys/param.h> #include <sys/systm.h> @@ -144,17 +137,11 @@ __FBSDID("$FreeBSD$"); #include <netinet/libalias/alias.h> #include <netinet/libalias/alias_local.h> #include <netinet/libalias/alias_mod.h> -#ifdef _ALIAS_SCTP -#include <netinet/libalias/alias_sctp.h> -#endif #else #include <err.h> #include "alias.h" #include "alias_local.h" #include "alias_mod.h" -#ifdef _ALIAS_SCTP -#include "alias_sctp.h" -#endif #endif /* @@ -1360,7 +1347,7 @@ LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) case IPPROTO_TCP: iresult = TcpAliasIn(la, pip); break; -#ifdef _ALIAS_SCTP +#ifdef _KERNEL case IPPROTO_SCTP: iresult = SctpAlias(la, pip, SN_TO_LOCAL); break; @@ -1510,7 +1497,7 @@ LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ case IPPROTO_TCP: iresult = TcpAliasOut(la, pip, maxpacketsize, create); break; - #ifdef _ALIAS_SCTP +#ifdef _KERNEL case IPPROTO_SCTP: iresult = SctpAlias(la, pip, SN_TO_GLOBAL); break; diff --git a/sys/netinet/libalias/alias.h b/sys/netinet/libalias/alias.h index f3e57de..2aed829 100644 --- a/sys/netinet/libalias/alias.h +++ b/sys/netinet/libalias/alias.h @@ -36,13 +36,6 @@ * distribution. */ -/** - * Modifications to add sctp functionality by David A. Hayes - * $Id: alias.h 122 2008-06-25 06:50:47Z dhayes $ - * All are inclosed in #ifdef _ALIAS_SCTP - * - */ - #ifndef _ALIAS_H_ #define _ALIAS_H_ @@ -52,11 +45,6 @@ #define LIBALIAS_BUF_SIZE 128 #ifdef _KERNEL - -#ifndef _ALIAS_SCTP -#define _ALIAS_SCTP //if ALIAS_SCTP code is to be included -#endif - /* * The kernel version of libalias does not support these features. */ diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c index 94dfa51..489933f 100644 --- a/sys/netinet/libalias/alias_db.c +++ b/sys/netinet/libalias/alias_db.c @@ -141,13 +141,6 @@ __FBSDID("$FreeBSD$"); See HISTORY file for additional revisions. */ -/** - * Modifications to add sctp functionality by David A. Hayes - * $Id: alias_db.c 177 2008-07-14 04:33:47Z dhayes $ - * All are inclosed in #ifdef _ALIAS_SCTP - * - */ - #ifdef _KERNEL #include <machine/stdarg.h> @@ -173,9 +166,6 @@ __FBSDID("$FreeBSD$"); #include <netinet/libalias/alias.h> #include <netinet/libalias/alias_local.h> #include <netinet/libalias/alias_mod.h> -#ifdef _ALIAS_SCTP -#include <netinet/libalias/alias_sctp.h> -#endif #include <net/if.h> #else #include "alias.h" @@ -383,7 +373,6 @@ static moduledata_t alias_mod = { }; DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); - #endif /* Internal utility routines (used only in alias_db.c) @@ -421,10 +410,8 @@ static void ClearFWHole(struct alias_link *); static void ShowAliasStats(struct libalias *); static int InitPacketAliasLog(struct libalias *); static void UninitPacketAliasLog(struct libalias *); -#ifdef _ALIAS_SCTP -struct in_addr FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm); + void SctpShowAliasStats(struct libalias *la); -#endif static u_int StartPointIn(struct in_addr alias_addr, @@ -504,25 +491,17 @@ ShowAliasStats(struct libalias *la) /* Used for debugging */ if (la->logDesc) { int tot = la->icmpLinkCount + la->udpLinkCount + -#ifdef _ALIAS_SCTP (la->sctpLinkCount>>1) + /* sctp counts half associations */ -#endif la->tcpLinkCount + la->pptpLinkCount + la->protoLinkCount + la->fragmentIdLinkCount + la->fragmentPtrLinkCount; AliasLog(la->logDesc, -#ifdef _ALIAS_SCTP "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u", -#else - "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u", -#endif la->icmpLinkCount, la->udpLinkCount, la->tcpLinkCount, -#ifdef _ALIAS_SCTP la->sctpLinkCount>>1, /* sctp counts half associations */ -#endif la->pptpLinkCount, la->protoLinkCount, la->fragmentIdLinkCount, @@ -533,12 +512,12 @@ ShowAliasStats(struct libalias *la) } } -#ifdef _ALIAS_SCTP void SctpShowAliasStats(struct libalias *la) { - ShowAliasStats(la); + + ShowAliasStats(la); } -#endif + /* Internal routines for finding, deleting and adding links @@ -1003,10 +982,6 @@ AddLink(struct libalias *la, struct in_addr src_addr, case LINK_TCP: lnk->expire_time = TCP_EXPIRE_INITIAL; break; -#ifdef _ALIAS_SCTP - case LINK_SCTP: /* treat like LINK_ADDR */ - break; -#endif case LINK_PPTP: lnk->flags |= LINK_PERMANENT; /* no timeout. */ break; @@ -1067,10 +1042,6 @@ AddLink(struct libalias *la, struct in_addr src_addr, return (NULL); } break; -#ifdef _ALIAS_SCTP - case LINK_SCTP: /* treat like LINK_ADDR */ - break; -#endif case LINK_PPTP: la->pptpLinkCount++; break; @@ -1317,17 +1288,16 @@ _FindLinkIn(struct libalias *la, struct in_addr dst_addr, src_addr = lnk->src_addr; src_port = lnk->src_port; } -#ifdef _ALIAS_SCTP - if(link_type == LINK_SCTP) { + + if (link_type == LINK_SCTP) { lnk->src_addr = src_addr; lnk->src_port = src_port; return(lnk); } -#endif - lnk = ReLink(lnk, - src_addr, dst_addr, alias_addr, - src_port, dst_port, alias_port, - link_type); + lnk = ReLink(lnk, + src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); } return (lnk); } @@ -2323,11 +2293,9 @@ LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_p case IPPROTO_TCP: link_type = LINK_TCP; break; -#ifdef _ALIAS_SCTP case IPPROTO_SCTP: link_type = LINK_SCTP; break; -#endif default: #ifdef LIBALIAS_DEBUG fprintf(stderr, "PacketAliasRedirectPort(): "); @@ -2547,8 +2515,8 @@ LibAliasInit(struct libalias *la) LIST_INIT(&la->linkTableOut[i]); for (i = 0; i < LINK_TABLE_IN_SIZE; i++) LIST_INIT(&la->linkTableIn[i]); -#ifdef _ALIAS_SCTP - AliasSctpInit(la);//*** +#ifdef _KERNEL + AliasSctpInit(la); #endif LIBALIAS_LOCK_INIT(la); LIBALIAS_LOCK(la); @@ -2557,7 +2525,7 @@ LibAliasInit(struct libalias *la) la->deleteAllLinks = 1; CleanupAliasData(la); la->deleteAllLinks = 0; -#ifdef _ALIAS_SCTP +#ifdef _KERNEL AliasSctpTerm(la); AliasSctpInit(la); #endif @@ -2569,9 +2537,7 @@ LibAliasInit(struct libalias *la) la->icmpLinkCount = 0; la->udpLinkCount = 0; la->tcpLinkCount = 0; -#ifdef _ALIAS_SCTP la->sctpLinkCount = 0; -#endif la->pptpLinkCount = 0; la->protoLinkCount = 0; la->fragmentIdLinkCount = 0; @@ -2600,7 +2566,7 @@ LibAliasUninit(struct libalias *la) { LIBALIAS_LOCK(la); -#ifdef _ALIAS_SCTP +#ifdef _KERNEL AliasSctpTerm(la); #endif la->deleteAllLinks = 1; @@ -2943,39 +2909,30 @@ LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) la->skinnyPort = port; LIBALIAS_UNLOCK(la); } -#ifdef _ALIAS_SCTP -/** - * @brief Find the address to redirect incoming packets - * - * The function is located in alias_db.c due to calls to static functions - * - * - * @param la pointer to the libalias instance - * @param sm pointer to the incoming message - * - * @return address to redirect an incoming INIT to + +/* + * Find the address to redirect incoming packets */ struct in_addr FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) { - struct alias_link *lnk; - struct in_addr redir; - - LIBALIAS_LOCK_ASSERT(la); - lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, - sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); - if (lnk != NULL) { - return(lnk->src_addr); /* port redirect */ - } else { - redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); - if (redir.s_addr == la->aliasAddress.s_addr || - redir.s_addr == la->targetAddress.s_addr) { /* No address found */ - lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, - NO_DEST_PORT, 0, LINK_SCTP, 1); - if (lnk != NULL) - return(lnk->src_addr); /* redirect proto */ - } - return(redir); /* address redirect */ - } + struct alias_link *lnk; + struct in_addr redir; + + LIBALIAS_LOCK_ASSERT(la); + lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, + sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); + if (lnk != NULL) { + return(lnk->src_addr); /* port redirect */ + } else { + redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); + if (redir.s_addr == la->aliasAddress.s_addr || + redir.s_addr == la->targetAddress.s_addr) { /* No address found */ + lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, + NO_DEST_PORT, 0, LINK_SCTP, 1); + if (lnk != NULL) + return(lnk->src_addr); /* redirect proto */ + } + return(redir); /* address redirect */ + } } -#endif diff --git a/sys/netinet/libalias/alias_ftp.c b/sys/netinet/libalias/alias_ftp.c index 243dfae..50fa8d0 100644 --- a/sys/netinet/libalias/alias_ftp.c +++ b/sys/netinet/libalias/alias_ftp.c @@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/module.h> #else +#include <ctype.h> #include <errno.h> #include <sys/types.h> #include <stdio.h> diff --git a/sys/netinet/libalias/alias_irc.c b/sys/netinet/libalias/alias_irc.c index fd76e83..8197fb8 100644 --- a/sys/netinet/libalias/alias_irc.c +++ b/sys/netinet/libalias/alias_irc.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/module.h> #else +#include <ctype.h> #include <errno.h> #include <sys/types.h> #include <stdio.h> diff --git a/sys/netinet/libalias/alias_local.h b/sys/netinet/libalias/alias_local.h index 4124508..e201394 100644 --- a/sys/netinet/libalias/alias_local.h +++ b/sys/netinet/libalias/alias_local.h @@ -42,12 +42,6 @@ * * <updated several times by original author and Eivind Eklund> */ -/** - * Modifications to add sctp functionality by David A. Hayes - * $Id: alias_local.h 122 2008-06-25 06:50:47Z dhayes $ - * All are inclosed in #ifdef _ALIAS_SCTP - * - */ #ifndef _ALIAS_LOCAL_H_ #define _ALIAS_LOCAL_H_ @@ -56,16 +50,6 @@ #include <sys/sysctl.h> #ifdef _KERNEL -/* if alias_sctp is not required, #define _ALIAS_SCTP should be commented out */ -#ifndef _ALIAS_SCTP -#define _ALIAS_SCTP -#endif -#ifdef _ALIAS_SCTP -#include <netinet/libalias/alias_sctp.h> -#endif -#endif - -#ifdef _KERNEL #include <sys/malloc.h> #include <sys/param.h> #include <sys/lock.h> @@ -73,6 +57,10 @@ /* XXX: LibAliasSetTarget() uses this constant. */ #define INADDR_NONE 0xffffffff + +#include <netinet/libalias/alias_sctp.h> +#else +#include "alias_sctp.h" #endif /* Sizes of input and output link tables */ @@ -163,33 +151,29 @@ struct libalias { struct in_addr true_addr; /* in network byte order. */ u_short true_port; /* in host byte order. */ - /* - * - *alias_sctp code - */ -#ifdef _ALIAS_SCTP - /*counts associations that have progressed to UP and not yet removed */ - int sctpLinkCount; - /*Timing queue for keeping track of association timeouts */ - struct sctp_nat_timer sctpNatTimer; - - /* Size of hash table used in this instance*/ - u_int sctpNatTableSize; -/** - * @brief Local look up table - * - * lookup table of sctp_nat_assoc sorted by l_vtag/l_port - */ - LIST_HEAD(sctpNatTableL, sctp_nat_assoc) *sctpTableLocal; -/** - * @brief Global look up table - * - * lookup table of sctp_nat_assoc sorted by g_vtag/g_port - */ - LIST_HEAD(sctpNatTableG, sctp_nat_assoc) *sctpTableGlobal; -#endif + /* + * sctp code support + */ + + /* counts associations that have progressed to UP and not yet removed */ + int sctpLinkCount; #ifdef _KERNEL + /* timing queue for keeping track of association timeouts */ + struct sctp_nat_timer sctpNatTimer; + + /* size of hash table used in this instance */ + u_int sctpNatTableSize; + +/* + * local look up table sorted by l_vtag/l_port + */ + LIST_HEAD(sctpNatTableL, sctp_nat_assoc) *sctpTableLocal; +/* + * global look up table sorted by g_vtag/g_port + */ + LIST_HEAD(sctpNatTableG, sctp_nat_assoc) *sctpTableGlobal; + /* * avoid races in libalias: every public function has to use it. */ @@ -240,21 +224,13 @@ struct libalias { /* Prototypes */ - /* - * - *alias_sctp code - */ -#ifdef _ALIAS_SCTP /* * SctpFunction prototypes * */ void AliasSctpInit(struct libalias *la); void AliasSctpTerm(struct libalias *la); - int SctpAlias(struct libalias *la, struct ip *ip, int direction); -//int SctpAliasOut(struct libalias *la, struct ip *ip); -#endif /* * We do not calculate TCP checksums when libalias is a kernel @@ -322,6 +298,8 @@ struct in_addr FindOriginalAddress(struct libalias *la, struct in_addr _alias_addr); struct in_addr FindAliasAddress(struct libalias *la, struct in_addr _original_addr); +struct in_addr +FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm); /* External data access/modification */ int diff --git a/sys/netinet/libalias/alias_nbt.c b/sys/netinet/libalias/alias_nbt.c index 0d17870..924ee6a 100644 --- a/sys/netinet/libalias/alias_nbt.c +++ b/sys/netinet/libalias/alias_nbt.c @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <sys/types.h> #include <stdio.h> +#include <strings.h> #endif #include <netinet/in_systm.h> diff --git a/sys/netinet/libalias/alias_sctp.c b/sys/netinet/libalias/alias_sctp.c index 5cb9acc..89dc979 100644 --- a/sys/netinet/libalias/alias_sctp.c +++ b/sys/netinet/libalias/alias_sctp.c @@ -1,34 +1,9 @@ -//* $Id$ */ -//#ifndef lint -//static char vcid[] = "$Id$"; -//#endif /* lint */ /** * @file alias_sctp.c * Copyright (c) 2008, Centre for Advanced Internet Architectures * Swinburne University of Technology, Melbourne, Australia * (CRICOS number 00111D). * - * Alias_sctp forms part of the libalias kernel module to handle - * Network Address Translation (NAT) for the SCTP protocol. - * - * This software was developed by David A. Hayes and Jason But - * - * The design is outlined in CAIA technical report number 080618A - * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW") - * - * Development is part of the CAIA SONATA project, - * proposed by Jason But and Grenville Armitage: - * http://caia.swin.edu.au/urp/sonata/ - * - * - * This project has been made possible in part by a grant from - * the Cisco University Research Program Fund at Community - * Foundation Silicon Valley. - * - * - * - * All rights reserved. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -54,6 +29,23 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Alias_sctp forms part of the libalias kernel module to handle + * Network Address Translation (NAT) for the SCTP protocol. + * + * This software was developed by David A. Hayes and Jason But + * + * The design is outlined in CAIA technical report number 080618A + * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW") + * + * Development is part of the CAIA SONATA project, + * proposed by Jason But and Grenville Armitage: + * http://caia.swin.edu.au/urp/sonata/ + * + * + * This project has been made possible in part by a grant from + * the Cisco University Research Program Fund at Community + * Foundation Silicon Valley. + * */ /** @mainpage * Alias_sctp is part of the SONATA (http://caia.swin.edu.au/urp/sonata) project @@ -80,6 +72,8 @@ * - Dynamic control of hash-table size */ +/* $FreeBSD$ */ + #ifdef _KERNEL #include <machine/stdarg.h> #include <sys/param.h> @@ -107,9 +101,9 @@ */ /* Packet Parsing Functions */ static int sctp_PktParser(struct libalias *la, int direction, struct ip *pip, - struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc); + struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc); static int GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, - uint32_t *l_vtag, uint32_t *g_vtag, int direction); + uint32_t *l_vtag, uint32_t *g_vtag, int direction); static int IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction); static void AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction); @@ -119,20 +113,20 @@ static int IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int directio /* State Machine Functions */ static int ProcessSctpMsg(struct libalias *la, int direction, \ - struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc); + struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc); static int ID_process(struct libalias *la, int direction,\ - struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); + struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); static int INi_process(struct libalias *la, int direction,\ - struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); + struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); static int INa_process(struct libalias *la, int direction,\ - struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); + struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); static int UP_process(struct libalias *la, int direction,\ - struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); + struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); static int CL_process(struct libalias *la, int direction,\ - struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); + struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); static void TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm,\ - struct sctp_nat_assoc *assoc, int sndrply, int direction); + struct sctp_nat_assoc *assoc, int sndrply, int direction); /* Hash Table Functions */ static struct sctp_nat_assoc* @@ -189,22 +183,6 @@ static void SctpAliasLog(const char *format, ...); */ void SctpShowAliasStats(struct libalias *la); -/** @ingroup external - * @brief Find the address to redirect incoming packets - * - * This function is defined in alias_db.c, since it calls static functions in - * this file - * - * Given a destination port for incoming packets to the NAT, discover what - * (if any) internal IP address this packet should be re-directed to - * - * @param la Pointer to the libalias instance - * @param sm Pointer to the incoming message - * - * @return Address to redirect an incoming INIT to - */ -struct in_addr FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm); - #ifdef _KERNEL MALLOC_DEFINE(M_SCTPNAT, "sctpnat", "sctp nat dbs"); @@ -364,9 +342,9 @@ static u_int sysctl_holddown_timer = 0; /**< Seconds to hold an association in t static u_int sysctl_hashtable_size = SN_DEFAULT_HASH_SIZE; /**< Sets the hash table size for any NEW NAT instances (existing instances retain their existing Hash Table */ /** @brief net.inet.ip.alias.sctp.error_on_ootb */ static u_int sysctl_error_on_ootb = 1; /**< NAT response to receipt of OOTB packet - (0 - No response, 1 - NAT will send ErrorM only to local side, - 2 - NAT will send local ErrorM and global ErrorM if there was a partial association match - 3 - NAT will send ErrorM to both local and global) */ + (0 - No response, 1 - NAT will send ErrorM only to local side, + 2 - NAT will send local ErrorM and global ErrorM if there was a partial association match + 3 - NAT will send ErrorM to both local and global) */ /** @brief net.inet.ip.alias.sctp.accept_global_ootb_addip */ static u_int sysctl_accept_global_ootb_addip = 0; /**<NAT responset to receipt of global OOTB AddIP (0 - No response, 1 - NAT will accept OOTB global AddIP messages for processing (Security risk)) */ /** @brief net.inet.ip.alias.sctp.initialising_chunk_proc_limit */ @@ -377,7 +355,7 @@ static u_int sysctl_chunk_proc_limit = 5; /**< A limit on the number of chunks t static u_int sysctl_param_proc_limit = 25; /**< A limit on the number of parameters (in chunks) that should be searched (DoS prevention) */ /** @brief net.inet.ip.alias.sctp.track_global_addresses */ static u_int sysctl_track_global_addresses = 0; /**< Configures the global address tracking option within the NAT (0 - Global tracking is disabled, > 0 - enables tracking but limits the number of global IP addresses to this value) - If set to >=1 the NAT will track that many global IP addresses. This may reduce look up table conflicts, but increases processing */ + If set to >=1 the NAT will track that many global IP addresses. This may reduce look up table conflicts, but increases processing */ #define SN_NO_ERROR_ON_OOTB 0 /**< Send no errorM on out of the blue packets */ #define SN_LOCAL_ERROR_ON_OOTB 1 /**< Send only local errorM on out of the blue packets */ @@ -393,41 +371,41 @@ SYSCTL_DECL(_net_inet_ip_alias); SYSCTL_NODE(_net_inet_ip_alias, OID_AUTO, sctp, CTLFLAG_RW, NULL, "SCTP NAT"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, log_level, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_log_level, 0, sysctl_chg_loglevel, "IU", - "Level of detail (0 - default, 1 - event, 2 - info, 3 - detail, 4 - debug, 5 - max debug)"); + &sysctl_log_level, 0, sysctl_chg_loglevel, "IU", + "Level of detail (0 - default, 1 - event, 2 - info, 3 - detail, 4 - debug, 5 - max debug)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, init_timer, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_init_timer, 0, sysctl_chg_timer, "IU", - "Timeout value (s) while waiting for (INIT-ACK|AddIP-ACK)"); + &sysctl_init_timer, 0, sysctl_chg_timer, "IU", + "Timeout value (s) while waiting for (INIT-ACK|AddIP-ACK)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, up_timer, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_up_timer, 0, sysctl_chg_timer, "IU", - "Timeout value (s) to keep an association up with no traffic"); + &sysctl_up_timer, 0, sysctl_chg_timer, "IU", + "Timeout value (s) to keep an association up with no traffic"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, shutdown_timer, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_shutdown_timer, 0, sysctl_chg_timer, "IU", - "Timeout value (s) while waiting for SHUTDOWN-COMPLETE"); + &sysctl_shutdown_timer, 0, sysctl_chg_timer, "IU", + "Timeout value (s) while waiting for SHUTDOWN-COMPLETE"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, holddown_timer, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_holddown_timer, 0, sysctl_chg_timer, "IU", - "Hold association in table for this many seconds after receiving a SHUTDOWN-COMPLETE"); + &sysctl_holddown_timer, 0, sysctl_chg_timer, "IU", + "Hold association in table for this many seconds after receiving a SHUTDOWN-COMPLETE"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, hashtable_size, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_hashtable_size, 0, sysctl_chg_hashtable_size, "IU", - "Size of hash tables used for NAT lookups (100 < prime_number > 1000001)"); + &sysctl_hashtable_size, 0, sysctl_chg_hashtable_size, "IU", + "Size of hash tables used for NAT lookups (100 < prime_number > 1000001)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, error_on_ootb, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_error_on_ootb, 0, sysctl_chg_error_on_ootb, "IU", - "ErrorM sent on receipt of ootb packet:\n\t0 - none,\n\t1 - to local only,\n\t2 - to local and global if a partial association match,\n\t3 - to local and global (DoS risk)"); + &sysctl_error_on_ootb, 0, sysctl_chg_error_on_ootb, "IU", + "ErrorM sent on receipt of ootb packet:\n\t0 - none,\n\t1 - to local only,\n\t2 - to local and global if a partial association match,\n\t3 - to local and global (DoS risk)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, accept_global_ootb_addip, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_accept_global_ootb_addip, 0, sysctl_chg_accept_global_ootb_addip, "IU", - "NAT response to receipt of global OOTB AddIP:\n\t0 - No response,\n\t1 - NAT will accept OOTB global AddIP messages for processing (Security risk)"); + &sysctl_accept_global_ootb_addip, 0, sysctl_chg_accept_global_ootb_addip, "IU", + "NAT response to receipt of global OOTB AddIP:\n\t0 - No response,\n\t1 - NAT will accept OOTB global AddIP messages for processing (Security risk)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, initialising_chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_initialising_chunk_proc_limit, 0, sysctl_chg_initialising_chunk_proc_limit, "IU", - "Number of chunks that should be processed if there is no current association found:\n\t > 0 (A high value is a DoS risk)"); + &sysctl_initialising_chunk_proc_limit, 0, sysctl_chg_initialising_chunk_proc_limit, "IU", + "Number of chunks that should be processed if there is no current association found:\n\t > 0 (A high value is a DoS risk)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_chunk_proc_limit, 0, sysctl_chg_chunk_proc_limit, "IU", - "Number of chunks that should be processed to find key chunk:\n\t>= initialising_chunk_proc_limit (A high value is a DoS risk)"); + &sysctl_chunk_proc_limit, 0, sysctl_chg_chunk_proc_limit, "IU", + "Number of chunks that should be processed to find key chunk:\n\t>= initialising_chunk_proc_limit (A high value is a DoS risk)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, param_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_param_proc_limit, 0, sysctl_chg_param_proc_limit, "IU", - "Number of parameters (in a chunk) that should be processed to find key parameters:\n\t> 1 (A high value is a DoS risk)"); + &sysctl_param_proc_limit, 0, sysctl_chg_param_proc_limit, "IU", + "Number of parameters (in a chunk) that should be processed to find key parameters:\n\t> 1 (A high value is a DoS risk)"); SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, track_global_addresses, CTLTYPE_UINT | CTLFLAG_RW, - &sysctl_track_global_addresses, 0, sysctl_chg_track_global_addresses, "IU", - "Configures the global address tracking option within the NAT:\n\t0 - Global tracking is disabled,\n\t> 0 - enables tracking but limits the number of global IP addresses to this value"); + &sysctl_track_global_addresses, 0, sysctl_chg_track_global_addresses, "IU", + "Configures the global address tracking option within the NAT:\n\t0 - Global tracking is disabled,\n\t> 0 - enables tracking but limits the number of global IP addresses to this value"); #endif /* SYSCTL_NODE */ @@ -440,16 +418,16 @@ SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, track_global_addresses, CTLTYPE_U */ int sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS) { - u_int level = *(u_int *)arg1; - int error; + u_int level = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &level, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &level, 0, req); + if (error) return (error); - sysctl_log_level = (level > SN_LOG_DEBUG_MAX)?(SN_LOG_DEBUG_MAX):(level); - sysctl_log_level = (level < SN_LOG_LOW)?(SN_LOG_LOW):(level); + sysctl_log_level = (level > SN_LOG_DEBUG_MAX)?(SN_LOG_DEBUG_MAX):(level); + sysctl_log_level = (level < SN_LOG_LOW)?(SN_LOG_LOW):(level); - return (0); + return (0); } /** @ingroup sysctl @@ -461,22 +439,22 @@ int sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_timer(SYSCTL_HANDLER_ARGS) { - u_int timer = *(u_int *)arg1; - int error; + u_int timer = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &timer, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &timer, 0, req); + if (error) return (error); - timer = (timer > SN_MAX_TIMER)?(SN_MAX_TIMER):(timer); + timer = (timer > SN_MAX_TIMER)?(SN_MAX_TIMER):(timer); - if (((u_int *)arg1) != &sysctl_holddown_timer) - { - timer = (timer < SN_MIN_TIMER)?(SN_MIN_TIMER):(timer); - } + if (((u_int *)arg1) != &sysctl_holddown_timer) + { + timer = (timer < SN_MIN_TIMER)?(SN_MIN_TIMER):(timer); + } - *(u_int *)arg1 = timer; + *(u_int *)arg1 = timer; - return (0); + return (0); } /** @ingroup sysctl @@ -490,20 +468,20 @@ int sysctl_chg_timer(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS) { - u_int size = *(u_int *)arg1; - int error; + u_int size = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &size, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &size, 0, req); + if (error) return (error); - size = (size < SN_MIN_HASH_SIZE)?(SN_MIN_HASH_SIZE):((size > SN_MAX_HASH_SIZE)?(SN_MAX_HASH_SIZE):(size)); + size = (size < SN_MIN_HASH_SIZE)?(SN_MIN_HASH_SIZE):((size > SN_MAX_HASH_SIZE)?(SN_MAX_HASH_SIZE):(size)); - size |= 0x00000001; /* make odd */ + size |= 0x00000001; /* make odd */ - for(;(((size % 3) == 0) || ((size % 5) == 0) || ((size % 7) == 0) || ((size % 11) == 0)); size+=2); - sysctl_hashtable_size = size; + for(;(((size % 3) == 0) || ((size % 5) == 0) || ((size % 7) == 0) || ((size % 11) == 0)); size+=2); + sysctl_hashtable_size = size; - return (0); + return (0); } /** @ingroup sysctl @@ -518,15 +496,15 @@ int sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS) { - u_int flag = *(u_int *)arg1; - int error; + u_int flag = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &flag, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &flag, 0, req); + if (error) return (error); - sysctl_error_on_ootb = (flag > SN_ERROR_ON_OOTB) ? SN_ERROR_ON_OOTB: flag; + sysctl_error_on_ootb = (flag > SN_ERROR_ON_OOTB) ? SN_ERROR_ON_OOTB: flag; - return (0); + return (0); } /** @ingroup sysctl @@ -537,15 +515,15 @@ int sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS) { - u_int flag = *(u_int *)arg1; - int error; + u_int flag = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &flag, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &flag, 0, req); + if (error) return (error); - sysctl_accept_global_ootb_addip = (flag == 1) ? 1: 0; + sysctl_accept_global_ootb_addip = (flag == 1) ? 1: 0; - return (0); + return (0); } /** @ingroup sysctl @@ -557,17 +535,17 @@ int sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS) { - u_int proclimit = *(u_int *)arg1; - int error; + u_int proclimit = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &proclimit, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &proclimit, 0, req); + if (error) return (error); - sysctl_initialising_chunk_proc_limit = (proclimit < 1) ? 1: proclimit; - sysctl_chunk_proc_limit = - (sysctl_chunk_proc_limit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : sysctl_chunk_proc_limit; + sysctl_initialising_chunk_proc_limit = (proclimit < 1) ? 1: proclimit; + sysctl_chunk_proc_limit = + (sysctl_chunk_proc_limit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : sysctl_chunk_proc_limit; - return (0); + return (0); } /** @ingroup sysctl @@ -579,16 +557,16 @@ int sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS) { - u_int proclimit = *(u_int *)arg1; - int error; + u_int proclimit = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &proclimit, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &proclimit, 0, req); + if (error) return (error); - sysctl_chunk_proc_limit = - (proclimit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : proclimit; + sysctl_chunk_proc_limit = + (proclimit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : proclimit; - return (0); + return (0); } @@ -601,16 +579,16 @@ int sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS) { - u_int proclimit = *(u_int *)arg1; - int error; + u_int proclimit = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &proclimit, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &proclimit, 0, req); + if (error) return (error); - sysctl_param_proc_limit = - (proclimit < 2) ? 2 : proclimit; + sysctl_param_proc_limit = + (proclimit < 2) ? 2 : proclimit; - return (0); + return (0); } /** @ingroup sysctl @@ -622,15 +600,15 @@ int sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS) */ int sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS) { - u_int num_to_track = *(u_int *)arg1; - int error; + u_int num_to_track = *(u_int *)arg1; + int error; - error = sysctl_handle_int(oidp, &num_to_track, 0, req); - if (error) return (error); + error = sysctl_handle_int(oidp, &num_to_track, 0, req); + if (error) return (error); - sysctl_track_global_addresses = (num_to_track > SN_MAX_GLOBAL_ADDRESSES) ? SN_MAX_GLOBAL_ADDRESSES : num_to_track; + sysctl_track_global_addresses = (num_to_track > SN_MAX_GLOBAL_ADDRESSES) ? SN_MAX_GLOBAL_ADDRESSES : num_to_track; - return (0); + return (0); } @@ -648,30 +626,30 @@ int sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS) */ void AliasSctpInit(struct libalias *la) { - /* Initialise association tables*/ - int i; - la->sctpNatTableSize = sysctl_hashtable_size; - SN_LOG(SN_LOG_EVENT, - SctpAliasLog("Initialising SCTP NAT Instance (hash_table_size:%d)\n", la->sctpNatTableSize)); - la->sctpTableLocal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableL)); - la->sctpTableGlobal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableG)); - la->sctpNatTimer.TimerQ = sn_calloc(SN_TIMER_QUEUE_SIZE, sizeof(struct sctpTimerQ)); - /* Initialise hash table */ - for (i = 0; i < la->sctpNatTableSize; i++) { - LIST_INIT(&la->sctpTableLocal[i]); - LIST_INIT(&la->sctpTableGlobal[i]); - } - - /* Initialise circular timer Q*/ - for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) - LIST_INIT(&la->sctpNatTimer.TimerQ[i]); + /* Initialise association tables*/ + int i; + la->sctpNatTableSize = sysctl_hashtable_size; + SN_LOG(SN_LOG_EVENT, + SctpAliasLog("Initialising SCTP NAT Instance (hash_table_size:%d)\n", la->sctpNatTableSize)); + la->sctpTableLocal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableL)); + la->sctpTableGlobal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableG)); + la->sctpNatTimer.TimerQ = sn_calloc(SN_TIMER_QUEUE_SIZE, sizeof(struct sctpTimerQ)); + /* Initialise hash table */ + for (i = 0; i < la->sctpNatTableSize; i++) { + LIST_INIT(&la->sctpTableLocal[i]); + LIST_INIT(&la->sctpTableGlobal[i]); + } + + /* Initialise circular timer Q*/ + for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) + LIST_INIT(&la->sctpNatTimer.TimerQ[i]); #ifdef _KERNEL - la->sctpNatTimer.loc_time=time_uptime; /* la->timeStamp is not set yet */ + la->sctpNatTimer.loc_time=time_uptime; /* la->timeStamp is not set yet */ #else - la->sctpNatTimer.loc_time=la->timeStamp; + la->sctpNatTimer.loc_time=la->timeStamp; #endif - la->sctpNatTimer.cur_loc = 0; - la->sctpLinkCount = 0; + la->sctpNatTimer.cur_loc = 0; + la->sctpLinkCount = 0; } /** @@ -688,25 +666,25 @@ void AliasSctpInit(struct libalias *la) */ void AliasSctpTerm(struct libalias *la) { - struct sctp_nat_assoc *assoc1, *assoc2; - int i; - - LIBALIAS_LOCK_ASSERT(la); - SN_LOG(SN_LOG_EVENT, - SctpAliasLog("Removing SCTP NAT Instance\n")); - for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) { - assoc1 = LIST_FIRST(&la->sctpNatTimer.TimerQ[i]); - while (assoc1 != NULL) { - freeGlobalAddressList(assoc1); - assoc2 = LIST_NEXT(assoc1, timer_Q); - sn_free(assoc1); - assoc1 = assoc2; - } - } - - sn_free(la->sctpTableLocal); - sn_free(la->sctpTableGlobal); - sn_free(la->sctpNatTimer.TimerQ); + struct sctp_nat_assoc *assoc1, *assoc2; + int i; + + LIBALIAS_LOCK_ASSERT(la); + SN_LOG(SN_LOG_EVENT, + SctpAliasLog("Removing SCTP NAT Instance\n")); + for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) { + assoc1 = LIST_FIRST(&la->sctpNatTimer.TimerQ[i]); + while (assoc1 != NULL) { + freeGlobalAddressList(assoc1); + assoc2 = LIST_NEXT(assoc1, timer_Q); + sn_free(assoc1); + assoc1 = assoc2; + } + } + + sn_free(la->sctpTableLocal); + sn_free(la->sctpTableGlobal); + sn_free(la->sctpNatTimer.TimerQ); } /** @@ -735,122 +713,122 @@ void AliasSctpTerm(struct libalias *la) int SctpAlias(struct libalias *la, struct ip *pip, int direction) { - int rtnval; - struct sctp_nat_msg msg; - struct sctp_nat_assoc *assoc = NULL; - - if ((direction != SN_TO_LOCAL) && (direction != SN_TO_GLOBAL)) { - SctpAliasLog("ERROR: Invalid direction\n"); - return(PKT_ALIAS_ERROR); - } - - sctp_CheckTimers(la); /* Check timers */ - - /* Parse the packet */ - rtnval = sctp_PktParser(la, direction, pip, &msg, &assoc); //using *char (change to mbuf when get code from paolo) - switch (rtnval) { - case SN_PARSE_OK: - break; - case SN_PARSE_ERROR_CHHL: - /* Not an error if there is a chunk length parsing error and this is a fragmented packet */ - if (ntohs(pip->ip_off) & IP_MF) { - rtnval = SN_PARSE_OK; - break; - } - SN_LOG(SN_LOG_EVENT, - logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); - return(PKT_ALIAS_ERROR); - case SN_PARSE_ERROR_PARTIALLOOKUP: - if (sysctl_error_on_ootb > SN_LOCALandPARTIAL_ERROR_ON_OOTB) { - SN_LOG(SN_LOG_EVENT, - logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); - return(PKT_ALIAS_ERROR); - } - case SN_PARSE_ERROR_LOOKUP: - if (sysctl_error_on_ootb == SN_ERROR_ON_OOTB || - (sysctl_error_on_ootb == SN_LOCALandPARTIAL_ERROR_ON_OOTB && direction == SN_TO_LOCAL) || - (sysctl_error_on_ootb == SN_LOCAL_ERROR_ON_OOTB && direction == SN_TO_GLOBAL)) { - TxAbortErrorM(la, &msg, assoc, SN_REFLECT_ERROR, direction); /*NB assoc=NULL */ - return(PKT_ALIAS_RESPOND); - } - default: - SN_LOG(SN_LOG_EVENT, - logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); - return(PKT_ALIAS_ERROR); - } - - SN_LOG(SN_LOG_DETAIL, - logsctpassoc(assoc, "*"); - logsctpparse(direction, &msg); - ); - - /* Process the SCTP message */ - rtnval = ProcessSctpMsg(la, direction, &msg, assoc); - - SN_LOG(SN_LOG_DEBUG_MAX, - logsctpassoc(assoc, "-"); - logSctpLocal(la); - logSctpGlobal(la); - ); - SN_LOG(SN_LOG_DEBUG, logTimerQ(la)); - - switch(rtnval){ - case SN_NAT_PKT: - switch(direction) { - case SN_TO_LOCAL: - DifferentialChecksum(&(msg.ip_hdr->ip_sum), - &(assoc->l_addr), &(msg.ip_hdr->ip_dst), 2); - msg.ip_hdr->ip_dst = assoc->l_addr; /* change dst address to local address*/ - break; - case SN_TO_GLOBAL: - DifferentialChecksum(&(msg.ip_hdr->ip_sum), - &(assoc->a_addr), &(msg.ip_hdr->ip_src), 2); - msg.ip_hdr->ip_src = assoc->a_addr; /* change src to alias addr*/ - break; - default: - rtnval = SN_DROP_PKT; /* shouldn't get here, but if it does drop packet */ - SN_LOG(SN_LOG_LOW, logsctperror("ERROR: Invalid direction", msg.sctp_hdr->v_tag, rtnval, direction)); - break; - } - break; - case SN_DROP_PKT: - SN_LOG(SN_LOG_DETAIL, logsctperror("SN_DROP_PKT", msg.sctp_hdr->v_tag, rtnval, direction)); - break; - case SN_REPLY_ABORT: - case SN_REPLY_ERROR: - case SN_SEND_ABORT: - TxAbortErrorM(la, &msg, assoc, rtnval, direction); - break; - default: - // big error, remove association and go to idle and write log messages - SN_LOG(SN_LOG_LOW, logsctperror("SN_PROCESSING_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); - assoc->state=SN_RM;/* Mark for removal*/ - break; - } - - /* Remove association if tagged for removal */ - if (assoc->state == SN_RM) { - if (assoc->TableRegister) { - sctp_RmTimeOut(la, assoc); - RmSctpAssoc(la, assoc); - } - LIBALIAS_LOCK_ASSERT(la); - freeGlobalAddressList(assoc); - sn_free(assoc); - } - switch(rtnval) { - case SN_NAT_PKT: - return(PKT_ALIAS_OK); - case SN_SEND_ABORT: - return(PKT_ALIAS_OK); - case SN_REPLY_ABORT: - case SN_REPLY_ERROR: - case SN_REFLECT_ERROR: - return(PKT_ALIAS_RESPOND); - case SN_DROP_PKT: - default: - return(PKT_ALIAS_ERROR); - } + int rtnval; + struct sctp_nat_msg msg; + struct sctp_nat_assoc *assoc = NULL; + + if ((direction != SN_TO_LOCAL) && (direction != SN_TO_GLOBAL)) { + SctpAliasLog("ERROR: Invalid direction\n"); + return(PKT_ALIAS_ERROR); + } + + sctp_CheckTimers(la); /* Check timers */ + + /* Parse the packet */ + rtnval = sctp_PktParser(la, direction, pip, &msg, &assoc); //using *char (change to mbuf when get code from paolo) + switch (rtnval) { + case SN_PARSE_OK: + break; + case SN_PARSE_ERROR_CHHL: + /* Not an error if there is a chunk length parsing error and this is a fragmented packet */ + if (ntohs(pip->ip_off) & IP_MF) { + rtnval = SN_PARSE_OK; + break; + } + SN_LOG(SN_LOG_EVENT, + logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); + return(PKT_ALIAS_ERROR); + case SN_PARSE_ERROR_PARTIALLOOKUP: + if (sysctl_error_on_ootb > SN_LOCALandPARTIAL_ERROR_ON_OOTB) { + SN_LOG(SN_LOG_EVENT, + logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); + return(PKT_ALIAS_ERROR); + } + case SN_PARSE_ERROR_LOOKUP: + if (sysctl_error_on_ootb == SN_ERROR_ON_OOTB || + (sysctl_error_on_ootb == SN_LOCALandPARTIAL_ERROR_ON_OOTB && direction == SN_TO_LOCAL) || + (sysctl_error_on_ootb == SN_LOCAL_ERROR_ON_OOTB && direction == SN_TO_GLOBAL)) { + TxAbortErrorM(la, &msg, assoc, SN_REFLECT_ERROR, direction); /*NB assoc=NULL */ + return(PKT_ALIAS_RESPOND); + } + default: + SN_LOG(SN_LOG_EVENT, + logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); + return(PKT_ALIAS_ERROR); + } + + SN_LOG(SN_LOG_DETAIL, + logsctpassoc(assoc, "*"); + logsctpparse(direction, &msg); + ); + + /* Process the SCTP message */ + rtnval = ProcessSctpMsg(la, direction, &msg, assoc); + + SN_LOG(SN_LOG_DEBUG_MAX, + logsctpassoc(assoc, "-"); + logSctpLocal(la); + logSctpGlobal(la); + ); + SN_LOG(SN_LOG_DEBUG, logTimerQ(la)); + + switch(rtnval){ + case SN_NAT_PKT: + switch(direction) { + case SN_TO_LOCAL: + DifferentialChecksum(&(msg.ip_hdr->ip_sum), + &(assoc->l_addr), &(msg.ip_hdr->ip_dst), 2); + msg.ip_hdr->ip_dst = assoc->l_addr; /* change dst address to local address*/ + break; + case SN_TO_GLOBAL: + DifferentialChecksum(&(msg.ip_hdr->ip_sum), + &(assoc->a_addr), &(msg.ip_hdr->ip_src), 2); + msg.ip_hdr->ip_src = assoc->a_addr; /* change src to alias addr*/ + break; + default: + rtnval = SN_DROP_PKT; /* shouldn't get here, but if it does drop packet */ + SN_LOG(SN_LOG_LOW, logsctperror("ERROR: Invalid direction", msg.sctp_hdr->v_tag, rtnval, direction)); + break; + } + break; + case SN_DROP_PKT: + SN_LOG(SN_LOG_DETAIL, logsctperror("SN_DROP_PKT", msg.sctp_hdr->v_tag, rtnval, direction)); + break; + case SN_REPLY_ABORT: + case SN_REPLY_ERROR: + case SN_SEND_ABORT: + TxAbortErrorM(la, &msg, assoc, rtnval, direction); + break; + default: + // big error, remove association and go to idle and write log messages + SN_LOG(SN_LOG_LOW, logsctperror("SN_PROCESSING_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); + assoc->state=SN_RM;/* Mark for removal*/ + break; + } + + /* Remove association if tagged for removal */ + if (assoc->state == SN_RM) { + if (assoc->TableRegister) { + sctp_RmTimeOut(la, assoc); + RmSctpAssoc(la, assoc); + } + LIBALIAS_LOCK_ASSERT(la); + freeGlobalAddressList(assoc); + sn_free(assoc); + } + switch(rtnval) { + case SN_NAT_PKT: + return(PKT_ALIAS_OK); + case SN_SEND_ABORT: + return(PKT_ALIAS_OK); + case SN_REPLY_ABORT: + case SN_REPLY_ERROR: + case SN_REFLECT_ERROR: + return(PKT_ALIAS_RESPOND); + case SN_DROP_PKT: + default: + return(PKT_ALIAS_ERROR); + } } /** @@ -889,92 +867,92 @@ SctpAlias(struct libalias *la, struct ip *pip, int direction) static void TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int sndrply, int direction) { - int sctp_size = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause); - int ip_size = sizeof(struct ip) + sctp_size; - int include_error_cause = 1; - char tmp_ip[ip_size]; - - if (ntohs(sm->ip_hdr->ip_len) < ip_size) { /* short packet, cannot send error cause */ - include_error_cause = 0; - ip_size = ip_size - sizeof(struct sctp_error_cause); - sctp_size = sctp_size - sizeof(struct sctp_error_cause); - } - /* Assign header pointers packet */ - struct ip* ip = (struct ip *) tmp_ip; - struct sctphdr* sctp_hdr = (struct sctphdr *) ((char *) ip + sizeof(*ip)); - struct sctp_chunkhdr* chunk_hdr = (struct sctp_chunkhdr *) ((char *) sctp_hdr + sizeof(*sctp_hdr)); - struct sctp_error_cause* error_cause = (struct sctp_error_cause *) ((char *) chunk_hdr + sizeof(*chunk_hdr)); - - /* construct ip header */ - ip->ip_v = sm->ip_hdr->ip_v; - ip->ip_hl = 5; /* 5*32 bit words */ - ip->ip_tos = 0; - ip->ip_len = htons(ip_size); - ip->ip_id = sm->ip_hdr->ip_id; - ip->ip_off = 0; - ip->ip_ttl = 255; - ip->ip_p = IPPROTO_SCTP; - /* - The definitions below should be removed when they make it into the SCTP stack - */ + int sctp_size = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause); + int ip_size = sizeof(struct ip) + sctp_size; + int include_error_cause = 1; + char tmp_ip[ip_size]; + + if (ntohs(sm->ip_hdr->ip_len) < ip_size) { /* short packet, cannot send error cause */ + include_error_cause = 0; + ip_size = ip_size - sizeof(struct sctp_error_cause); + sctp_size = sctp_size - sizeof(struct sctp_error_cause); + } + /* Assign header pointers packet */ + struct ip* ip = (struct ip *) tmp_ip; + struct sctphdr* sctp_hdr = (struct sctphdr *) ((char *) ip + sizeof(*ip)); + struct sctp_chunkhdr* chunk_hdr = (struct sctp_chunkhdr *) ((char *) sctp_hdr + sizeof(*sctp_hdr)); + struct sctp_error_cause* error_cause = (struct sctp_error_cause *) ((char *) chunk_hdr + sizeof(*chunk_hdr)); + + /* construct ip header */ + ip->ip_v = sm->ip_hdr->ip_v; + ip->ip_hl = 5; /* 5*32 bit words */ + ip->ip_tos = 0; + ip->ip_len = htons(ip_size); + ip->ip_id = sm->ip_hdr->ip_id; + ip->ip_off = 0; + ip->ip_ttl = 255; + ip->ip_p = IPPROTO_SCTP; + /* + The definitions below should be removed when they make it into the SCTP stack + */ #define SCTP_MIDDLEBOX_FLAG 0x02 #define SCTP_NAT_TABLE_COLLISION 0x00b0 #define SCTP_MISSING_NAT 0x00b1 - chunk_hdr->chunk_type = (sndrply & SN_TX_ABORT) ? SCTP_ABORT_ASSOCIATION : SCTP_OPERATION_ERROR; - chunk_hdr->chunk_flags = SCTP_MIDDLEBOX_FLAG; - if (include_error_cause) { - error_cause->code = htons((sndrply & SN_REFLECT_ERROR) ? SCTP_MISSING_NAT : SCTP_NAT_TABLE_COLLISION); - error_cause->length = htons(sizeof(struct sctp_error_cause)); - chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr) + sizeof(struct sctp_error_cause)); - } else { - chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr)); - } - - /* set specific values */ - switch(sndrply) { - case SN_REFLECT_ERROR: - chunk_hdr->chunk_flags |= SCTP_HAD_NO_TCB; /* set Tbit */ - sctp_hdr->v_tag = sm->sctp_hdr->v_tag; - break; - case SN_REPLY_ERROR: - sctp_hdr->v_tag = (direction == SN_TO_LOCAL) ? assoc->g_vtag : assoc->l_vtag ; - break; - case SN_SEND_ABORT: - sctp_hdr->v_tag = sm->sctp_hdr->v_tag; - break; - case SN_REPLY_ABORT: - sctp_hdr->v_tag = sm->sctpchnk.Init->initiate_tag; - break; - } + chunk_hdr->chunk_type = (sndrply & SN_TX_ABORT) ? SCTP_ABORT_ASSOCIATION : SCTP_OPERATION_ERROR; + chunk_hdr->chunk_flags = SCTP_MIDDLEBOX_FLAG; + if (include_error_cause) { + error_cause->code = htons((sndrply & SN_REFLECT_ERROR) ? SCTP_MISSING_NAT : SCTP_NAT_TABLE_COLLISION); + error_cause->length = htons(sizeof(struct sctp_error_cause)); + chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr) + sizeof(struct sctp_error_cause)); + } else { + chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr)); + } + + /* set specific values */ + switch(sndrply) { + case SN_REFLECT_ERROR: + chunk_hdr->chunk_flags |= SCTP_HAD_NO_TCB; /* set Tbit */ + sctp_hdr->v_tag = sm->sctp_hdr->v_tag; + break; + case SN_REPLY_ERROR: + sctp_hdr->v_tag = (direction == SN_TO_LOCAL) ? assoc->g_vtag : assoc->l_vtag ; + break; + case SN_SEND_ABORT: + sctp_hdr->v_tag = sm->sctp_hdr->v_tag; + break; + case SN_REPLY_ABORT: + sctp_hdr->v_tag = sm->sctpchnk.Init->initiate_tag; + break; + } - /* Set send/reply values */ - if (sndrply == SN_SEND_ABORT) { /*pass through NAT */ - ip->ip_src = (direction == SN_TO_LOCAL) ? sm->ip_hdr->ip_src : assoc->a_addr; - ip->ip_dst = (direction == SN_TO_LOCAL) ? assoc->l_addr : sm->ip_hdr->ip_dst; - sctp_hdr->src_port = sm->sctp_hdr->src_port; - sctp_hdr->dest_port = sm->sctp_hdr->dest_port; - } else { /* reply and reflect */ - ip->ip_src = sm->ip_hdr->ip_dst; - ip->ip_dst = sm->ip_hdr->ip_src; - sctp_hdr->src_port = sm->sctp_hdr->dest_port; - sctp_hdr->dest_port = sm->sctp_hdr->src_port; - } + /* Set send/reply values */ + if (sndrply == SN_SEND_ABORT) { /*pass through NAT */ + ip->ip_src = (direction == SN_TO_LOCAL) ? sm->ip_hdr->ip_src : assoc->a_addr; + ip->ip_dst = (direction == SN_TO_LOCAL) ? assoc->l_addr : sm->ip_hdr->ip_dst; + sctp_hdr->src_port = sm->sctp_hdr->src_port; + sctp_hdr->dest_port = sm->sctp_hdr->dest_port; + } else { /* reply and reflect */ + ip->ip_src = sm->ip_hdr->ip_dst; + ip->ip_dst = sm->ip_hdr->ip_src; + sctp_hdr->src_port = sm->sctp_hdr->dest_port; + sctp_hdr->dest_port = sm->sctp_hdr->src_port; + } - /* Calculate IP header checksum */ - ip->ip_sum = in_cksum_hdr(ip); + /* Calculate IP header checksum */ + ip->ip_sum = in_cksum_hdr(ip); - /* calculate SCTP header CRC32 */ - sctp_hdr->checksum = 0; - sctp_hdr->checksum = sctp_csum_finalize(update_crc32(0xffffffff, (unsigned char *) sctp_hdr, sctp_size)); - - memcpy(sm->ip_hdr, ip, ip_size); - - SN_LOG(SN_LOG_EVENT,SctpAliasLog("%s %s 0x%x (->%s:%u vtag=0x%x crc=0x%x)\n", - ((sndrply == SN_SEND_ABORT) ? "Sending" : "Replying"), - ((sndrply & SN_TX_ERROR) ? "ErrorM" : "AbortM"), - (include_error_cause ? ntohs(error_cause->code) : 0), - inet_ntoa(ip->ip_dst),ntohs(sctp_hdr->dest_port), - ntohl(sctp_hdr->v_tag), ntohl(sctp_hdr->checksum))); + /* calculate SCTP header CRC32 */ + sctp_hdr->checksum = 0; + sctp_hdr->checksum = sctp_finalize_crc32(update_crc32(0xffffffff, (unsigned char *) sctp_hdr, sctp_size)); + + memcpy(sm->ip_hdr, ip, ip_size); + + SN_LOG(SN_LOG_EVENT,SctpAliasLog("%s %s 0x%x (->%s:%u vtag=0x%x crc=0x%x)\n", + ((sndrply == SN_SEND_ABORT) ? "Sending" : "Replying"), + ((sndrply & SN_TX_ERROR) ? "ErrorM" : "AbortM"), + (include_error_cause ? ntohs(error_cause->code) : 0), + inet_ntoa(ip->ip_dst),ntohs(sctp_hdr->dest_port), + ntohl(sctp_hdr->v_tag), ntohl(sctp_hdr->checksum))); } /* ---------------------------------------------------------------------- @@ -1004,209 +982,209 @@ TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm, struct sctp_nat_asso */ static int sctp_PktParser(struct libalias *la, int direction, struct ip *pip, - struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc) + struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc) //sctp_PktParser(int direction, struct mbuf *ipak, int ip_hdr_len,struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc) { - struct sctphdr *sctp_hdr; - struct sctp_chunkhdr *chunk_hdr; - struct sctp_paramhdr *param_hdr; - struct in_addr ipv4addr; - int bytes_left; /* bytes left in ip packet */ - int chunk_length; - int chunk_count; - int partial_match = 0; - // mbuf *mp; - // int mlen; - - // mlen = SCTP_HEADER_LEN(i_pak); - // mp = SCTP_HEADER_TO_CHAIN(i_pak); /* does nothing in bsd since header and chain not separate */ - - /* - * Note, that if the VTag is zero, it must be an INIT - * Also, I am only interested in the content of INIT and ADDIP chunks - */ - - // no mbuf stuff from Paolo yet so ... - sm->ip_hdr = pip; - /* remove ip header length from the bytes_left */ - bytes_left = ntohs(pip->ip_len) - (pip->ip_hl << 2); - - /* Check SCTP header length and move to first chunk */ - if (bytes_left < sizeof(struct sctphdr)) { - sm->sctp_hdr = NULL; - return(SN_PARSE_ERROR_IPSHL); /* packet not long enough*/ - } - - sm->sctp_hdr = sctp_hdr = (struct sctphdr *) ip_next(pip); - bytes_left -= sizeof(struct sctphdr); + struct sctphdr *sctp_hdr; + struct sctp_chunkhdr *chunk_hdr; + struct sctp_paramhdr *param_hdr; + struct in_addr ipv4addr; + int bytes_left; /* bytes left in ip packet */ + int chunk_length; + int chunk_count; + int partial_match = 0; + // mbuf *mp; + // int mlen; + + // mlen = SCTP_HEADER_LEN(i_pak); + // mp = SCTP_HEADER_TO_CHAIN(i_pak); /* does nothing in bsd since header and chain not separate */ + + /* + * Note, that if the VTag is zero, it must be an INIT + * Also, I am only interested in the content of INIT and ADDIP chunks + */ + + // no mbuf stuff from Paolo yet so ... + sm->ip_hdr = pip; + /* remove ip header length from the bytes_left */ + bytes_left = ntohs(pip->ip_len) - (pip->ip_hl << 2); + + /* Check SCTP header length and move to first chunk */ + if (bytes_left < sizeof(struct sctphdr)) { + sm->sctp_hdr = NULL; + return(SN_PARSE_ERROR_IPSHL); /* packet not long enough*/ + } + + sm->sctp_hdr = sctp_hdr = (struct sctphdr *) ip_next(pip); + bytes_left -= sizeof(struct sctphdr); - /* Check for valid ports (zero valued ports would find partially initialised associations */ - if (sctp_hdr->src_port == 0 || sctp_hdr->dest_port == 0) - return(SN_PARSE_ERROR_PORT); + /* Check for valid ports (zero valued ports would find partially initialised associations */ + if (sctp_hdr->src_port == 0 || sctp_hdr->dest_port == 0) + return(SN_PARSE_ERROR_PORT); - /* Check length of first chunk */ - if (bytes_left < SN_MIN_CHUNK_SIZE) /* malformed chunk - could cause endless loop*/ - return(SN_PARSE_ERROR_CHHL); /* packet not long enough for this chunk */ + /* Check length of first chunk */ + if (bytes_left < SN_MIN_CHUNK_SIZE) /* malformed chunk - could cause endless loop*/ + return(SN_PARSE_ERROR_CHHL); /* packet not long enough for this chunk */ - /* First chunk */ - chunk_hdr = SN_SCTP_FIRSTCHUNK(sctp_hdr); + /* First chunk */ + chunk_hdr = SN_SCTP_FIRSTCHUNK(sctp_hdr); - chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); - if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) /* malformed chunk - could cause endless loop*/ - return(SN_PARSE_ERROR_CHHL); - - if ((chunk_hdr->chunk_flags & SCTP_HAD_NO_TCB) && - ((chunk_hdr->chunk_type == SCTP_ABORT_ASSOCIATION) || - (chunk_hdr->chunk_type == SCTP_SHUTDOWN_COMPLETE))) { - /* T-Bit set */ - if (direction == SN_TO_LOCAL) - *passoc = FindSctpGlobalT(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); - else - *passoc = FindSctpLocalT(la, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); - } else { - /* Proper v_tag settings */ - if (direction == SN_TO_LOCAL) - *passoc = FindSctpGlobal(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); - else - *passoc = FindSctpLocal(la, pip->ip_src, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port); - } - - chunk_count = 1; - /* Real packet parsing occurs below */ - sm->msg = SN_SCTP_OTHER;/* Initialise to largest value*/ - sm->chunk_length = 0; /* only care about length for key chunks */ - while (IS_SCTP_CONTROL(chunk_hdr)) { - switch(chunk_hdr->chunk_type) { - case SCTP_INITIATION: - if (chunk_length < sizeof(struct sctp_init_chunk)) /* malformed chunk*/ - return(SN_PARSE_ERROR_CHHL); - sm->msg = SN_SCTP_INIT; - sm->sctpchnk.Init = (struct sctp_init *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); - sm->chunk_length = chunk_length; - /* if no existing association, create a new one */ - if (*passoc == NULL) { - if (sctp_hdr->v_tag == 0){ //Init requires vtag=0 - *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); - if (*passoc == NULL) {/* out of resources */ - return(SN_PARSE_ERROR_AS_MALLOC); - } - /* Initialise association - malloc initialises memory to zeros */ - (*passoc)->state = SN_ID; - LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ - (*passoc)->TableRegister = SN_NULL_TBL; - return(SN_PARSE_OK); - } - return(SN_PARSE_ERROR_VTAG); - } - return(SN_PARSE_ERROR_LOOKUP); - case SCTP_INITIATION_ACK: - if (chunk_length < sizeof(struct sctp_init_ack_chunk)) /* malformed chunk*/ - return(SN_PARSE_ERROR_CHHL); - sm->msg = SN_SCTP_INITACK; - sm->sctpchnk.InitAck = (struct sctp_init_ack *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); - sm->chunk_length = chunk_length; - return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK)); - case SCTP_ABORT_ASSOCIATION: /* access only minimum sized chunk */ - sm->msg = SN_SCTP_ABORT; - sm->chunk_length = chunk_length; - return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP_ABORT):(SN_PARSE_OK)); - case SCTP_SHUTDOWN_ACK: - if (chunk_length < sizeof(struct sctp_shutdown_ack_chunk)) /* malformed chunk*/ - return(SN_PARSE_ERROR_CHHL); - if (sm->msg > SN_SCTP_SHUTACK) { - sm->msg = SN_SCTP_SHUTACK; - sm->chunk_length = chunk_length; - } - break; - case SCTP_SHUTDOWN_COMPLETE: /* minimum sized chunk */ - if (sm->msg > SN_SCTP_SHUTCOMP) { - sm->msg = SN_SCTP_SHUTCOMP; - sm->chunk_length = chunk_length; - } - return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK)); - case SCTP_ASCONF: - if (sm->msg > SN_SCTP_ASCONF) { - if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv4addr_param))) /* malformed chunk*/ - return(SN_PARSE_ERROR_CHHL); - //leave parameter searching to later, if required - param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + sizeof(struct sctp_asconf_chunk)); /*compulsory IP parameter*/ - if (ntohs(param_hdr->param_type) == SCTP_IPV4_ADDRESS) { - if ((*passoc == NULL) && (direction == SN_TO_LOCAL)) { /* AddIP with no association */ - /* try look up with the ASCONF packet's alternative address */ - ipv4addr.s_addr = ((struct sctp_ipv4addr_param *) param_hdr)->addr; - *passoc = FindSctpGlobal(la, ipv4addr, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); - } - param_hdr = (struct sctp_paramhdr *) - ((char *) param_hdr + sizeof(struct sctp_ipv4addr_param)); /*asconf's compulsory address parameter */ - sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv4addr_param); /* rest of chunk */ + chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); + if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) /* malformed chunk - could cause endless loop*/ + return(SN_PARSE_ERROR_CHHL); + + if ((chunk_hdr->chunk_flags & SCTP_HAD_NO_TCB) && + ((chunk_hdr->chunk_type == SCTP_ABORT_ASSOCIATION) || + (chunk_hdr->chunk_type == SCTP_SHUTDOWN_COMPLETE))) { + /* T-Bit set */ + if (direction == SN_TO_LOCAL) + *passoc = FindSctpGlobalT(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); + else + *passoc = FindSctpLocalT(la, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); } else { - if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv6addr_param))) /* malformed chunk*/ - return(SN_PARSE_ERROR_CHHL); - param_hdr = (struct sctp_paramhdr *) - ((char *) param_hdr + sizeof(struct sctp_ipv6addr_param)); /*asconf's compulsory address parameter */ - sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv6addr_param); /* rest of chunk */ + /* Proper v_tag settings */ + if (direction == SN_TO_LOCAL) + *passoc = FindSctpGlobal(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); + else + *passoc = FindSctpLocal(la, pip->ip_src, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port); } - sm->msg = SN_SCTP_ASCONF; - sm->sctpchnk.Asconf = param_hdr; + + chunk_count = 1; + /* Real packet parsing occurs below */ + sm->msg = SN_SCTP_OTHER;/* Initialise to largest value*/ + sm->chunk_length = 0; /* only care about length for key chunks */ + while (IS_SCTP_CONTROL(chunk_hdr)) { + switch(chunk_hdr->chunk_type) { + case SCTP_INITIATION: + if (chunk_length < sizeof(struct sctp_init_chunk)) /* malformed chunk*/ + return(SN_PARSE_ERROR_CHHL); + sm->msg = SN_SCTP_INIT; + sm->sctpchnk.Init = (struct sctp_init *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); + sm->chunk_length = chunk_length; + /* if no existing association, create a new one */ + if (*passoc == NULL) { + if (sctp_hdr->v_tag == 0){ //Init requires vtag=0 + *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); + if (*passoc == NULL) {/* out of resources */ + return(SN_PARSE_ERROR_AS_MALLOC); + } + /* Initialise association - malloc initialises memory to zeros */ + (*passoc)->state = SN_ID; + LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ + (*passoc)->TableRegister = SN_NULL_TBL; + return(SN_PARSE_OK); + } + return(SN_PARSE_ERROR_VTAG); + } + return(SN_PARSE_ERROR_LOOKUP); + case SCTP_INITIATION_ACK: + if (chunk_length < sizeof(struct sctp_init_ack_chunk)) /* malformed chunk*/ + return(SN_PARSE_ERROR_CHHL); + sm->msg = SN_SCTP_INITACK; + sm->sctpchnk.InitAck = (struct sctp_init_ack *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); + sm->chunk_length = chunk_length; + return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK)); + case SCTP_ABORT_ASSOCIATION: /* access only minimum sized chunk */ + sm->msg = SN_SCTP_ABORT; + sm->chunk_length = chunk_length; + return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP_ABORT):(SN_PARSE_OK)); + case SCTP_SHUTDOWN_ACK: + if (chunk_length < sizeof(struct sctp_shutdown_ack_chunk)) /* malformed chunk*/ + return(SN_PARSE_ERROR_CHHL); + if (sm->msg > SN_SCTP_SHUTACK) { + sm->msg = SN_SCTP_SHUTACK; + sm->chunk_length = chunk_length; + } + break; + case SCTP_SHUTDOWN_COMPLETE: /* minimum sized chunk */ + if (sm->msg > SN_SCTP_SHUTCOMP) { + sm->msg = SN_SCTP_SHUTCOMP; + sm->chunk_length = chunk_length; + } + return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK)); + case SCTP_ASCONF: + if (sm->msg > SN_SCTP_ASCONF) { + if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv4addr_param))) /* malformed chunk*/ + return(SN_PARSE_ERROR_CHHL); + //leave parameter searching to later, if required + param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + sizeof(struct sctp_asconf_chunk)); /*compulsory IP parameter*/ + if (ntohs(param_hdr->param_type) == SCTP_IPV4_ADDRESS) { + if ((*passoc == NULL) && (direction == SN_TO_LOCAL)) { /* AddIP with no association */ + /* try look up with the ASCONF packet's alternative address */ + ipv4addr.s_addr = ((struct sctp_ipv4addr_param *) param_hdr)->addr; + *passoc = FindSctpGlobal(la, ipv4addr, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); + } + param_hdr = (struct sctp_paramhdr *) + ((char *) param_hdr + sizeof(struct sctp_ipv4addr_param)); /*asconf's compulsory address parameter */ + sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv4addr_param); /* rest of chunk */ + } else { + if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv6addr_param))) /* malformed chunk*/ + return(SN_PARSE_ERROR_CHHL); + param_hdr = (struct sctp_paramhdr *) + ((char *) param_hdr + sizeof(struct sctp_ipv6addr_param)); /*asconf's compulsory address parameter */ + sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv6addr_param); /* rest of chunk */ + } + sm->msg = SN_SCTP_ASCONF; + sm->sctpchnk.Asconf = param_hdr; - if (*passoc == NULL) { /* AddIP with no association */ - *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); - if (*passoc == NULL) {/* out of resources */ - return(SN_PARSE_ERROR_AS_MALLOC); - } - /* Initialise association - malloc initialises memory to zeros */ - (*passoc)->state = SN_ID; - LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ - (*passoc)->TableRegister = SN_NULL_TBL; - return(SN_PARSE_OK); + if (*passoc == NULL) { /* AddIP with no association */ + *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); + if (*passoc == NULL) {/* out of resources */ + return(SN_PARSE_ERROR_AS_MALLOC); + } + /* Initialise association - malloc initialises memory to zeros */ + (*passoc)->state = SN_ID; + LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ + (*passoc)->TableRegister = SN_NULL_TBL; + return(SN_PARSE_OK); + } + } + break; + case SCTP_ASCONF_ACK: + if (sm->msg > SN_SCTP_ASCONFACK) { + if (chunk_length < sizeof(struct sctp_asconf_ack_chunk)) /* malformed chunk*/ + return(SN_PARSE_ERROR_CHHL); + //leave parameter searching to later, if required + param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + + sizeof(struct sctp_asconf_ack_chunk)); + sm->msg = SN_SCTP_ASCONFACK; + sm->sctpchnk.Asconf = param_hdr; + sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_ack_chunk); + } + break; + default: + break; /* do nothing*/ + } + + /* if no association is found exit - we need to find an Init or AddIP within sysctl_initialising_chunk_proc_limit */ + if ((*passoc == NULL) && (chunk_count >= sysctl_initialising_chunk_proc_limit)) + return(SN_PARSE_ERROR_LOOKUP); + + /* finished with this chunk, on to the next chunk*/ + bytes_left-= chunk_length; + + /* Is this the end of the packet ? */ + if (bytes_left == 0) + return (*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK); + + /* Are there enough bytes in packet to at least retrieve length of next chunk ? */ + if (bytes_left < SN_MIN_CHUNK_SIZE) + return(SN_PARSE_ERROR_CHHL); + + chunk_hdr = SN_SCTP_NEXTCHUNK(chunk_hdr); + + /* Is the chunk long enough to not cause endless look and are there enough bytes in packet to read the chunk ? */ + chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); + if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) + return(SN_PARSE_ERROR_CHHL); + if(++chunk_count > sysctl_chunk_proc_limit) + return(SN_PARSE_OK); /* limit for processing chunks, take what we get */ } - } - break; - case SCTP_ASCONF_ACK: - if (sm->msg > SN_SCTP_ASCONFACK) { - if (chunk_length < sizeof(struct sctp_asconf_ack_chunk)) /* malformed chunk*/ - return(SN_PARSE_ERROR_CHHL); - //leave parameter searching to later, if required - param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr - + sizeof(struct sctp_asconf_ack_chunk)); - sm->msg = SN_SCTP_ASCONFACK; - sm->sctpchnk.Asconf = param_hdr; - sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_ack_chunk); - } - break; - default: - break; /* do nothing*/ - } - - /* if no association is found exit - we need to find an Init or AddIP within sysctl_initialising_chunk_proc_limit */ - if ((*passoc == NULL) && (chunk_count >= sysctl_initialising_chunk_proc_limit)) - return(SN_PARSE_ERROR_LOOKUP); - - /* finished with this chunk, on to the next chunk*/ - bytes_left-= chunk_length; - - /* Is this the end of the packet ? */ - if (bytes_left == 0) - return(SN_PARSE_OK); - - /* Are there enough bytes in packet to at least retrieve length of next chunk ? */ - if (bytes_left < SN_MIN_CHUNK_SIZE) - return(SN_PARSE_ERROR_CHHL); - - chunk_hdr = SN_SCTP_NEXTCHUNK(chunk_hdr); - - /* Is the chunk long enough to not cause endless look and are there enough bytes in packet to read the chunk ? */ - chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); - if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) - return(SN_PARSE_ERROR_CHHL); - if(++chunk_count > sysctl_chunk_proc_limit) - return(SN_PARSE_OK); /* limit for processing chunks, take what we get */ - } - - if (*passoc == NULL) - return (partial_match)?(SN_PARSE_ERROR_PARTIALLOOKUP):(SN_PARSE_ERROR_LOOKUP); - else - return(SN_PARSE_OK); + + if (*passoc == NULL) + return (partial_match)?(SN_PARSE_ERROR_PARTIALLOOKUP):(SN_PARSE_ERROR_LOOKUP); + else + return(SN_PARSE_OK); } /** @ingroup packet_parser @@ -1229,57 +1207,57 @@ sctp_PktParser(struct libalias *la, int direction, struct ip *pip, static int GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, uint32_t *l_vtag, uint32_t *g_vtag, int direction) { - /* To be removed when information is in the sctp headers */ + /* To be removed when information is in the sctp headers */ #define SCTP_VTAG_PARAM 0xC007 - struct sctp_vtag_param { - struct sctp_paramhdr ph;/* type=SCTP_VTAG_PARAM */ - uint32_t local_vtag; - uint32_t remote_vtag; - } __attribute__((packed)); + struct sctp_vtag_param { + struct sctp_paramhdr ph;/* type=SCTP_VTAG_PARAM */ + uint32_t local_vtag; + uint32_t remote_vtag; + } __attribute__((packed)); - struct sctp_vtag_param *vtag_param; - struct sctp_paramhdr *param; - int bytes_left; - int param_size; - int param_count; - - param_count = 1; - param = sm->sctpchnk.Asconf; - param_size = SCTP_SIZE32(ntohs(param->param_length)); - bytes_left = sm->chunk_length; - /* step through Asconf parameters */ - while((bytes_left >= param_size) && (bytes_left >= SN_VTAG_PARAM_SIZE)) { - if (ntohs(param->param_type) == SCTP_VTAG_PARAM) { - vtag_param = (struct sctp_vtag_param *) param; - switch(direction) { - /* The Internet draft is a little ambigious as to order of these vtags. - We think it is this way around. If we are wrong, the order will need - to be changed. */ - case SN_TO_GLOBAL: - *g_vtag = vtag_param->local_vtag; - *l_vtag = vtag_param->remote_vtag; - break; - case SN_TO_LOCAL: - *g_vtag = vtag_param->remote_vtag; - *l_vtag = vtag_param->local_vtag; - break; - } - return(1); /* found */ - } - - bytes_left -= param_size; - if (bytes_left < SN_MIN_PARAM_SIZE) return(0); - - param = SN_SCTP_NEXTPARAM(param); - param_size = SCTP_SIZE32(ntohs(param->param_length)); - if (++param_count > sysctl_param_proc_limit) { - SN_LOG(SN_LOG_EVENT, - logsctperror("Parameter parse limit exceeded (GetAsconfVtags)", - sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); - return(0); /* not found limit exceeded*/ - } - } - return(0); /* not found */ + struct sctp_vtag_param *vtag_param; + struct sctp_paramhdr *param; + int bytes_left; + int param_size; + int param_count; + + param_count = 1; + param = sm->sctpchnk.Asconf; + param_size = SCTP_SIZE32(ntohs(param->param_length)); + bytes_left = sm->chunk_length; + /* step through Asconf parameters */ + while((bytes_left >= param_size) && (bytes_left >= SN_VTAG_PARAM_SIZE)) { + if (ntohs(param->param_type) == SCTP_VTAG_PARAM) { + vtag_param = (struct sctp_vtag_param *) param; + switch(direction) { + /* The Internet draft is a little ambigious as to order of these vtags. + We think it is this way around. If we are wrong, the order will need + to be changed. */ + case SN_TO_GLOBAL: + *g_vtag = vtag_param->local_vtag; + *l_vtag = vtag_param->remote_vtag; + break; + case SN_TO_LOCAL: + *g_vtag = vtag_param->remote_vtag; + *l_vtag = vtag_param->local_vtag; + break; + } + return(1); /* found */ + } + + bytes_left -= param_size; + if (bytes_left < SN_MIN_PARAM_SIZE) return(0); + + param = SN_SCTP_NEXTPARAM(param); + param_size = SCTP_SIZE32(ntohs(param->param_length)); + if (++param_count > sysctl_param_proc_limit) { + SN_LOG(SN_LOG_EVENT, + logsctperror("Parameter parse limit exceeded (GetAsconfVtags)", + sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); + return(0); /* not found limit exceeded*/ + } + } + return(0); /* not found */ } /** @ingroup packet_parser @@ -1296,119 +1274,119 @@ GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, uint32_t *l_vtag, u static void AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction) { - struct sctp_ipv4addr_param *ipv4_param; - struct sctp_paramhdr *param = NULL; - struct sctp_GlobalAddress *G_Addr; - struct in_addr g_addr = {0}; - int bytes_left = 0; - int param_size; - int param_count, addr_param_count = 0; - - switch(direction) { - case SN_TO_GLOBAL: /* does not contain global addresses */ - g_addr = sm->ip_hdr->ip_dst; - bytes_left = 0; /* force exit */ - break; - case SN_TO_LOCAL: - g_addr = sm->ip_hdr->ip_src; - param_count = 1; - switch(sm->msg) { - case SN_SCTP_INIT: - bytes_left = sm->chunk_length - sizeof(struct sctp_init_chunk); - param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.Init + sizeof(struct sctp_init)); - break; - case SN_SCTP_INITACK: - bytes_left = sm->chunk_length - sizeof(struct sctp_init_ack_chunk); - param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.InitAck + sizeof(struct sctp_init_ack)); - break; - case SN_SCTP_ASCONF: - bytes_left = sm->chunk_length; - param = sm->sctpchnk.Asconf; - break; - } - } - if (bytes_left >= SN_MIN_PARAM_SIZE) - param_size = SCTP_SIZE32(ntohs(param->param_length)); - else - param_size = bytes_left+1; /* force skip loop */ + struct sctp_ipv4addr_param *ipv4_param; + struct sctp_paramhdr *param = NULL; + struct sctp_GlobalAddress *G_Addr; + struct in_addr g_addr = {0}; + int bytes_left = 0; + int param_size; + int param_count, addr_param_count = 0; + + switch(direction) { + case SN_TO_GLOBAL: /* does not contain global addresses */ + g_addr = sm->ip_hdr->ip_dst; + bytes_left = 0; /* force exit */ + break; + case SN_TO_LOCAL: + g_addr = sm->ip_hdr->ip_src; + param_count = 1; + switch(sm->msg) { + case SN_SCTP_INIT: + bytes_left = sm->chunk_length - sizeof(struct sctp_init_chunk); + param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.Init + sizeof(struct sctp_init)); + break; + case SN_SCTP_INITACK: + bytes_left = sm->chunk_length - sizeof(struct sctp_init_ack_chunk); + param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.InitAck + sizeof(struct sctp_init_ack)); + break; + case SN_SCTP_ASCONF: + bytes_left = sm->chunk_length; + param = sm->sctpchnk.Asconf; + break; + } + } + if (bytes_left >= SN_MIN_PARAM_SIZE) + param_size = SCTP_SIZE32(ntohs(param->param_length)); + else + param_size = bytes_left+1; /* force skip loop */ - if ((assoc->state == SN_ID) && ((sm->msg == SN_SCTP_INIT) || (bytes_left < SN_MIN_PARAM_SIZE))) {/* add pkt address */ - G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); - if (G_Addr == NULL) {/* out of resources */ - SN_LOG(SN_LOG_EVENT, - logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", - sm->sctp_hdr->v_tag, 0, direction)); - assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ - sysctl_track_global_addresses=0; - return; - } - G_Addr->g_addr = g_addr; - if (!Add_Global_Address_to_List(assoc, G_Addr)) - SN_LOG(SN_LOG_EVENT, - logsctperror("AddGlobalIPAddress: Address already in list", - sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); - } - - /* step through parameters */ - while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { - if (assoc->num_Gaddr >= sysctl_track_global_addresses) { - SN_LOG(SN_LOG_EVENT, - logsctperror("AddGlobalIPAddress: Maximum Number of addresses reached", - sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); - return; - } - switch(ntohs(param->param_type)) { - case SCTP_ADD_IP_ADDRESS: - /* skip to address parameter - leave param_size so bytes left will be calculated properly*/ - param = (struct sctp_paramhdr *) &((struct sctp_asconf_addrv4_param *) param)->addrp; - case SCTP_IPV4_ADDRESS: - ipv4_param = (struct sctp_ipv4addr_param *) param; - /* add addresses to association */ - G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); - if (G_Addr == NULL) {/* out of resources */ - SN_LOG(SN_LOG_EVENT, - logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", - sm->sctp_hdr->v_tag, 0, direction)); - assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ - sysctl_track_global_addresses=0; - return; - } - /* add address */ - addr_param_count++; - if ((sm->msg == SN_SCTP_ASCONF) && (ipv4_param->addr == INADDR_ANY)) { /* use packet address */ - G_Addr->g_addr = g_addr; - if (!Add_Global_Address_to_List(assoc, G_Addr)) - SN_LOG(SN_LOG_EVENT, - logsctperror("AddGlobalIPAddress: Address already in list", - sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); - return; /*shouldn't be any other addresses if the zero address is given*/ - } else { - G_Addr->g_addr.s_addr = ipv4_param->addr; - if (!Add_Global_Address_to_List(assoc, G_Addr)) - SN_LOG(SN_LOG_EVENT, - logsctperror("AddGlobalIPAddress: Address already in list", - sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); - } - } + if ((assoc->state == SN_ID) && ((sm->msg == SN_SCTP_INIT) || (bytes_left < SN_MIN_PARAM_SIZE))) {/* add pkt address */ + G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); + if (G_Addr == NULL) {/* out of resources */ + SN_LOG(SN_LOG_EVENT, + logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", + sm->sctp_hdr->v_tag, 0, direction)); + assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ + sysctl_track_global_addresses=0; + return; + } + G_Addr->g_addr = g_addr; + if (!Add_Global_Address_to_List(assoc, G_Addr)) + SN_LOG(SN_LOG_EVENT, + logsctperror("AddGlobalIPAddress: Address already in list", + sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); + } + + /* step through parameters */ + while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { + if (assoc->num_Gaddr >= sysctl_track_global_addresses) { + SN_LOG(SN_LOG_EVENT, + logsctperror("AddGlobalIPAddress: Maximum Number of addresses reached", + sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); + return; + } + switch(ntohs(param->param_type)) { + case SCTP_ADD_IP_ADDRESS: + /* skip to address parameter - leave param_size so bytes left will be calculated properly*/ + param = (struct sctp_paramhdr *) &((struct sctp_asconf_addrv4_param *) param)->addrp; + case SCTP_IPV4_ADDRESS: + ipv4_param = (struct sctp_ipv4addr_param *) param; + /* add addresses to association */ + G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); + if (G_Addr == NULL) {/* out of resources */ + SN_LOG(SN_LOG_EVENT, + logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", + sm->sctp_hdr->v_tag, 0, direction)); + assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ + sysctl_track_global_addresses=0; + return; + } + /* add address */ + addr_param_count++; + if ((sm->msg == SN_SCTP_ASCONF) && (ipv4_param->addr == INADDR_ANY)) { /* use packet address */ + G_Addr->g_addr = g_addr; + if (!Add_Global_Address_to_List(assoc, G_Addr)) + SN_LOG(SN_LOG_EVENT, + logsctperror("AddGlobalIPAddress: Address already in list", + sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); + return; /*shouldn't be any other addresses if the zero address is given*/ + } else { + G_Addr->g_addr.s_addr = ipv4_param->addr; + if (!Add_Global_Address_to_List(assoc, G_Addr)) + SN_LOG(SN_LOG_EVENT, + logsctperror("AddGlobalIPAddress: Address already in list", + sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); + } + } - bytes_left -= param_size; - if (bytes_left < SN_MIN_PARAM_SIZE) - break; + bytes_left -= param_size; + if (bytes_left < SN_MIN_PARAM_SIZE) + break; - param = SN_SCTP_NEXTPARAM(param); - param_size = SCTP_SIZE32(ntohs(param->param_length)); - if (++param_count > sysctl_param_proc_limit) { - SN_LOG(SN_LOG_EVENT, - logsctperror("Parameter parse limit exceeded (AddGlobalIPAddress)", - sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); - break; /* limit exceeded*/ - } - } - if (addr_param_count == 0) { - SN_LOG(SN_LOG_DETAIL, - logsctperror("AddGlobalIPAddress: no address parameters to add", + param = SN_SCTP_NEXTPARAM(param); + param_size = SCTP_SIZE32(ntohs(param->param_length)); + if (++param_count > sysctl_param_proc_limit) { + SN_LOG(SN_LOG_EVENT, + logsctperror("Parameter parse limit exceeded (AddGlobalIPAddress)", + sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); + break; /* limit exceeded*/ + } + } + if (addr_param_count == 0) { + SN_LOG(SN_LOG_DETAIL, + logsctperror("AddGlobalIPAddress: no address parameters to add", sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); - } + } } /** @@ -1426,19 +1404,19 @@ AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int */ static int Add_Global_Address_to_List(struct sctp_nat_assoc *assoc, struct sctp_GlobalAddress *G_addr) { - struct sctp_GlobalAddress *iter_G_Addr = NULL, *first_G_Addr = NULL; - first_G_Addr = LIST_FIRST(&(assoc->Gaddr)); - if (first_G_Addr == NULL) { - LIST_INSERT_HEAD(&(assoc->Gaddr), G_addr, list_Gaddr); /* add new address to beginning of list*/ - } else { - LIST_FOREACH(iter_G_Addr, &(assoc->Gaddr), list_Gaddr) { - if (G_addr->g_addr.s_addr == iter_G_Addr->g_addr.s_addr) - return(0); /* already exists, so don't add */ - } - LIST_INSERT_AFTER(first_G_Addr, G_addr, list_Gaddr); /* add address to end of list*/ - } - assoc->num_Gaddr++; - return(1); /* success */ + struct sctp_GlobalAddress *iter_G_Addr = NULL, *first_G_Addr = NULL; + first_G_Addr = LIST_FIRST(&(assoc->Gaddr)); + if (first_G_Addr == NULL) { + LIST_INSERT_HEAD(&(assoc->Gaddr), G_addr, list_Gaddr); /* add new address to beginning of list*/ + } else { + LIST_FOREACH(iter_G_Addr, &(assoc->Gaddr), list_Gaddr) { + if (G_addr->g_addr.s_addr == iter_G_Addr->g_addr.s_addr) + return(0); /* already exists, so don't add */ + } + LIST_INSERT_AFTER(first_G_Addr, G_addr, list_Gaddr); /* add address to end of list*/ + } + assoc->num_Gaddr++; + return(1); /* success */ } /** @ingroup packet_parser @@ -1457,85 +1435,85 @@ static int Add_Global_Address_to_List(struct sctp_nat_assoc *assoc, struct sct static void RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction) { - struct sctp_asconf_addrv4_param *asconf_ipv4_param; - struct sctp_paramhdr *param; - struct sctp_GlobalAddress *G_Addr, *G_Addr_tmp; - struct in_addr g_addr; - int bytes_left; - int param_size; - int param_count; - - if(direction == SN_TO_GLOBAL) - g_addr = sm->ip_hdr->ip_dst; - else - g_addr = sm->ip_hdr->ip_src; - - bytes_left = sm->chunk_length; - param_count = 1; - param = sm->sctpchnk.Asconf; - if (bytes_left >= SN_MIN_PARAM_SIZE) { - param_size = SCTP_SIZE32(ntohs(param->param_length)); - } else { - SN_LOG(SN_LOG_EVENT, - logsctperror("RmGlobalIPAddress: truncated packet - cannot remove IP addresses", + struct sctp_asconf_addrv4_param *asconf_ipv4_param; + struct sctp_paramhdr *param; + struct sctp_GlobalAddress *G_Addr, *G_Addr_tmp; + struct in_addr g_addr; + int bytes_left; + int param_size; + int param_count; + + if(direction == SN_TO_GLOBAL) + g_addr = sm->ip_hdr->ip_dst; + else + g_addr = sm->ip_hdr->ip_src; + + bytes_left = sm->chunk_length; + param_count = 1; + param = sm->sctpchnk.Asconf; + if (bytes_left >= SN_MIN_PARAM_SIZE) { + param_size = SCTP_SIZE32(ntohs(param->param_length)); + } else { + SN_LOG(SN_LOG_EVENT, + logsctperror("RmGlobalIPAddress: truncated packet - cannot remove IP addresses", sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); - return; - } - - /* step through Asconf parameters */ - while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { - if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) { - asconf_ipv4_param = (struct sctp_asconf_addrv4_param *) param; - if (asconf_ipv4_param->addrp.addr == INADDR_ANY) { /* remove all bar pkt address */ - LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { - if(G_Addr->g_addr.s_addr != sm->ip_hdr->ip_src.s_addr) { - if (assoc->num_Gaddr > 1) { /* only delete if more than one */ - LIST_REMOVE(G_Addr, list_Gaddr); - sn_free(G_Addr); - assoc->num_Gaddr--; - } else { - SN_LOG(SN_LOG_EVENT, - logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", - sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); - } - } - } - return; /*shouldn't be any other addresses if the zero address is given*/ - } else { - LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { - if(G_Addr->g_addr.s_addr == asconf_ipv4_param->addrp.addr) { - if (assoc->num_Gaddr > 1) { /* only delete if more than one */ - LIST_REMOVE(G_Addr, list_Gaddr); - sn_free(G_Addr); - assoc->num_Gaddr--; - break; /* Since add only adds new addresses, there should be no double entries */ - } else { - SN_LOG(SN_LOG_EVENT, - logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", - sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); - } - } + return; } - } - } - bytes_left -= param_size; - if (bytes_left == 0) return; - else if (bytes_left < SN_MIN_PARAM_SIZE) { - SN_LOG(SN_LOG_EVENT, - logsctperror("RmGlobalIPAddress: truncated packet - may not have removed all IP addresses", - sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); - return; - } + + /* step through Asconf parameters */ + while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { + if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) { + asconf_ipv4_param = (struct sctp_asconf_addrv4_param *) param; + if (asconf_ipv4_param->addrp.addr == INADDR_ANY) { /* remove all bar pkt address */ + LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { + if(G_Addr->g_addr.s_addr != sm->ip_hdr->ip_src.s_addr) { + if (assoc->num_Gaddr > 1) { /* only delete if more than one */ + LIST_REMOVE(G_Addr, list_Gaddr); + sn_free(G_Addr); + assoc->num_Gaddr--; + } else { + SN_LOG(SN_LOG_EVENT, + logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", + sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); + } + } + } + return; /*shouldn't be any other addresses if the zero address is given*/ + } else { + LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { + if(G_Addr->g_addr.s_addr == asconf_ipv4_param->addrp.addr) { + if (assoc->num_Gaddr > 1) { /* only delete if more than one */ + LIST_REMOVE(G_Addr, list_Gaddr); + sn_free(G_Addr); + assoc->num_Gaddr--; + break; /* Since add only adds new addresses, there should be no double entries */ + } else { + SN_LOG(SN_LOG_EVENT, + logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", + sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); + } + } + } + } + } + bytes_left -= param_size; + if (bytes_left == 0) return; + else if (bytes_left < SN_MIN_PARAM_SIZE) { + SN_LOG(SN_LOG_EVENT, + logsctperror("RmGlobalIPAddress: truncated packet - may not have removed all IP addresses", + sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); + return; + } - param = SN_SCTP_NEXTPARAM(param); - param_size = SCTP_SIZE32(ntohs(param->param_length)); - if (++param_count > sysctl_param_proc_limit) { - SN_LOG(SN_LOG_EVENT, - logsctperror("Parameter parse limit exceeded (RmGlobalIPAddress)", - sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); - return; /* limit exceeded*/ - } - } + param = SN_SCTP_NEXTPARAM(param); + param_size = SCTP_SIZE32(ntohs(param->param_length)); + if (++param_count > sysctl_param_proc_limit) { + SN_LOG(SN_LOG_EVENT, + logsctperror("Parameter parse limit exceeded (RmGlobalIPAddress)", + sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); + return; /* limit exceeded*/ + } + } } /** @ingroup packet_parser @@ -1563,42 +1541,42 @@ RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int d static int IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction) { - struct sctp_paramhdr *param; - int bytes_left; - int param_size; - int param_count; - - param_count = 1; - param = sm->sctpchnk.Asconf; - param_size = SCTP_SIZE32(ntohs(param->param_length)); - if (param_size == 8) - return(1); /*success - default acknowledgement of everything */ - - bytes_left = sm->chunk_length; - if (bytes_left < param_size) - return(0); /* not found */ - /* step through Asconf parameters */ - while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { - if (ntohs(param->param_type) == SCTP_SUCCESS_REPORT) - return(1); /* success - but can't match correlation IDs - should only be one */ - /* check others just in case */ - bytes_left -= param_size; - if (bytes_left >= SN_MIN_PARAM_SIZE) { - param = SN_SCTP_NEXTPARAM(param); - } else { - return(0); - } - param_size = SCTP_SIZE32(ntohs(param->param_length)); - if (bytes_left < param_size) return(0); - - if (++param_count > sysctl_param_proc_limit) { - SN_LOG(SN_LOG_EVENT, - logsctperror("Parameter parse limit exceeded (IsASCONFack)", - sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); - return(0); /* not found limit exceeded*/ - } - } - return(0); /* not success */ + struct sctp_paramhdr *param; + int bytes_left; + int param_size; + int param_count; + + param_count = 1; + param = sm->sctpchnk.Asconf; + param_size = SCTP_SIZE32(ntohs(param->param_length)); + if (param_size == 8) + return(1); /*success - default acknowledgement of everything */ + + bytes_left = sm->chunk_length; + if (bytes_left < param_size) + return(0); /* not found */ + /* step through Asconf parameters */ + while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { + if (ntohs(param->param_type) == SCTP_SUCCESS_REPORT) + return(1); /* success - but can't match correlation IDs - should only be one */ + /* check others just in case */ + bytes_left -= param_size; + if (bytes_left >= SN_MIN_PARAM_SIZE) { + param = SN_SCTP_NEXTPARAM(param); + } else { + return(0); + } + param_size = SCTP_SIZE32(ntohs(param->param_length)); + if (bytes_left < param_size) return(0); + + if (++param_count > sysctl_param_proc_limit) { + SN_LOG(SN_LOG_EVENT, + logsctperror("Parameter parse limit exceeded (IsASCONFack)", + sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); + return(0); /* not found limit exceeded*/ + } + } + return(0); /* not success */ } /** @ingroup packet_parser @@ -1616,42 +1594,42 @@ IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction) static int IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction) { - struct sctp_paramhdr *param; - int bytes_left; - int param_size; - int param_count; - - param_count = 1; - param = sm->sctpchnk.Asconf; - param_size = SCTP_SIZE32(ntohs(param->param_length)); - - bytes_left = sm->chunk_length; - if (bytes_left < param_size) - return(0); /* not found */ - /* step through Asconf parameters */ - while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { - if (ntohs(param->param_type) == SCTP_ADD_IP_ADDRESS) - return(SCTP_ADD_IP_ADDRESS); - else if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) - return(SCTP_DEL_IP_ADDRESS); - /* check others just in case */ - bytes_left -= param_size; - if (bytes_left >= SN_MIN_PARAM_SIZE) { - param = SN_SCTP_NEXTPARAM(param); - } else { - return(0); /*Neither found */ - } - param_size = SCTP_SIZE32(ntohs(param->param_length)); - if (bytes_left < param_size) return(0); - - if (++param_count > sysctl_param_proc_limit) { - SN_LOG(SN_LOG_EVENT, - logsctperror("Parameter parse limit exceeded IsADDorDEL)", - sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); - return(0); /* not found limit exceeded*/ - } - } - return(0); /*Neither found */ + struct sctp_paramhdr *param; + int bytes_left; + int param_size; + int param_count; + + param_count = 1; + param = sm->sctpchnk.Asconf; + param_size = SCTP_SIZE32(ntohs(param->param_length)); + + bytes_left = sm->chunk_length; + if (bytes_left < param_size) + return(0); /* not found */ + /* step through Asconf parameters */ + while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { + if (ntohs(param->param_type) == SCTP_ADD_IP_ADDRESS) + return(SCTP_ADD_IP_ADDRESS); + else if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) + return(SCTP_DEL_IP_ADDRESS); + /* check others just in case */ + bytes_left -= param_size; + if (bytes_left >= SN_MIN_PARAM_SIZE) { + param = SN_SCTP_NEXTPARAM(param); + } else { + return(0); /*Neither found */ + } + param_size = SCTP_SIZE32(ntohs(param->param_length)); + if (bytes_left < param_size) return(0); + + if (++param_count > sysctl_param_proc_limit) { + SN_LOG(SN_LOG_EVENT, + logsctperror("Parameter parse limit exceeded IsADDorDEL)", + sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); + return(0); /* not found limit exceeded*/ + } + } + return(0); /*Neither found */ } /* ---------------------------------------------------------------------- @@ -1683,25 +1661,25 @@ IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction) static int ProcessSctpMsg(struct libalias *la, int direction, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc) { - int rtnval; - - switch (assoc->state) { - case SN_ID: /* Idle */ - rtnval = ID_process(la, direction, assoc, sm); - if (rtnval != SN_NAT_PKT) { - assoc->state = SN_RM;/* Mark for removal*/ - } - return(rtnval); - case SN_INi: /* Initialising - Init */ - return(INi_process(la, direction, assoc, sm)); - case SN_INa: /* Initialising - AddIP */ - return(INa_process(la, direction, assoc, sm)); - case SN_UP: /* Association UP */ - return(UP_process(la, direction, assoc, sm)); - case SN_CL: /* Association Closing */ - return(CL_process(la, direction, assoc, sm)); - } - return(SN_PROCESSING_ERROR); + int rtnval; + + switch (assoc->state) { + case SN_ID: /* Idle */ + rtnval = ID_process(la, direction, assoc, sm); + if (rtnval != SN_NAT_PKT) { + assoc->state = SN_RM;/* Mark for removal*/ + } + return(rtnval); + case SN_INi: /* Initialising - Init */ + return(INi_process(la, direction, assoc, sm)); + case SN_INa: /* Initialising - AddIP */ + return(INa_process(la, direction, assoc, sm)); + case SN_UP: /* Association UP */ + return(UP_process(la, direction, assoc, sm)); + case SN_CL: /* Association Closing */ + return(CL_process(la, direction, assoc, sm)); + } + return(SN_PROCESSING_ERROR); } /** @ingroup state_machine @@ -1721,56 +1699,56 @@ ProcessSctpMsg(struct libalias *la, int direction, struct sctp_nat_msg *sm, stru static int ID_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) { - switch(sm->msg) { - case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk with ADDIP */ - if (!sysctl_accept_global_ootb_addip && (direction == SN_TO_LOCAL)) - return(SN_DROP_PKT); - /* if this Asconf packet does not contain the Vtag parameters it is of no use in Idle state */ - if (!GetAsconfVtags(la, sm, &(assoc->l_vtag), &(assoc->g_vtag), direction)) - return(SN_DROP_PKT); - case SN_SCTP_INIT: /* a packet containing an INIT chunk or an ASCONF AddIP */ - if (sysctl_track_global_addresses) - AddGlobalIPAddresses(sm, assoc, direction); - switch(direction){ - case SN_TO_GLOBAL: - assoc->l_addr = sm->ip_hdr->ip_src; - assoc->a_addr = FindAliasAddress(la, assoc->l_addr); - assoc->l_port = sm->sctp_hdr->src_port; - assoc->g_port = sm->sctp_hdr->dest_port; - if(sm->msg == SN_SCTP_INIT) - assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; - if (AddSctpAssocGlobal(la, assoc)) /* DB clash *///**** need to add dst address - return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); - if(sm->msg == SN_SCTP_ASCONF) { - if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_dst)) /* DB clash */ - return(SN_REPLY_ERROR); - assoc->TableRegister |= SN_WAIT_TOLOCAL; /* wait for tolocal ack */ - } - break; - case SN_TO_LOCAL: - assoc->l_addr = FindSctpRedirectAddress(la, sm); - assoc->a_addr = sm->ip_hdr->ip_dst; - assoc->l_port = sm->sctp_hdr->dest_port; - assoc->g_port = sm->sctp_hdr->src_port; - if(sm->msg == SN_SCTP_INIT) - assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; - if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) /* DB clash */ - return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); - if(sm->msg == SN_SCTP_ASCONF) { - if (AddSctpAssocGlobal(la, assoc)) /* DB clash */ //**** need to add src address - return(SN_REPLY_ERROR); - assoc->TableRegister |= SN_WAIT_TOGLOBAL; /* wait for toglobal ack */ - } - break; - } - assoc->state = (sm->msg == SN_SCTP_INIT) ? SN_INi : SN_INa; - assoc->exp = SN_I_T(la); - sctp_AddTimeOut(la,assoc); - return(SN_NAT_PKT); - default: /* Any other type of SCTP message is not valid in Idle */ - return(SN_DROP_PKT); - } - return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ + switch(sm->msg) { + case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk with ADDIP */ + if (!sysctl_accept_global_ootb_addip && (direction == SN_TO_LOCAL)) + return(SN_DROP_PKT); + /* if this Asconf packet does not contain the Vtag parameters it is of no use in Idle state */ + if (!GetAsconfVtags(la, sm, &(assoc->l_vtag), &(assoc->g_vtag), direction)) + return(SN_DROP_PKT); + case SN_SCTP_INIT: /* a packet containing an INIT chunk or an ASCONF AddIP */ + if (sysctl_track_global_addresses) + AddGlobalIPAddresses(sm, assoc, direction); + switch(direction){ + case SN_TO_GLOBAL: + assoc->l_addr = sm->ip_hdr->ip_src; + assoc->a_addr = FindAliasAddress(la, assoc->l_addr); + assoc->l_port = sm->sctp_hdr->src_port; + assoc->g_port = sm->sctp_hdr->dest_port; + if(sm->msg == SN_SCTP_INIT) + assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; + if (AddSctpAssocGlobal(la, assoc)) /* DB clash *///**** need to add dst address + return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); + if(sm->msg == SN_SCTP_ASCONF) { + if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_dst)) /* DB clash */ + return(SN_REPLY_ERROR); + assoc->TableRegister |= SN_WAIT_TOLOCAL; /* wait for tolocal ack */ + } + break; + case SN_TO_LOCAL: + assoc->l_addr = FindSctpRedirectAddress(la, sm); + assoc->a_addr = sm->ip_hdr->ip_dst; + assoc->l_port = sm->sctp_hdr->dest_port; + assoc->g_port = sm->sctp_hdr->src_port; + if(sm->msg == SN_SCTP_INIT) + assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; + if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) /* DB clash */ + return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); + if(sm->msg == SN_SCTP_ASCONF) { + if (AddSctpAssocGlobal(la, assoc)) /* DB clash */ //**** need to add src address + return(SN_REPLY_ERROR); + assoc->TableRegister |= SN_WAIT_TOGLOBAL; /* wait for toglobal ack */ + } + break; + } + assoc->state = (sm->msg == SN_SCTP_INIT) ? SN_INi : SN_INa; + assoc->exp = SN_I_T(la); + sctp_AddTimeOut(la,assoc); + return(SN_NAT_PKT); + default: /* Any other type of SCTP message is not valid in Idle */ + return(SN_DROP_PKT); + } +return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ } /** @ingroup state_machine @@ -1789,40 +1767,40 @@ ID_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, str static int INi_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) { - switch(sm->msg) { - case SN_SCTP_INIT: /* a packet containing a retransmitted INIT chunk */ - sctp_ResetTimeOut(la, assoc, SN_I_T(la)); - return(SN_NAT_PKT); - case SN_SCTP_INITACK: /* a packet containing an INIT-ACK chunk */ - switch(direction){ - case SN_TO_LOCAL: - if (assoc->num_Gaddr) /*If tracking global addresses for this association */ - AddGlobalIPAddresses(sm, assoc, direction); - assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; - if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) { /* DB clash */ - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_SEND_ABORT); - } - break; - case SN_TO_GLOBAL: - assoc->l_addr = sm->ip_hdr->ip_src; // Only if not set in Init! * - assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; - if (AddSctpAssocGlobal(la, assoc)) { /* DB clash */ - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_SEND_ABORT); - } - break; - } - assoc->state = SN_UP;/* association established for NAT */ - sctp_ResetTimeOut(la,assoc, SN_U_T(la)); - return(SN_NAT_PKT); - case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_NAT_PKT); - default: - return(SN_DROP_PKT); - } - return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ + switch(sm->msg) { + case SN_SCTP_INIT: /* a packet containing a retransmitted INIT chunk */ + sctp_ResetTimeOut(la, assoc, SN_I_T(la)); + return(SN_NAT_PKT); + case SN_SCTP_INITACK: /* a packet containing an INIT-ACK chunk */ + switch(direction){ + case SN_TO_LOCAL: + if (assoc->num_Gaddr) /*If tracking global addresses for this association */ + AddGlobalIPAddresses(sm, assoc, direction); + assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; + if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) { /* DB clash */ + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_SEND_ABORT); + } + break; + case SN_TO_GLOBAL: + assoc->l_addr = sm->ip_hdr->ip_src; // Only if not set in Init! * + assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; + if (AddSctpAssocGlobal(la, assoc)) { /* DB clash */ + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_SEND_ABORT); + } + break; + } + assoc->state = SN_UP;/* association established for NAT */ + sctp_ResetTimeOut(la,assoc, SN_U_T(la)); + return(SN_NAT_PKT); + case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_NAT_PKT); + default: + return(SN_DROP_PKT); + } + return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ } /** @ingroup state_machine @@ -1841,36 +1819,36 @@ INi_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, st static int INa_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) { - switch(sm->msg) { - case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ - sctp_ResetTimeOut(la,assoc, SN_I_T(la)); - return(SN_NAT_PKT); - case SN_SCTP_ASCONFACK: /* a packet containing an ASCONF chunk with a ADDIP-ACK */ - switch(direction){ - case SN_TO_LOCAL: - if (!(assoc->TableRegister & SN_WAIT_TOLOCAL)) /* wrong direction */ - return(SN_DROP_PKT); - break; - case SN_TO_GLOBAL: - if (!(assoc->TableRegister & SN_WAIT_TOGLOBAL)) /* wrong direction */ - return(SN_DROP_PKT); - } - if (IsASCONFack(la,sm,direction)) { - assoc->TableRegister &= SN_BOTH_TBL; /* remove wait flags */ - assoc->state = SN_UP; /* association established for NAT */ - sctp_ResetTimeOut(la,assoc, SN_U_T(la)); - return(SN_NAT_PKT); - } else { - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_NAT_PKT); - } - case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_NAT_PKT); - default: - return(SN_DROP_PKT); - } - return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ + switch(sm->msg) { + case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ + sctp_ResetTimeOut(la,assoc, SN_I_T(la)); + return(SN_NAT_PKT); + case SN_SCTP_ASCONFACK: /* a packet containing an ASCONF chunk with a ADDIP-ACK */ + switch(direction){ + case SN_TO_LOCAL: + if (!(assoc->TableRegister & SN_WAIT_TOLOCAL)) /* wrong direction */ + return(SN_DROP_PKT); + break; + case SN_TO_GLOBAL: + if (!(assoc->TableRegister & SN_WAIT_TOGLOBAL)) /* wrong direction */ + return(SN_DROP_PKT); + } + if (IsASCONFack(la,sm,direction)) { + assoc->TableRegister &= SN_BOTH_TBL; /* remove wait flags */ + assoc->state = SN_UP; /* association established for NAT */ + sctp_ResetTimeOut(la,assoc, SN_U_T(la)); + return(SN_NAT_PKT); + } else { + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_NAT_PKT); + } + case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_NAT_PKT); + default: + return(SN_DROP_PKT); + } + return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ } /** @ingroup state_machine @@ -1889,29 +1867,29 @@ INa_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, str static int UP_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) { - switch(sm->msg) { - case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ - assoc->state = SN_CL; - sctp_ResetTimeOut(la,assoc, SN_C_T(la)); - return(SN_NAT_PKT); - case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_NAT_PKT); - case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ - if ((direction == SN_TO_LOCAL) && assoc->num_Gaddr) /*If tracking global addresses for this association & from global side */ - switch(IsADDorDEL(la,sm,direction)) { - case SCTP_ADD_IP_ADDRESS: - AddGlobalIPAddresses(sm, assoc, direction); - break; - case SCTP_DEL_IP_ADDRESS: - RmGlobalIPAddresses(sm, assoc, direction); - break; - } /* fall through to default */ - default: - sctp_ResetTimeOut(la,assoc, SN_U_T(la)); - return(SN_NAT_PKT); /* forward packet */ - } - return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ + switch(sm->msg) { + case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ + assoc->state = SN_CL; + sctp_ResetTimeOut(la,assoc, SN_C_T(la)); + return(SN_NAT_PKT); + case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_NAT_PKT); + case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ + if ((direction == SN_TO_LOCAL) && assoc->num_Gaddr) /*If tracking global addresses for this association & from global side */ + switch(IsADDorDEL(la,sm,direction)) { + case SCTP_ADD_IP_ADDRESS: + AddGlobalIPAddresses(sm, assoc, direction); + break; + case SCTP_DEL_IP_ADDRESS: + RmGlobalIPAddresses(sm, assoc, direction); + break; + } /* fall through to default */ + default: + sctp_ResetTimeOut(la,assoc, SN_U_T(la)); + return(SN_NAT_PKT); /* forward packet */ + } + return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ } /** @ingroup state_machine @@ -1932,25 +1910,25 @@ UP_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, str static int CL_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) { - switch(sm->msg) { - case SN_SCTP_SHUTCOMP: /* a packet containing a SHUTDOWN-COMPLETE chunk */ - assoc->state = SN_CL; /* Stay in Close state until timeout */ - if (sysctl_holddown_timer > 0) - sctp_ResetTimeOut(la, assoc, SN_X_T(la));/* allow to stay open for Tbit packets*/ - else - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_NAT_PKT); - case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ - assoc->state = SN_CL; /* Stay in Close state until timeout */ - sctp_ResetTimeOut(la, assoc, SN_C_T(la)); - return(SN_NAT_PKT); - case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ - assoc->state = SN_RM;/* Mark for removal*/ - return(SN_NAT_PKT); - default: - return(SN_DROP_PKT); - } - return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ + switch(sm->msg) { + case SN_SCTP_SHUTCOMP: /* a packet containing a SHUTDOWN-COMPLETE chunk */ + assoc->state = SN_CL; /* Stay in Close state until timeout */ + if (sysctl_holddown_timer > 0) + sctp_ResetTimeOut(la, assoc, SN_X_T(la));/* allow to stay open for Tbit packets*/ + else + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_NAT_PKT); + case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ + assoc->state = SN_CL; /* Stay in Close state until timeout */ + sctp_ResetTimeOut(la, assoc, SN_C_T(la)); + return(SN_NAT_PKT); + case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ + assoc->state = SN_RM;/* Mark for removal*/ + return(SN_NAT_PKT); + default: + return(SN_DROP_PKT); + } + return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ } /* ---------------------------------------------------------------------- @@ -1980,27 +1958,27 @@ CL_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, stru static struct sctp_nat_assoc* FindSctpLocal(struct libalias *la, struct in_addr l_addr, struct in_addr g_addr, uint32_t l_vtag, uint16_t l_port, uint16_t g_port) { - u_int i; - struct sctp_nat_assoc *assoc = NULL; - struct sctp_GlobalAddress *G_Addr = NULL; + u_int i; + struct sctp_nat_assoc *assoc = NULL; + struct sctp_GlobalAddress *G_Addr = NULL; - if (l_vtag != 0) { /* an init packet, vtag==0 */ - i = SN_TABLE_HASH(l_vtag, l_port, la->sctpNatTableSize); - LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { - if ((assoc->l_vtag == l_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)\ - && (assoc->l_addr.s_addr == l_addr.s_addr)) { - if (assoc->num_Gaddr) { - LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { - if(G_Addr->g_addr.s_addr == g_addr.s_addr) - return(assoc); - } - } else { - return(assoc); + if (l_vtag != 0) { /* an init packet, vtag==0 */ + i = SN_TABLE_HASH(l_vtag, l_port, la->sctpNatTableSize); + LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { + if ((assoc->l_vtag == l_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)\ + && (assoc->l_addr.s_addr == l_addr.s_addr)) { + if (assoc->num_Gaddr) { + LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { + if(G_Addr->g_addr.s_addr == g_addr.s_addr) + return(assoc); + } + } else { + return(assoc); + } + } + } } - } - } - } - return(NULL); + return(NULL); } /** @ingroup Hash @@ -2017,29 +1995,29 @@ FindSctpLocal(struct libalias *la, struct in_addr l_addr, struct in_addr g_addr, static struct sctp_nat_assoc* FindSctpGlobalClash(struct libalias *la, struct sctp_nat_assoc *Cassoc) { - u_int i; - struct sctp_nat_assoc *assoc = NULL; - struct sctp_GlobalAddress *G_Addr = NULL; - struct sctp_GlobalAddress *G_AddrC = NULL; + u_int i; + struct sctp_nat_assoc *assoc = NULL; + struct sctp_GlobalAddress *G_Addr = NULL; + struct sctp_GlobalAddress *G_AddrC = NULL; - if (Cassoc->g_vtag != 0) { /* an init packet, vtag==0 */ - i = SN_TABLE_HASH(Cassoc->g_vtag, Cassoc->g_port, la->sctpNatTableSize); - LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { - if ((assoc->g_vtag == Cassoc->g_vtag) && (assoc->g_port == Cassoc->g_port) && (assoc->l_port == Cassoc->l_port)) { - if (assoc->num_Gaddr) { - LIST_FOREACH(G_AddrC, &(Cassoc->Gaddr), list_Gaddr) { - LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { - if(G_Addr->g_addr.s_addr == G_AddrC->g_addr.s_addr) - return(assoc); - } - } - } else { - return(assoc); + if (Cassoc->g_vtag != 0) { /* an init packet, vtag==0 */ + i = SN_TABLE_HASH(Cassoc->g_vtag, Cassoc->g_port, la->sctpNatTableSize); + LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { + if ((assoc->g_vtag == Cassoc->g_vtag) && (assoc->g_port == Cassoc->g_port) && (assoc->l_port == Cassoc->l_port)) { + if (assoc->num_Gaddr) { + LIST_FOREACH(G_AddrC, &(Cassoc->Gaddr), list_Gaddr) { + LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { + if(G_Addr->g_addr.s_addr == G_AddrC->g_addr.s_addr) + return(assoc); + } + } + } else { + return(assoc); + } + } + } } - } - } - } - return(NULL); + return(NULL); } /** @ingroup Hash @@ -2064,28 +2042,28 @@ FindSctpGlobalClash(struct libalias *la, struct sctp_nat_assoc *Cassoc) static struct sctp_nat_assoc* FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match) { - u_int i; - struct sctp_nat_assoc *assoc = NULL; - struct sctp_GlobalAddress *G_Addr = NULL; + u_int i; + struct sctp_nat_assoc *assoc = NULL; + struct sctp_GlobalAddress *G_Addr = NULL; - *partial_match = 0; - if (g_vtag != 0) { /* an init packet, vtag==0 */ - i = SN_TABLE_HASH(g_vtag, g_port, la->sctpNatTableSize); - LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { - if ((assoc->g_vtag == g_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { - *partial_match = 1; - if (assoc->num_Gaddr) { - LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { - if(G_Addr->g_addr.s_addr == g_addr.s_addr) - return(assoc); - } - } else { - return(assoc); + *partial_match = 0; + if (g_vtag != 0) { /* an init packet, vtag==0 */ + i = SN_TABLE_HASH(g_vtag, g_port, la->sctpNatTableSize); + LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { + if ((assoc->g_vtag == g_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { + *partial_match = 1; + if (assoc->num_Gaddr) { + LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { + if(G_Addr->g_addr.s_addr == g_addr.s_addr) + return(assoc); + } + } else { + return(assoc); + } + } + } } - } - } - } - return(NULL); + return(NULL); } /** @ingroup Hash @@ -2105,29 +2083,29 @@ FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint static struct sctp_nat_assoc* FindSctpLocalT(struct libalias *la, struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port) { - u_int i; - struct sctp_nat_assoc *assoc = NULL, *lastmatch = NULL; - struct sctp_GlobalAddress *G_Addr = NULL; - int cnt = 0; + u_int i; + struct sctp_nat_assoc *assoc = NULL, *lastmatch = NULL; + struct sctp_GlobalAddress *G_Addr = NULL; + int cnt = 0; - if (l_vtag != 0) { /* an init packet, vtag==0 */ - i = SN_TABLE_HASH(l_vtag, g_port, la->sctpNatTableSize); - LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { - if ((assoc->g_vtag == l_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { - if (assoc->num_Gaddr) { - LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { - if(G_Addr->g_addr.s_addr == G_Addr->g_addr.s_addr) - return(assoc); /* full match */ - } - } else { - if (++cnt > 1) return(NULL); - lastmatch = assoc; + if (l_vtag != 0) { /* an init packet, vtag==0 */ + i = SN_TABLE_HASH(l_vtag, g_port, la->sctpNatTableSize); + LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { + if ((assoc->g_vtag == l_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { + if (assoc->num_Gaddr) { + LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { + if(G_Addr->g_addr.s_addr == G_Addr->g_addr.s_addr) + return(assoc); /* full match */ + } + } else { + if (++cnt > 1) return(NULL); + lastmatch = assoc; + } + } + } } - } - } - } - /* If there is more than one match we do not know which local address to send to */ - return( cnt ? lastmatch : NULL ); + /* If there is more than one match we do not know which local address to send to */ + return( cnt ? lastmatch : NULL ); } /** @ingroup Hash @@ -2147,26 +2125,26 @@ FindSctpLocalT(struct libalias *la, struct in_addr g_addr, uint32_t l_vtag, uin static struct sctp_nat_assoc* FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port) { - u_int i; - struct sctp_nat_assoc *assoc = NULL; - struct sctp_GlobalAddress *G_Addr = NULL; + u_int i; + struct sctp_nat_assoc *assoc = NULL; + struct sctp_GlobalAddress *G_Addr = NULL; - if (g_vtag != 0) { /* an init packet, vtag==0 */ - i = SN_TABLE_HASH(g_vtag, l_port, la->sctpNatTableSize); - LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { - if ((assoc->l_vtag == g_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)) { - if (assoc->num_Gaddr) { - LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { - if(G_Addr->g_addr.s_addr == g_addr.s_addr) - return(assoc); - } - } else { - return(assoc); + if (g_vtag != 0) { /* an init packet, vtag==0 */ + i = SN_TABLE_HASH(g_vtag, l_port, la->sctpNatTableSize); + LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { + if ((assoc->l_vtag == g_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)) { + if (assoc->num_Gaddr) { + LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { + if(G_Addr->g_addr.s_addr == g_addr.s_addr) + return(assoc); + } + } else { + return(assoc); + } + } + } } - } - } - } - return(NULL); + return(NULL); } /** @ingroup Hash @@ -2188,43 +2166,43 @@ FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uin static int AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr) { - struct sctp_nat_assoc *found; - - LIBALIAS_LOCK_ASSERT(la); - found = FindSctpLocal(la, assoc->l_addr, g_addr, assoc->l_vtag, assoc->l_port, assoc->g_port); - /* - * Note that if a different global address initiated this Init, - * ie it wasn't resent as presumed: - * - the local receiver if receiving it for the first time will establish - * an association with the new global host - * - if receiving an init from a different global address after sending a - * lost initack it will send an initack to the new global host, the first - * association attempt will then be blocked if retried. - */ - if (found != NULL) { - if ((found->TableRegister == SN_LOCAL_TBL) && (found->g_port == assoc->g_port)) { /* resent message */ - RmSctpAssoc(la, found); - sctp_RmTimeOut(la, found); - freeGlobalAddressList(found); - sn_free(found); - } else - return(SN_ADD_CLASH); - } + struct sctp_nat_assoc *found; + + LIBALIAS_LOCK_ASSERT(la); + found = FindSctpLocal(la, assoc->l_addr, g_addr, assoc->l_vtag, assoc->l_port, assoc->g_port); + /* + * Note that if a different global address initiated this Init, + * ie it wasn't resent as presumed: + * - the local receiver if receiving it for the first time will establish + * an association with the new global host + * - if receiving an init from a different global address after sending a + * lost initack it will send an initack to the new global host, the first + * association attempt will then be blocked if retried. + */ + if (found != NULL) { + if ((found->TableRegister == SN_LOCAL_TBL) && (found->g_port == assoc->g_port)) { /* resent message */ + RmSctpAssoc(la, found); + sctp_RmTimeOut(la, found); + freeGlobalAddressList(found); + sn_free(found); + } else + return(SN_ADD_CLASH); + } - LIST_INSERT_HEAD(&la->sctpTableLocal[SN_TABLE_HASH(assoc->l_vtag, assoc->l_port, la->sctpNatTableSize)], - assoc, list_L); - assoc->TableRegister |= SN_LOCAL_TBL; - la->sctpLinkCount++; //increment link count + LIST_INSERT_HEAD(&la->sctpTableLocal[SN_TABLE_HASH(assoc->l_vtag, assoc->l_port, la->sctpNatTableSize)], + assoc, list_L); + assoc->TableRegister |= SN_LOCAL_TBL; + la->sctpLinkCount++; //increment link count - if (assoc->TableRegister == SN_BOTH_TBL) { - /* libalias log -- controlled by libalias */ - if (la->packetAliasMode & PKT_ALIAS_LOG) - SctpShowAliasStats(la); + if (assoc->TableRegister == SN_BOTH_TBL) { + /* libalias log -- controlled by libalias */ + if (la->packetAliasMode & PKT_ALIAS_LOG) + SctpShowAliasStats(la); - SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); - } + SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); + } - return(SN_ADD_OK); + return(SN_ADD_OK); } /** @ingroup Hash @@ -2245,35 +2223,35 @@ AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_a static int AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc) { - struct sctp_nat_assoc *found; - - LIBALIAS_LOCK_ASSERT(la); - found = FindSctpGlobalClash(la, assoc); - if (found != NULL) { - if ((found->TableRegister == SN_GLOBAL_TBL) && \ - (found->l_addr.s_addr == assoc->l_addr.s_addr) && (found->l_port == assoc->l_port)) { /* resent message */ - RmSctpAssoc(la, found); - sctp_RmTimeOut(la, found); - freeGlobalAddressList(found); - sn_free(found); - } else - return(SN_ADD_CLASH); - } + struct sctp_nat_assoc *found; + + LIBALIAS_LOCK_ASSERT(la); + found = FindSctpGlobalClash(la, assoc); + if (found != NULL) { + if ((found->TableRegister == SN_GLOBAL_TBL) && \ + (found->l_addr.s_addr == assoc->l_addr.s_addr) && (found->l_port == assoc->l_port)) { /* resent message */ + RmSctpAssoc(la, found); + sctp_RmTimeOut(la, found); + freeGlobalAddressList(found); + sn_free(found); + } else + return(SN_ADD_CLASH); + } - LIST_INSERT_HEAD(&la->sctpTableGlobal[SN_TABLE_HASH(assoc->g_vtag, assoc->g_port, la->sctpNatTableSize)], - assoc, list_G); - assoc->TableRegister |= SN_GLOBAL_TBL; - la->sctpLinkCount++; //increment link count + LIST_INSERT_HEAD(&la->sctpTableGlobal[SN_TABLE_HASH(assoc->g_vtag, assoc->g_port, la->sctpNatTableSize)], + assoc, list_G); + assoc->TableRegister |= SN_GLOBAL_TBL; + la->sctpLinkCount++; //increment link count - if (assoc->TableRegister == SN_BOTH_TBL) { - /* libalias log -- controlled by libalias */ - if (la->packetAliasMode & PKT_ALIAS_LOG) - SctpShowAliasStats(la); + if (assoc->TableRegister == SN_BOTH_TBL) { + /* libalias log -- controlled by libalias */ + if (la->packetAliasMode & PKT_ALIAS_LOG) + SctpShowAliasStats(la); - SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); - } + SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); + } - return(SN_ADD_OK); + return(SN_ADD_OK); } /** @ingroup Hash @@ -2293,33 +2271,33 @@ AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc) static void RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc) { - // struct sctp_nat_assoc *found; - if (assoc == NULL) { - /* very bad, log and die*/ - SN_LOG(SN_LOG_LOW, - logsctperror("ERROR: alias_sctp:RmSctpAssoc(NULL)\n", 0, 0, SN_TO_NODIR)); - return; - } - /* log if association is fully up and now closing */ - if (assoc->TableRegister == SN_BOTH_TBL) { - SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "$")); - } - LIBALIAS_LOCK_ASSERT(la); - if (assoc->TableRegister & SN_LOCAL_TBL) { - assoc->TableRegister ^= SN_LOCAL_TBL; - la->sctpLinkCount--; //decrement link count - LIST_REMOVE(assoc, list_L); - } + // struct sctp_nat_assoc *found; + if (assoc == NULL) { + /* very bad, log and die*/ + SN_LOG(SN_LOG_LOW, + logsctperror("ERROR: alias_sctp:RmSctpAssoc(NULL)\n", 0, 0, SN_TO_NODIR)); + return; + } + /* log if association is fully up and now closing */ + if (assoc->TableRegister == SN_BOTH_TBL) { + SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "$")); + } + LIBALIAS_LOCK_ASSERT(la); + if (assoc->TableRegister & SN_LOCAL_TBL) { + assoc->TableRegister ^= SN_LOCAL_TBL; + la->sctpLinkCount--; //decrement link count + LIST_REMOVE(assoc, list_L); + } - if (assoc->TableRegister & SN_GLOBAL_TBL) { - assoc->TableRegister ^= SN_GLOBAL_TBL; - la->sctpLinkCount--; //decrement link count - LIST_REMOVE(assoc, list_G); - } - // sn_free(assoc); //Don't remove now, remove if needed later - /* libalias logging -- controlled by libalias log definition */ - if (la->packetAliasMode & PKT_ALIAS_LOG) - SctpShowAliasStats(la); + if (assoc->TableRegister & SN_GLOBAL_TBL) { + assoc->TableRegister ^= SN_GLOBAL_TBL; + la->sctpLinkCount--; //decrement link count + LIST_REMOVE(assoc, list_G); + } + // sn_free(assoc); //Don't remove now, remove if needed later + /* libalias logging -- controlled by libalias log definition */ + if (la->packetAliasMode & PKT_ALIAS_LOG) + SctpShowAliasStats(la); } /** @@ -2333,14 +2311,14 @@ RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc) */ static void freeGlobalAddressList(struct sctp_nat_assoc *assoc) { - struct sctp_GlobalAddress *gaddr1=NULL,*gaddr2=NULL; - /*free global address list*/ - gaddr1 = LIST_FIRST(&(assoc->Gaddr)); - while (gaddr1 != NULL) { - gaddr2 = LIST_NEXT(gaddr1, list_Gaddr); - sn_free(gaddr1); - gaddr1 = gaddr2; - } + struct sctp_GlobalAddress *gaddr1=NULL,*gaddr2=NULL; + /*free global address list*/ + gaddr1 = LIST_FIRST(&(assoc->Gaddr)); + while (gaddr1 != NULL) { + gaddr2 = LIST_NEXT(gaddr1, list_Gaddr); + sn_free(gaddr1); + gaddr1 = gaddr2; + } } /* ---------------------------------------------------------------------- * TIMER QUEUE CODE @@ -2372,13 +2350,13 @@ static void freeGlobalAddressList(struct sctp_nat_assoc *assoc) static void sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) { - int add_loc; - LIBALIAS_LOCK_ASSERT(la); - add_loc = assoc->exp - la->sctpNatTimer.loc_time + la->sctpNatTimer.cur_loc; - if (add_loc >= SN_TIMER_QUEUE_SIZE) - add_loc -= SN_TIMER_QUEUE_SIZE; - LIST_INSERT_HEAD(&la->sctpNatTimer.TimerQ[add_loc], assoc, timer_Q); - assoc->exp_loc = add_loc; + int add_loc; + LIBALIAS_LOCK_ASSERT(la); + add_loc = assoc->exp - la->sctpNatTimer.loc_time + la->sctpNatTimer.cur_loc; + if (add_loc >= SN_TIMER_QUEUE_SIZE) + add_loc -= SN_TIMER_QUEUE_SIZE; + LIST_INSERT_HEAD(&la->sctpNatTimer.TimerQ[add_loc], assoc, timer_Q); + assoc->exp_loc = add_loc; } /** @ingroup Timer @@ -2393,8 +2371,8 @@ sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) static void sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) { - LIBALIAS_LOCK_ASSERT(la); - LIST_REMOVE(assoc, timer_Q);/* Note this is O(1) */ + LIBALIAS_LOCK_ASSERT(la); + LIST_REMOVE(assoc, timer_Q);/* Note this is O(1) */ } @@ -2412,13 +2390,13 @@ sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) static void sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp) { - if (newexp < assoc->exp) { - sctp_RmTimeOut(la, assoc); - assoc->exp = newexp; - sctp_AddTimeOut(la, assoc); - } else { - assoc->exp = newexp; - } + if (newexp < assoc->exp) { + sctp_RmTimeOut(la, assoc); + assoc->exp = newexp; + sctp_AddTimeOut(la, assoc); + } else { + assoc->exp = newexp; + } } /** @ingroup Timer @@ -2440,29 +2418,29 @@ sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp) void sctp_CheckTimers(struct libalias *la) { - struct sctp_nat_assoc *assoc; + struct sctp_nat_assoc *assoc; - LIBALIAS_LOCK_ASSERT(la); - while(la->timeStamp >= la->sctpNatTimer.loc_time) { - while (!LIST_EMPTY(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc])) { - assoc = LIST_FIRST(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc]); - //SLIST_REMOVE_HEAD(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc], timer_Q); - LIST_REMOVE(assoc, timer_Q); - if (la->timeStamp >= assoc->exp) { /* state expired */ - SN_LOG(((assoc->state == SN_CL)?(SN_LOG_DEBUG):(SN_LOG_INFO)), - logsctperror("Timer Expired", assoc->g_vtag, assoc->state, SN_TO_NODIR)); - RmSctpAssoc(la, assoc); - freeGlobalAddressList(assoc); - sn_free(assoc); - } else {/* state not expired, reschedule timer*/ - sctp_AddTimeOut(la, assoc); - } - } - /* Goto next location in the timer queue*/ - ++la->sctpNatTimer.loc_time; - if (++la->sctpNatTimer.cur_loc >= SN_TIMER_QUEUE_SIZE) - la->sctpNatTimer.cur_loc = 0; - } + LIBALIAS_LOCK_ASSERT(la); + while(la->timeStamp >= la->sctpNatTimer.loc_time) { + while (!LIST_EMPTY(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc])) { + assoc = LIST_FIRST(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc]); + //SLIST_REMOVE_HEAD(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc], timer_Q); + LIST_REMOVE(assoc, timer_Q); + if (la->timeStamp >= assoc->exp) { /* state expired */ + SN_LOG(((assoc->state == SN_CL)?(SN_LOG_DEBUG):(SN_LOG_INFO)), + logsctperror("Timer Expired", assoc->g_vtag, assoc->state, SN_TO_NODIR)); + RmSctpAssoc(la, assoc); + freeGlobalAddressList(assoc); + sn_free(assoc); + } else {/* state not expired, reschedule timer*/ + sctp_AddTimeOut(la, assoc); + } + } + /* Goto next location in the timer queue*/ + ++la->sctpNatTimer.loc_time; + if (++la->sctpNatTimer.cur_loc >= SN_TIMER_QUEUE_SIZE) + la->sctpNatTimer.cur_loc = 0; + } } /* ---------------------------------------------------------------------- @@ -2486,19 +2464,19 @@ sctp_CheckTimers(struct libalias *la) static void logsctperror(char* errormsg, uint32_t vtag, int error, int direction) { - char dir; - switch(direction) { - case SN_TO_LOCAL: - dir = 'L'; - break; - case SN_TO_GLOBAL: - dir = 'G'; - break; - default: - dir = '*'; - break; - } - SctpAliasLog("->%c %s (vt=%u) %d\n", dir, errormsg, ntohl(vtag), error); + char dir; + switch(direction) { + case SN_TO_LOCAL: + dir = 'L'; + break; + case SN_TO_GLOBAL: + dir = 'G'; + break; + default: + dir = '*'; + break; + } + SctpAliasLog("->%c %s (vt=%u) %d\n", dir, errormsg, ntohl(vtag), error); } /** @ingroup Logging @@ -2510,47 +2488,47 @@ logsctperror(char* errormsg, uint32_t vtag, int error, int direction) static void logsctpparse(int direction, struct sctp_nat_msg *sm) { - char *ploc, *pstate; - switch(direction) { - case SN_TO_LOCAL: - ploc = "TO_LOCAL -"; - break; - case SN_TO_GLOBAL: - ploc = "TO_GLOBAL -"; - break; - default: - ploc = ""; - } - switch(sm->msg) { - case SN_SCTP_INIT: - pstate = "Init"; - break; - case SN_SCTP_INITACK: - pstate = "InitAck"; - break; - case SN_SCTP_ABORT: - pstate = "Abort"; - break; - case SN_SCTP_SHUTACK: - pstate = "ShutAck"; - break; - case SN_SCTP_SHUTCOMP: - pstate = "ShutComp"; - break; - case SN_SCTP_ASCONF: - pstate = "Asconf"; - break; - case SN_SCTP_ASCONFACK: - pstate = "AsconfAck"; - break; - case SN_SCTP_OTHER: - pstate = "Other"; - break; - default: - pstate = "***ERROR***"; - break; - } - SctpAliasLog("Parsed: %s %s\n", ploc, pstate); + char *ploc, *pstate; + switch(direction) { + case SN_TO_LOCAL: + ploc = "TO_LOCAL -"; + break; + case SN_TO_GLOBAL: + ploc = "TO_GLOBAL -"; + break; + default: + ploc = ""; + } + switch(sm->msg) { + case SN_SCTP_INIT: + pstate = "Init"; + break; + case SN_SCTP_INITACK: + pstate = "InitAck"; + break; + case SN_SCTP_ABORT: + pstate = "Abort"; + break; + case SN_SCTP_SHUTACK: + pstate = "ShutAck"; + break; + case SN_SCTP_SHUTCOMP: + pstate = "ShutComp"; + break; + case SN_SCTP_ASCONF: + pstate = "Asconf"; + break; + case SN_SCTP_ASCONFACK: + pstate = "AsconfAck"; + break; + case SN_SCTP_OTHER: + pstate = "Other"; + break; + default: + pstate = "***ERROR***"; + break; + } + SctpAliasLog("Parsed: %s %s\n", ploc, pstate); } /** @ingroup Logging @@ -2561,39 +2539,39 @@ logsctpparse(int direction, struct sctp_nat_msg *sm) */ static void logsctpassoc(struct sctp_nat_assoc *assoc, char* s) { - struct sctp_GlobalAddress *G_Addr = NULL; - char *sp; - switch(assoc->state) { - case SN_ID: - sp = "ID "; - break; - case SN_INi: - sp = "INi "; - break; - case SN_INa: - sp = "INa "; - break; - case SN_UP: - sp = "UP "; - break; - case SN_CL: - sp = "CL "; - break; - case SN_RM: - sp = "RM "; - break; - default: - sp = "***ERROR***"; - break; - } - SctpAliasLog("%sAssoc: %s exp=%u la=%s lv=%u lp=%u gv=%u gp=%u tbl=%d\n", - s, sp, assoc->exp, inet_ntoa(assoc->l_addr), ntohl(assoc->l_vtag), - ntohs(assoc->l_port), ntohl(assoc->g_vtag), ntohs(assoc->g_port), - assoc->TableRegister); - /* list global addresses */ - LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { - SctpAliasLog("\t\tga=%s\n",inet_ntoa(G_Addr->g_addr)); - } + struct sctp_GlobalAddress *G_Addr = NULL; + char *sp; + switch(assoc->state) { + case SN_ID: + sp = "ID "; + break; + case SN_INi: + sp = "INi "; + break; + case SN_INa: + sp = "INa "; + break; + case SN_UP: + sp = "UP "; + break; + case SN_CL: + sp = "CL "; + break; + case SN_RM: + sp = "RM "; + break; + default: + sp = "***ERROR***"; + break; + } + SctpAliasLog("%sAssoc: %s exp=%u la=%s lv=%u lp=%u gv=%u gp=%u tbl=%d\n", + s, sp, assoc->exp, inet_ntoa(assoc->l_addr), ntohl(assoc->l_vtag), + ntohs(assoc->l_port), ntohl(assoc->g_vtag), ntohs(assoc->g_port), + assoc->TableRegister); + /* list global addresses */ + LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { + SctpAliasLog("\t\tga=%s\n",inet_ntoa(G_Addr->g_addr)); + } } /** @ingroup Logging @@ -2603,15 +2581,15 @@ static void logsctpassoc(struct sctp_nat_assoc *assoc, char* s) */ static void logSctpGlobal(struct libalias *la) { - u_int i; - struct sctp_nat_assoc *assoc = NULL; + u_int i; + struct sctp_nat_assoc *assoc = NULL; - SctpAliasLog("G->\n"); - for (i=0; i < la->sctpNatTableSize; i++) { - LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { - logsctpassoc(assoc, " "); - } - } + SctpAliasLog("G->\n"); + for (i=0; i < la->sctpNatTableSize; i++) { + LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { + logsctpassoc(assoc, " "); + } + } } /** @ingroup Logging @@ -2621,15 +2599,15 @@ static void logSctpGlobal(struct libalias *la) */ static void logSctpLocal(struct libalias *la) { - u_int i; - struct sctp_nat_assoc *assoc = NULL; + u_int i; + struct sctp_nat_assoc *assoc = NULL; - SctpAliasLog("L->\n"); - for (i=0; i < la->sctpNatTableSize; i++) { - LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { - logsctpassoc(assoc, " "); - } - } + SctpAliasLog("L->\n"); + for (i=0; i < la->sctpNatTableSize; i++) { + LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { + logsctpassoc(assoc, " "); + } + } } /** @ingroup Logging @@ -2639,18 +2617,18 @@ static void logSctpLocal(struct libalias *la) */ static void logTimerQ(struct libalias *la) { - static char buf[50]; - u_int i; - struct sctp_nat_assoc *assoc = NULL; - - SctpAliasLog("t->\n"); - for (i=0; i < SN_TIMER_QUEUE_SIZE; i++) { - LIST_FOREACH(assoc, &la->sctpNatTimer.TimerQ[i], timer_Q) { - snprintf(buf, 50, " l=%u ",i); - //SctpAliasLog(la->logDesc," l=%d ",i); - logsctpassoc(assoc, buf); - } - } + static char buf[50]; + u_int i; + struct sctp_nat_assoc *assoc = NULL; + + SctpAliasLog("t->\n"); + for (i=0; i < SN_TIMER_QUEUE_SIZE; i++) { + LIST_FOREACH(assoc, &la->sctpNatTimer.TimerQ[i], timer_Q) { + snprintf(buf, 50, " l=%u ",i); + //SctpAliasLog(la->logDesc," l=%d ",i); + logsctpassoc(assoc, buf); + } + } } /** @ingroup Logging @@ -2665,23 +2643,23 @@ static void logTimerQ(struct libalias *la) static void SctpAliasLog(const char *format, ...) { - char buffer[LIBALIAS_BUF_SIZE]; - va_list ap; - va_start(ap, format); - vsnprintf(buffer, LIBALIAS_BUF_SIZE, format, ap); - va_end(ap); - log(LOG_SECURITY | LOG_INFO, - "alias_sctp: %s", buffer); + char buffer[LIBALIAS_BUF_SIZE]; + va_list ap; + va_start(ap, format); + vsnprintf(buffer, LIBALIAS_BUF_SIZE, format, ap); + va_end(ap); + log(LOG_SECURITY | LOG_INFO, + "alias_sctp: %s", buffer); } #else static void SctpAliasLog(FILE *stream, const char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vfprintf(stream, format, ap); - va_end(ap); - fflush(stream); + va_start(ap, format); + vfprintf(stream, format, ap); + va_end(ap); + fflush(stream); } #endif diff --git a/sys/netinet/libalias/alias_sctp.h b/sys/netinet/libalias/alias_sctp.h index f299a6f..7953f43 100644 --- a/sys/netinet/libalias/alias_sctp.h +++ b/sys/netinet/libalias/alias_sctp.h @@ -1,34 +1,9 @@ -/*/* $Id$ */ -//#ifndef lint -//static char vcid[] = "$Id$"; -//#endif /* lint */ /** * @file alias_sctp.h * Copyright (c) 2008, Centre for Advanced Internet Architectures * Swinburne University of Technology, Melbourne, Australia * (CRICOS number 00111D). * - * Alias_sctp forms part of the libalias kernel module to handle - * Network Address Translation (NAT) for the SCTP protocol. - * - * This software was developed by David A. Hayes - * with leadership and advice from Jason But - * - * The design is outlined in CAIA technical report number 080618A - * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW") - * - * Development is part of the CAIA SONATA project, - * proposed by Jason But and Grenville Armitage: - * http://caia.swin.edu.au/urp/sonata/ - * - * - * This project has been made possible in part by a grant from - * the Cisco University Research Program Fund at Community - * Foundation Silicon Valley. - * - * - * All rights reserved. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -54,7 +29,28 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Alias_sctp forms part of the libalias kernel module to handle + * Network Address Translation (NAT) for the SCTP protocol. + * + * This software was developed by David A. Hayes + * with leadership and advice from Jason But + * + * The design is outlined in CAIA technical report number 080618A + * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW") + * + * Development is part of the CAIA SONATA project, + * proposed by Jason But and Grenville Armitage: + * http://caia.swin.edu.au/urp/sonata/ + * + * + * This project has been made possible in part by a grant from + * the Cisco University Research Program Fund at Community + * Foundation Silicon Valley. + * */ + +/* $FreeBSD$ */ + #ifndef _ALIAS_SCTP_H_ #define _ALIAS_SCTP_H_ @@ -136,27 +132,27 @@ * Information is stored in network byte order (as is libalias)*** */ struct sctp_nat_assoc { - uint32_t l_vtag; /**< local side verification tag */ - uint16_t l_port; /**< local side port number */ - uint32_t g_vtag; /**< global side verification tag */ - uint16_t g_port; /**< global side port number */ - struct in_addr l_addr; /**< local ip address */ - struct in_addr a_addr; /**< alias ip address */ - int state; /**< current state of NAT association */ - int TableRegister; /**< stores which look up tables association is registered in */ - int exp; /**< timer expiration in seconds from uptime */ - int exp_loc; /**< current location in timer_Q */ - int num_Gaddr; /**< number of global IP addresses in the list */ - LIST_HEAD(sctpGlobalAddresshead,sctp_GlobalAddress) Gaddr; /**< List of global addresses */ - LIST_ENTRY (sctp_nat_assoc) list_L; /**< Linked list of pointers for Local table*/ - LIST_ENTRY (sctp_nat_assoc) list_G; /**< Linked list of pointers for Global table */ - LIST_ENTRY (sctp_nat_assoc) timer_Q; /**< Linked list of pointers for timer Q */ + uint32_t l_vtag; /**< local side verification tag */ + uint16_t l_port; /**< local side port number */ + uint32_t g_vtag; /**< global side verification tag */ + uint16_t g_port; /**< global side port number */ + struct in_addr l_addr; /**< local ip address */ + struct in_addr a_addr; /**< alias ip address */ + int state; /**< current state of NAT association */ + int TableRegister; /**< stores which look up tables association is registered in */ + int exp; /**< timer expiration in seconds from uptime */ + int exp_loc; /**< current location in timer_Q */ + int num_Gaddr; /**< number of global IP addresses in the list */ + LIST_HEAD(sctpGlobalAddresshead,sctp_GlobalAddress) Gaddr; /**< List of global addresses */ + LIST_ENTRY (sctp_nat_assoc) list_L; /**< Linked list of pointers for Local table*/ + LIST_ENTRY (sctp_nat_assoc) list_G; /**< Linked list of pointers for Global table */ + LIST_ENTRY (sctp_nat_assoc) timer_Q; /**< Linked list of pointers for timer Q */ //Using libalias locking }; struct sctp_GlobalAddress { - struct in_addr g_addr; - LIST_ENTRY (sctp_GlobalAddress) list_Gaddr; /**< Linked list of pointers for Global table */ + struct in_addr g_addr; + LIST_ENTRY (sctp_GlobalAddress) list_Gaddr; /**< Linked list of pointers for Global table */ }; /** @@ -165,9 +161,9 @@ struct sctp_GlobalAddress { * The only chunks whose contents are of any interest are the INIT and ASCONF_AddIP */ union sctpChunkOfInt { - struct sctp_init *Init; /**< Pointer to Init Chunk */ - struct sctp_init_ack *InitAck; /**< Pointer to Init Chunk */ - struct sctp_paramhdr *Asconf; /**< Pointer to ASCONF chunk */ + struct sctp_init *Init; /**< Pointer to Init Chunk */ + struct sctp_init_ack *InitAck; /**< Pointer to Init Chunk */ + struct sctp_paramhdr *Asconf; /**< Pointer to ASCONF chunk */ }; @@ -177,15 +173,15 @@ union sctpChunkOfInt { * Structure containing the relevant information from the SCTP message */ struct sctp_nat_msg { - uint16_t msg; /**< one of the key messages defined above */ + uint16_t msg; /**< one of the key messages defined above */ #ifdef INET6 - // struct ip6_hdr *ip_hdr; /**< pointer to ip packet header */ /*no inet6 support yet*/ + // struct ip6_hdr *ip_hdr; /**< pointer to ip packet header */ /*no inet6 support yet*/ #else - struct ip *ip_hdr; /**< pointer to ip packet header */ + struct ip *ip_hdr; /**< pointer to ip packet header */ #endif //#ifdef INET6 - struct sctphdr *sctp_hdr; /**< pointer to sctp common header */ - union sctpChunkOfInt sctpchnk; /**< union of pointers to the chunk of interest */ - int chunk_length; /**< length of chunk of interest */ + struct sctphdr *sctp_hdr; /**< pointer to sctp common header */ + union sctpChunkOfInt sctpchnk; /**< union of pointers to the chunk of interest */ + int chunk_length; /**< length of chunk of interest */ }; @@ -195,9 +191,9 @@ struct sctp_nat_msg { */ struct sctp_nat_timer { - int loc_time; /**< time in seconds for the current location in the queue */ - int cur_loc; /**< index of the current location in the circular queue */ - LIST_HEAD(sctpTimerQ,sctp_nat_assoc) *TimerQ; /**< List of associations at this position in the timer Q */ + int loc_time; /**< time in seconds for the current location in the queue */ + int cur_loc; /**< index of the current location in the circular queue */ + LIST_HEAD(sctpTimerQ,sctp_nat_assoc) *TimerQ; /**< List of associations at this position in the timer Q */ }; diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 9fe0eca..27f4b9c 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -276,10 +276,8 @@ rip_input(struct mbuf *m, int off) continue; if (inp->inp_faddr.s_addr != ip->ip_src.s_addr) continue; - if (jailed(inp->inp_cred)) { - if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst)) - continue; - } + if (prison_check_ip4(inp->inp_cred, &ip->ip_dst) != 0) + continue; if (last != NULL) { struct mbuf *n; @@ -306,10 +304,8 @@ rip_input(struct mbuf *m, int off) if (inp->inp_faddr.s_addr && inp->inp_faddr.s_addr != ip->ip_src.s_addr) continue; - if (jailed(inp->inp_cred)) { - if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst)) - continue; - } + if (prison_check_ip4(inp->inp_cred, &ip->ip_dst) != 0) + continue; if (last != NULL) { struct mbuf *n; @@ -370,14 +366,12 @@ rip_output(struct mbuf *m, struct socket *so, u_long dst) ip->ip_off = 0; ip->ip_p = inp->inp_ip_p; ip->ip_len = m->m_pkthdr.len; - if (jailed(inp->inp_cred)) { - if (prison_getip4(inp->inp_cred, &ip->ip_src)) { - INP_RUNLOCK(inp); - m_freem(m); - return (EPERM); - } - } else { - ip->ip_src = inp->inp_laddr; + ip->ip_src = inp->inp_laddr; + error = prison_get_ip4(inp->inp_cred, &ip->ip_src); + if (error != 0) { + INP_RUNLOCK(inp); + m_freem(m); + return (error); } ip->ip_dst.s_addr = dst; ip->ip_ttl = inp->inp_ip_ttl; @@ -388,10 +382,11 @@ rip_output(struct mbuf *m, struct socket *so, u_long dst) } INP_RLOCK(inp); ip = mtod(m, struct ip *); - if (!prison_check_ip4(inp->inp_cred, &ip->ip_src)) { + error = prison_check_ip4(inp->inp_cred, &ip->ip_src); + if (error != 0) { INP_RUNLOCK(inp); m_freem(m); - return (EPERM); + return (error); } /* @@ -803,12 +798,14 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) INIT_VNET_INET(so->so_vnet); struct sockaddr_in *addr = (struct sockaddr_in *)nam; struct inpcb *inp; + int error; if (nam->sa_len != sizeof(*addr)) return (EINVAL); - if (!prison_check_ip4(td->td_ucred, &addr->sin_addr)) - return (EADDRNOTAVAIL); + error = prison_check_ip4(td->td_ucred, &addr->sin_addr); + if (error != 0) + return (error); if (TAILQ_EMPTY(&V_ifnet) || (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index 71715cc..6da97ec 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -1645,8 +1645,10 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, bcopy(p_random->random_data, new_key->key, random_len); } #else - keylen = sizeof(*p_random) + random_len + sizeof(*chunks) + num_chunks + - sizeof(*hmacs) + hmacs_len; + keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; + if (chunks != NULL) { + keylen += sizeof(*chunks) + num_chunks; + } new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index cc48d2f..ca9c010 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -37,8 +37,15 @@ __FBSDID("$FreeBSD$"); #define __sctp_constants_h__ /* IANA assigned port number for SCTP over UDP encapsulation */ -#define SCTP_OVER_UDP_TUNNELING_PORT 9899 - +/* For freebsd we cannot bind the port at + * startup. Otherwise what will happen is + * we really won't be bound. The user must + * put it into the sysctl... or we need + * to build a special timer for this to allow + * us to wait 1 second or so after the system + * comes up. + */ +#define SCTP_OVER_UDP_TUNNELING_PORT 0 /* Number of packets to get before sack sent by default */ #define SCTP_DEFAULT_SACK_FREQ 2 @@ -310,10 +317,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_PARTIAL_DELIVERY_SHIFT 1 -/* Minimum number of bytes read by user before we - * condsider doing a rwnd update - */ - /* * default HMAC for cookies, etc... use one of the AUTH HMAC id's * SCTP_HMAC is the HMAC_ID to use @@ -323,21 +326,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_SIGNATURE_SIZE SCTP_AUTH_DIGEST_LEN_SHA1 #define SCTP_SIGNATURE_ALOC_SIZE SCTP_SIGNATURE_SIZE -/* DEFINE HERE WHAT CRC YOU WANT TO USE */ -#define SCTP_USECRC_RFC2960 1 -/* #define SCTP_USECRC_FLETCHER 1 */ -/* #define SCTP_USECRC_SSHCRC32 1 */ -/* #define SCTP_USECRC_FASTCRC32 1 */ -/* #define SCTP_USECRC_CRC32 1 */ -/* #define SCTP_USECRC_TCP32 1 */ -/* #define SCTP_USECRC_CRC16SMAL 1 */ -/* #define SCTP_USECRC_CRC16 1 */ -/* #define SCTP_USECRC_MODADLER 1 */ - -#ifndef SCTP_ADLER32_BASE -#define SCTP_ADLER32_BASE 65521 -#endif - /* * the SCTP protocol signature this includes the version number encoded in * the last 4 bits of the signature. @@ -619,43 +607,16 @@ __FBSDID("$FreeBSD$"); -/* - * Number of ticks before the soxwakeup() event that is delayed is sent AFTER - * the accept() call - */ - -/* - * Of course we really don't collect stale cookies, being folks of decerning - * taste. However we do count them, if we get too many before the association - * comes up.. we give up. Below is the constant that dictates when we give it - * up...this is a implemenation dependent treatment. In ours we do not ask - * for a extension of time, but just retry this many times... - */ - /* max number of TSN's dup'd that I will hold */ #define SCTP_MAX_DUP_TSNS 20 /* * Here we define the types used when setting the retry amounts. */ -/* constants for type of set */ - -/* Maximum TSN's we will summarize in a drop report */ - /* How many drop re-attempts we make on INIT/COOKIE-ECHO */ #define SCTP_RETRY_DROPPED_THRESH 4 /* - * And the max we will keep a history of in the tcb which MUST be lower than - * 256. - */ - -/* - * Here we define the default timers and the default number of attemts we - * make for each respective side (send/init). - */ - -/* * Maxmium number of chunks a single association can have on it. Note that * this is a squishy number since the count can run over this if the user * sends a large message down .. the fragmented chunks don't count until @@ -763,7 +724,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_DEBUG_INDATA1 0x01000000 #define SCTP_DEBUG_INDATA2 0x02000000 /* unused */ #define SCTP_DEBUG_INDATA3 0x04000000 /* unused */ -#define SCTP_DEBUG_INDATA4 0x08000000 /* unused */ +#define SCTP_DEBUG_CRCOFFLOAD 0x08000000 /* unused */ #define SCTP_DEBUG_USRREQ1 0x10000000 /* unused */ #define SCTP_DEBUG_USRREQ2 0x20000000 /* unused */ #define SCTP_DEBUG_PEEL1 0x40000000 @@ -783,7 +744,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_INITIAL_CWND 4380 -#define SCTP_DEFAULT_MTU 1500 /* emegency default MTU */ +#define SCTP_DEFAULT_MTU 1500 /* emergency default MTU */ /* amount peer is obligated to have in rwnd or I will abort */ #define SCTP_MIN_RWND 1500 @@ -996,13 +957,6 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_STACK_VTAG_HASH_SIZE 32 - -/* - * If we use the per-endpoint model than we do not have a hash table of - * entries but instead have a single head pointer and we must crawl through - * the entire list. - */ - /* * Number of seconds of time wait for a vtag. */ diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c index 7f0e742..3fba39e 100644 --- a/sys/netinet/sctp_crc32.c +++ b/sys/netinet/sctp_crc32.c @@ -34,12 +34,16 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/uio.h> +#include <netinet/sctp.h> #include <netinet/sctp_os.h> #include <netinet/sctp_crc32.h> +#include <netinet/sctp_pcb.h> -#ifndef SCTP_USE_ADLER32 - - +#if !defined(SCTP_WITH_NO_CSUM) /** * * Routine Description: @@ -80,12 +84,14 @@ __FBSDID("$FreeBSD$"); * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o32[256] = @@ -134,12 +140,14 @@ uint32_t sctp_crc_tableil8_o32[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o40[256] = @@ -188,12 +196,14 @@ uint32_t sctp_crc_tableil8_o40[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o48[256] = @@ -242,12 +252,14 @@ uint32_t sctp_crc_tableil8_o48[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o56[256] = @@ -296,12 +308,14 @@ uint32_t sctp_crc_tableil8_o56[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o64[256] = @@ -350,12 +364,14 @@ uint32_t sctp_crc_tableil8_o64[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o72[256] = @@ -404,12 +420,14 @@ uint32_t sctp_crc_tableil8_o72[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o80[256] = @@ -458,12 +476,14 @@ uint32_t sctp_crc_tableil8_o80[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o88[256] = @@ -506,6 +526,7 @@ uint32_t sctp_crc_tableil8_o88[256] = * end of the CRC lookup table crc_tableil8_o88 */ + static uint32_t sctp_crc32c_sb8_64_bit(uint32_t crc, unsigned char *p_buf, @@ -662,7 +683,7 @@ uint32_t sctp_crc_c[256] = { #define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF]) -uint32_t +static uint32_t old_update_crc32(uint32_t crc32c, unsigned char *buffer, unsigned int length) @@ -677,7 +698,7 @@ old_update_crc32(uint32_t crc32c, uint32_t -sctp_csum_finalize(uint32_t crc32c) +sctp_finalize_crc32(uint32_t crc32c) { uint32_t result; @@ -709,4 +730,88 @@ sctp_csum_finalize(uint32_t crc32c) return (crc32c); } +#endif /* !defined(SCTP_WITH_NO_CSUM) */ + +#if defined(SCTP_WITH_NO_CSUM) +uint32_t +sctp_calculate_cksum(struct mbuf *m, uint32_t offset) +{ + return (0); +} + +#else +uint32_t +sctp_calculate_cksum(struct mbuf *m, uint32_t offset) +{ + /* + * given a mbuf chain with a packetheader offset by 'offset' + * pointing at a sctphdr (with csum set to 0) go through the chain + * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also + * has a side bonus as it will calculate the total length of the + * mbuf chain. Note: if offset is greater than the total mbuf + * length, checksum=1, pktlen=0 is returned (ie. no real error code) + */ + uint32_t base = 0xffffffff; + struct mbuf *at; + + at = m; + /* find the correct mbuf and offset into mbuf */ + while ((at != NULL) && (offset > (uint32_t) SCTP_BUF_LEN(at))) { + offset -= SCTP_BUF_LEN(at); /* update remaining offset + * left */ + at = SCTP_BUF_NEXT(at); + } + while (at != NULL) { + if ((SCTP_BUF_LEN(at) - offset) > 0) { + if ((SCTP_BUF_LEN(at) - offset) < 4) { + /* Use old method if less than 4 bytes */ + base = old_update_crc32(base, + (unsigned char *)(SCTP_BUF_AT(at, offset)), + (unsigned int)(SCTP_BUF_LEN(at) - offset)); + } else { + base = update_crc32(base, + (unsigned char *)(SCTP_BUF_AT(at, offset)), + (unsigned int)(SCTP_BUF_LEN(at) - offset)); + } + /* we only offset once into the first mbuf */ + } + if (offset) { + if (offset < (uint32_t) SCTP_BUF_LEN(at)) + offset = 0; + else + offset -= SCTP_BUF_LEN(at); + } + at = SCTP_BUF_NEXT(at); + } + base = sctp_finalize_crc32(base); + return (base); +} + #endif + +void +sctp_delayed_cksum(struct mbuf *m) +{ + struct ip *ip; + uint32_t checksum; + uint32_t offset; + + ip = mtod(m, struct ip *); + offset = ip->ip_hl << 2; + checksum = sctp_calculate_cksum(m, offset); + SCTP_STAT_DECR(sctps_sendhwcrc); + SCTP_STAT_INCR(sctps_sendswcrc); + offset += offsetof(struct sctphdr, checksum); + + if (offset + sizeof(uint32_t) > (uint32_t) (m->m_len)) { + printf("delayed m_pullup, m->len: %d off: %d p: %d\n", + (uint32_t) m->m_len, offset, ip->ip_p); + /* + * XXX this shouldn't happen, but if it does, the correct + * behavior may be to insert the checksum in the appropriate + * next mbuf in the chain. + */ + return; + } + *(uint32_t *) (m->m_data + offset) = checksum; +} diff --git a/sys/netinet/sctp_crc32.h b/sys/netinet/sctp_crc32.h index 88739ed..2c353d2 100644 --- a/sys/netinet/sctp_crc32.h +++ b/sys/netinet/sctp_crc32.h @@ -36,16 +36,12 @@ __FBSDID("$FreeBSD$"); #ifndef __crc32c_h__ #define __crc32c_h__ -#ifndef SCTP_USE_ADLER32 - #if defined(_KERNEL) || defined(__Userspace__) +uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t); +void sctp_delayed_cksum(struct mbuf *); uint32_t update_crc32(uint32_t, unsigned char *, unsigned int); - -uint32_t old_update_crc32(uint32_t, unsigned char *, unsigned int); - -uint32_t sctp_csum_finalize(uint32_t); - +uint32_t sctp_finalize_crc32(uint32_t); #endif /* _KERNEL */ -#endif /* !SCTP_USE_ADLER32 */ + #endif /* __crc32c_h__ */ diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index c686fac..2d8a1f2 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_asconf.h> #include <netinet/sctp_bsd_addr.h> #include <netinet/sctp_timer.h> +#include <netinet/sctp_crc32.h> #include <netinet/udp.h> @@ -1384,14 +1385,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* FOOBAR */ return (NULL); } - /* pre-reserve some space */ -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); /* Set the len */ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); ph = mtod(op_err, struct sctp_paramhdr *); @@ -2504,15 +2497,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* FOOBAR */ return (NULL); } - /* pre-reserve some space */ -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - /* Set the len */ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_stale_cookie_msg); scm = mtod(op_err, struct sctp_stale_cookie_msg *); @@ -2598,9 +2582,9 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, } } } - if (to == NULL) + if (to == NULL) { return (NULL); - + } cookie_len -= SCTP_SIGNATURE_SIZE; if (*stcb == NULL) { /* this is the "normal" case... get a new TCB */ @@ -5594,7 +5578,6 @@ sctp_input_with_port(i_pak, off, port) int refcount_up = 0; int length, mlen, offset; - if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) { SCTP_RELEASE_PKT(i_pak); return; @@ -5642,6 +5625,11 @@ sctp_input_with_port(i_pak, off, port) } ip = mtod(m, struct ip *); } + /* validate mbuf chain length with IP payload length */ + if (mlen < (SCTP_GET_IPV4_LENGTH(ip) - iphlen)) { + SCTP_STAT_INCR(sctps_hdrops); + goto bad; + } sh = (struct sctphdr *)((caddr_t)ip + iphlen); ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(*sh)); SCTPDBG(SCTP_DEBUG_INPUT1, @@ -5659,15 +5647,26 @@ sctp_input_with_port(i_pak, off, port) goto bad; } /* validate SCTP checksum */ + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, + "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", + m->m_pkthdr.len, + if_name(m->m_pkthdr.rcvif), + m->m_pkthdr.csum_flags); + if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { + SCTP_STAT_INCR(sctps_recvhwcrc); + goto sctp_skip_csum_4; + } check = sh->checksum; /* save incoming checksum */ if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) && ((ip->ip_src.s_addr == ip->ip_dst.s_addr) || (SCTP_IS_IT_LOOPBACK(m))) ) { + SCTP_STAT_INCR(sctps_recvnocrc); goto sctp_skip_csum_4; } sh->checksum = 0; /* prepare for calc */ - calc_check = sctp_calculate_sum(m, &mlen, iphlen); + calc_check = sctp_calculate_cksum(m, iphlen); + SCTP_STAT_INCR(sctps_recvswcrc); if (calc_check != check) { SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", calc_check, check, m, mlen, iphlen); @@ -5699,11 +5698,6 @@ sctp_skip_csum_4: SCTP_STAT_INCR(sctps_hdrops); goto bad; } - /* validate mbuf chain length with IP payload length */ - if (mlen < (SCTP_GET_IPV4_LENGTH(ip) - iphlen)) { - SCTP_STAT_INCR(sctps_hdrops); - goto bad; - } /* * Locate pcb and tcb for datagram sctp_findassociation_addr() wants * IP/SCTP/first chunk header... diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index d0e7a18..fcaf715 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -154,11 +154,8 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT); #define MOD_IPSEC ipsec /* then define the macro(s) that hook into the vimage macros */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 800056 #define MODULE_GLOBAL(__MODULE, __SYMBOL) V_ ## __SYMBOL -#else -#define MODULE_GLOBAL(__MODULE, __SYMBOL) (__SYMBOL) -#endif + /* * */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 9efff50..eac896c 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_indata.h> #include <netinet/sctp_bsd_addr.h> #include <netinet/sctp_input.h> +#include <netinet/sctp_crc32.h> #include <netinet/udp.h> #include <machine/in_cksum.h> @@ -5213,6 +5214,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, int ecn_ok, struct sctp_tmit_chunk *chk, int out_of_asoc_ok, + uint16_t src_port, + uint16_t dest_port, + uint32_t v_tag, uint16_t port, int so_locked, #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) @@ -5237,7 +5241,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, struct mbuf *newm; struct sctphdr *sctphdr; int packet_length; - uint32_t csum; int ret; uint32_t vrf_id; sctp_route_t *ro = NULL; @@ -5263,51 +5266,27 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, if ((auth != NULL) && (stcb != NULL)) { sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid); } - /* Calculate the csum and fill in the length of the packet */ - sctphdr = mtod(m, struct sctphdr *); - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (to->sa_family == AF_INET) && - (stcb->asoc.loopback_scope)) { - sctphdr->checksum = 0; - /* - * This can probably now be taken out since my audit shows - * no more bad pktlen's coming in. But we will wait a while - * yet. - */ - packet_length = sctp_calculate_len(m); - } else { - sctphdr->checksum = 0; - csum = sctp_calculate_sum(m, &packet_length, 0); - sctphdr->checksum = csum; - } - if (to->sa_family == AF_INET) { struct ip *ip = NULL; sctp_route_t iproute; uint8_t tos_value; + int len; + len = sizeof(struct ip) + sizeof(struct sctphdr); if (port) { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA); + len += sizeof(struct udphdr); } + newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); if (newm == NULL) { sctp_m_freem(m); SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } - if (port) { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip) + sizeof(struct udphdr)); - SCTP_BUF_LEN(newm) = sizeof(struct ip) + sizeof(struct udphdr); - packet_length += sizeof(struct ip) + sizeof(struct udphdr); - } else { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip)); - SCTP_BUF_LEN(newm) = sizeof(struct ip); - packet_length += sizeof(struct ip); - } + SCTP_ALIGN_TO_END(newm, len); + SCTP_BUF_LEN(newm) = len; SCTP_BUF_NEXT(newm) = m; m = newm; + packet_length = sctp_calculate_len(m); ip = mtod(m, struct ip *); ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); @@ -5401,12 +5380,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } } if (port) { - udp = (struct udphdr *)(ip + 1); + udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip)); udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; udp->uh_ulen = htons(packet_length - sizeof(struct ip)); udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); + sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); + } else { + sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(struct ip)); } + + sctphdr->src_port = src_port; + sctphdr->dest_port = dest_port; + sctphdr->v_tag = v_tag; + sctphdr->checksum = 0; + /* * If source address selection fails and we find no route * then the ip_output should fail as well with a @@ -5517,7 +5505,25 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #endif SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } SCTP_ENABLE_UDP_CSUM(o_pak); + } else { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + m->m_pkthdr.csum_flags = CSUM_SCTP; + m->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } } /* send it out. table id is taken from stcb */ #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) @@ -5591,6 +5597,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, struct sockaddr_in6 lsa6_storage; int error; u_short prev_port = 0; + int len; if (net != NULL) { flowlabel = net->tos_flowlabel; @@ -5598,27 +5605,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; } + len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr); if (port) { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA); + len += sizeof(struct udphdr); } + newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); if (newm == NULL) { sctp_m_freem(m); SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } - if (port) { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr) + sizeof(struct udphdr); - packet_length += sizeof(struct ip6_hdr) + sizeof(struct udphdr); - } else { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr)); - SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr); - packet_length += sizeof(struct ip6_hdr); - } + SCTP_ALIGN_TO_END(newm, len); + SCTP_BUF_LEN(newm) = len; SCTP_BUF_NEXT(newm) = m; m = newm; + packet_length = sctp_calculate_len(m); ip6h = mtod(m, struct ip6_hdr *); /* @@ -5763,12 +5764,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, ip6h->ip6_src = lsa6->sin6_addr; if (port) { - udp = (struct udphdr *)(ip6h + 1); + udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; udp->uh_ulen = htons(packet_length - sizeof(struct ip6_hdr)); udp->uh_sum = 0; + sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); + } else { + sctphdr = (struct sctphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); } + + sctphdr->src_port = src_port; + sctphdr->dest_port = dest_port; + sctphdr->v_tag = v_tag; + sctphdr->checksum = 0; + /* * We set the hop limit now since there is a good chance * that our ro pointer is now filled @@ -5805,9 +5815,27 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #endif SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { udp->uh_sum = 0xffff; } + } else { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + m->m_pkthdr.csum_flags = CSUM_SCTP; + m->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } } /* send it out. table id is taken from stcb */ #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) @@ -5905,7 +5933,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked { struct mbuf *m, *m_at, *mp_last; struct sctp_nets *net; - struct sctp_init_msg *initm; + struct sctp_init_chunk *init; struct sctp_supported_addr_param *sup_addr; struct sctp_adaptation_layer_indication *ali; struct sctp_ecn_supported_param *ecn; @@ -5961,7 +5989,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n"); return; } - SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg); + SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk); /* * assume peer supports asconf in order to be able to queue local * address changes while an INIT is in flight and before the assoc @@ -5969,28 +5997,24 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked */ stcb->asoc.peer_supports_asconf = 1; /* Now lets put the SCTP header in place */ - initm = mtod(m, struct sctp_init_msg *); - initm->sh.src_port = inp->sctp_lport; - initm->sh.dest_port = stcb->rport; - initm->sh.v_tag = 0; - initm->sh.checksum = 0; /* calculate later */ + init = mtod(m, struct sctp_init_chunk *); /* now the chunk header */ - initm->msg.ch.chunk_type = SCTP_INITIATION; - initm->msg.ch.chunk_flags = 0; + init->ch.chunk_type = SCTP_INITIATION; + init->ch.chunk_flags = 0; /* fill in later from mbuf we build */ - initm->msg.ch.chunk_length = 0; + init->ch.chunk_length = 0; /* place in my tag */ - initm->msg.init.initiate_tag = htonl(stcb->asoc.my_vtag); + init->init.initiate_tag = htonl(stcb->asoc.my_vtag); /* set up some of the credits. */ - initm->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), + init->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND)); - initm->msg.init.num_outbound_streams = htons(stcb->asoc.pre_open_streams); - initm->msg.init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams); - initm->msg.init.initial_tsn = htonl(stcb->asoc.init_seq_number); + init->init.num_outbound_streams = htons(stcb->asoc.pre_open_streams); + init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams); + init->init.initial_tsn = htonl(stcb->asoc.init_seq_number); /* now the address restriction */ - sup_addr = (struct sctp_supported_addr_param *)((caddr_t)initm + - sizeof(*initm)); + sup_addr = (struct sctp_supported_addr_param *)((caddr_t)init + + sizeof(*init)); sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE); #ifdef INET6 /* we support 2 types: IPv6/IPv4 */ @@ -6004,7 +6028,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked sup_addr->addr_type[1] = htons(0); /* this is the padding */ #endif SCTP_BUF_LEN(m) += sizeof(*sup_addr) + sizeof(uint16_t); - /* adaptation layer indication parameter */ ali = (struct sctp_adaptation_layer_indication *)((caddr_t)sup_addr + sizeof(*sup_addr) + sizeof(uint16_t)); ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); @@ -6013,6 +6036,16 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTP_BUF_LEN(m) += sizeof(*ali); ecn = (struct sctp_ecn_supported_param *)((caddr_t)ali + sizeof(*ali)); + if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { + /* Add NAT friendly parameter */ + struct sctp_paramhdr *ph; + + ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); + ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); + ph->param_length = htons(sizeof(struct sctp_paramhdr)); + SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr); + ecn = (struct sctp_ecn_supported_param *)((caddr_t)ph + sizeof(*ph)); + } /* now any cookie time extensions */ if (stcb->asoc.cookie_preserve_req) { struct sctp_cookie_perserve_param *cookie_preserve; @@ -6052,19 +6085,22 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; - if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) + if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; + } /* * EY if the initiator supports nr_sacks, need to report that to * responder in INIT chunk */ - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; + } p_len = sizeof(*pr_supported) + num_ext; pr_supported->ph.param_length = htons(p_len); bzero((caddr_t)pr_supported + p_len, SCTP_SIZE32(p_len) - p_len); SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len); + /* ECN nonce: And now tell the peer we support ECN nonce */ if (SCTP_BASE_SYSCTL(sctp_ecn_nonce)) { ecn_nonce = (struct sctp_ecn_nonce_supported_param *) @@ -6073,15 +6109,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked ecn_nonce->ph.param_length = htons(sizeof(*ecn_nonce)); SCTP_BUF_LEN(m) += sizeof(*ecn_nonce); } - if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { - /* Add NAT friendly parameter */ - struct sctp_paramhdr *ph; - - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); - ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); - ph->param_length = htons(sizeof(struct sctp_paramhdr)); - SCTP_BUF_LEN(m) += sizeof(sizeof(struct sctp_paramhdr)); - } /* add authentication parameters */ if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { struct sctp_auth_random *randp; @@ -6160,7 +6187,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked mp_last = m_at; p_len += SCTP_BUF_LEN(m_at); } - initm->msg.ch.chunk_length = htons((p_len - sizeof(struct sctphdr))); + init->ch.chunk_length = htons(p_len); /* * We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return * here since the timer will drive a retranmission. @@ -6185,7 +6212,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n"); ret = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, - m, 0, NULL, 0, 0, 0, NULL, 0, net->port, so_locked, NULL); + m, 0, NULL, 0, 0, 0, NULL, 0, + inp->sctp_lport, stcb->rport, htonl(0), + net->port, so_locked, NULL); SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net); @@ -6711,7 +6740,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, { struct sctp_association *asoc; struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last; - struct sctp_init_msg *initackm_out; + struct sctp_init_ack_chunk *initack; struct sctp_adaptation_layer_indication *ali; struct sctp_ecn_supported_param *ecn; struct sctp_prsctp_supported_param *prsctp; @@ -6776,7 +6805,7 @@ do_a_abort: sctp_m_freem(op_err); return; } - SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg); + SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk); /* the time I built cookie */ (void)SCTP_GETTIME_TIMEVAL(&stc.time_entered); @@ -7059,29 +7088,25 @@ do_a_abort: } } /* Now lets put the SCTP header in place */ - initackm_out = mtod(m, struct sctp_init_msg *); - initackm_out->sh.src_port = inp->sctp_lport; - initackm_out->sh.dest_port = sh->src_port; - initackm_out->sh.v_tag = init_chk->init.initiate_tag; + initack = mtod(m, struct sctp_init_ack_chunk *); /* Save it off for quick ref */ stc.peers_vtag = init_chk->init.initiate_tag; - initackm_out->sh.checksum = 0; /* calculate later */ /* who are we */ memcpy(stc.identification, SCTP_VERSION_STRING, min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification))); /* now the chunk header */ - initackm_out->msg.ch.chunk_type = SCTP_INITIATION_ACK; - initackm_out->msg.ch.chunk_flags = 0; + initack->ch.chunk_type = SCTP_INITIATION_ACK; + initack->ch.chunk_flags = 0; /* fill in later from mbuf we build */ - initackm_out->msg.ch.chunk_length = 0; + initack->ch.chunk_length = 0; /* place in my tag */ if ((asoc != NULL) && ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(asoc) == SCTP_STATE_INUSE) || (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) { /* re-use the v-tags and init-seq here */ - initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); - initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number); + initack->init.initiate_tag = htonl(asoc->my_vtag); + initack->init.initial_tsn = htonl(asoc->init_seq_number); } else { uint32_t vtag, itsn; @@ -7101,17 +7126,17 @@ do_a_abort: */ goto new_tag; } - initackm_out->msg.init.initiate_tag = htonl(vtag); + initack->init.initiate_tag = htonl(vtag); /* get a TSN to use too */ itsn = sctp_select_initial_TSN(&inp->sctp_ep); - initackm_out->msg.init.initial_tsn = htonl(itsn); + initack->init.initial_tsn = htonl(itsn); SCTP_TCB_LOCK(stcb); atomic_add_int(&asoc->refcnt, -1); } else { vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); - initackm_out->msg.init.initiate_tag = htonl(vtag); + initack->init.initiate_tag = htonl(vtag); /* get a TSN to use too */ - initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); } if (hold_inp_lock) { SCTP_INP_RLOCK(inp); @@ -7119,7 +7144,7 @@ do_a_abort: } } /* save away my tag to */ - stc.my_vtag = initackm_out->msg.init.initiate_tag; + stc.my_vtag = initack->init.initiate_tag; /* set up some of the credits. */ so = inp->sctp_socket; @@ -7128,7 +7153,7 @@ do_a_abort: sctp_m_freem(m); return; } else { - initackm_out->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND)); + initack->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND)); } /* set what I want */ his_limit = ntohs(init_chk->init.num_inbound_streams); @@ -7144,17 +7169,17 @@ do_a_abort: } if (his_limit < i_want) { /* I Want more :< */ - initackm_out->msg.init.num_outbound_streams = init_chk->init.num_inbound_streams; + initack->init.num_outbound_streams = init_chk->init.num_inbound_streams; } else { /* I can have what I want :> */ - initackm_out->msg.init.num_outbound_streams = htons(i_want); + initack->init.num_outbound_streams = htons(i_want); } /* tell him his limt. */ - initackm_out->msg.init.num_inbound_streams = + initack->init.num_inbound_streams = htons(inp->sctp_ep.max_open_streams_intome); /* adaptation layer indication parameter */ - ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initackm_out + sizeof(*initackm_out)); + ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initack + sizeof(*initack)); ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); ali->ph.param_length = htons(sizeof(*ali)); ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator); @@ -7183,7 +7208,7 @@ do_a_abort: ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); ph->param_length = htons(sizeof(struct sctp_paramhdr)); - SCTP_BUF_LEN(m) += sizeof(sizeof(struct sctp_paramhdr)); + SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr); } /* And now tell the peer we do all the extensions */ pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); @@ -7317,8 +7342,7 @@ do_a_abort: } /* Now we must build a cookie */ - m_cookie = sctp_add_cookie(inp, init_pkt, offset, m, - sizeof(struct sctphdr), &stc, &signature); + m_cookie = sctp_add_cookie(inp, init_pkt, offset, m, 0, &stc, &signature); if (m_cookie == NULL) { /* memory problem */ sctp_m_freem(m); @@ -7339,7 +7363,7 @@ do_a_abort: * Place in the size, but we don't include the last pad (if any) in * the INIT-ACK. */ - initackm_out->msg.ch.chunk_length = htons((p_len - sizeof(struct sctphdr))); + initack->ch.chunk_length = htons(p_len); /* * Time to sign the cookie, we don't sign over the cookie signature @@ -7370,11 +7394,12 @@ do_a_abort: over_addr = &store1; } else { over_addr = NULL; - } (void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0, - 0, NULL, 0, port, SCTP_SO_NOT_LOCKED, over_addr); + 0, NULL, 0, + inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag, + port, SCTP_SO_NOT_LOCKED, over_addr); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } @@ -9164,7 +9189,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, struct sctp_nets *net; struct mbuf *outchain, *endoutchain; struct sctp_tmit_chunk *chk, *nchk; - struct sctphdr *shdr; /* temp arrays for unlinking */ struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; @@ -9177,7 +9201,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, int tsns_sent = 0; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; - uint16_t auth_keyid = 0; + uint16_t auth_keyid; + int override_ok = 1; int data_auth_reqd = 0; /* @@ -9189,6 +9214,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, *num_out = 0; cwnd_full_ind = 0; + auth_keyid = stcb->asoc.authinfo.active_keyid; if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) || @@ -9532,24 +9558,14 @@ again_one_more_time: * it is used to do appropriate * source address selection. */ - SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); - if (outchain == NULL) { - /* no memory */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - error = ENOBUFS; - *reason_code = 7; - continue; - } - shdr = mtod(outchain, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, - outchain, auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) { + outchain, auth_offset, auth, + stcb->asoc.authinfo.active_keyid, + no_fragmentflg, 0, NULL, asconf, + inp->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; SCTP_STAT_INCR(sctps_lowlevelerr); @@ -9773,24 +9789,15 @@ again_one_more_time: sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); cookie = 0; } - SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); - if (outchain == NULL) { - /* no memory */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - error = ENOBUFS; - goto error_out_again; - } - shdr = mtod(outchain, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, outchain, - auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) { + auth_offset, auth, + stcb->asoc.authinfo.active_keyid, + no_fragmentflg, 0, NULL, asconf, + inp->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; SCTP_STAT_INCR(sctps_lowlevelerr); @@ -9798,7 +9805,6 @@ again_one_more_time: if (from_where == 0) { SCTP_STAT_INCR(sctps_lowlevelerrusr); } - error_out_again: /* error, could not output */ if (hbflag) { if (*now_filled == 0) { @@ -9948,8 +9954,16 @@ again_one_more_time: &auth_offset, stcb, SCTP_DATA); + auth_keyid = chk->auth_keyid; + override_ok = 0; SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + } else if (override_ok) { + /* + * use this data's + * keyid + */ auth_keyid = chk->auth_keyid; + override_ok = 0; } else if (auth_keyid != chk->auth_keyid) { /* * different keyid, @@ -10072,25 +10086,6 @@ again_one_more_time: sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } /* Now send it, if there is anything to send :> */ - SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); - if (outchain == NULL) { - /* out of mbufs */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - error = ENOBUFS; - goto errored_send; - } - shdr = mtod(outchain, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); - /* - * if data auth isn't needed, use the assoc active - * key - */ - if (!data_auth_reqd) - auth_keyid = stcb->asoc.authinfo.active_keyid; if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, @@ -10102,7 +10097,10 @@ again_one_more_time: no_fragmentflg, bundle_at, data_list[0], - asconf, net->port, so_locked, NULL))) { + asconf, + inp->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { /* error, we could not output */ if (error == ENOBUFS) { SCTP_STAT_INCR(sctps_lowlevelerr); @@ -10111,7 +10109,6 @@ again_one_more_time: if (from_where == 0) { SCTP_STAT_INCR(sctps_lowlevelerrusr); } - errored_send: SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (hbflag) { if (*now_filled == 0) { @@ -10727,7 +10724,6 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; struct sctp_tmit_chunk *chk, *fwd; struct mbuf *m, *endofchain; - struct sctphdr *shdr; struct sctp_nets *net = NULL; uint32_t tsns_sent = 0; int no_fragmentflg, bundle_at, cnt_thru; @@ -10735,7 +10731,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, int error, i, one_chunk, fwd_tsn, ctl_cnt, tmr_started; struct sctp_auth_chunk *auth = NULL; uint32_t auth_offset = 0; - uint16_t auth_keyid = 0; + uint16_t auth_keyid; + int override_ok = 1; int data_auth_reqd = 0; uint32_t dmtu = 0; @@ -10746,6 +10743,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, *cnt_out = 0; fwd = NULL; endofchain = m = NULL; + auth_keyid = stcb->asoc.authinfo.active_keyid; #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xC3, 1); #endif @@ -10803,24 +10801,13 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo); } else if (chk->rec.chunk_id.id == SCTP_ASCONF) sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo); - - SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT); - if (m == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - return (ENOBUFS); - } - shdr = mtod(m, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); chk->snd_count++; /* update our count */ - if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo, (struct sockaddr *)&chk->whoTo->ro._l_addr, m, auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked, NULL))) { + no_fragmentflg, 0, NULL, 0, + inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), + chk->whoTo->port, so_locked, NULL))) { SCTP_STAT_INCR(sctps_lowlevelerr); return (error); } @@ -10954,8 +10941,12 @@ one_chunk_around: &auth_offset, stcb, SCTP_DATA); + auth_keyid = chk->auth_keyid; + override_ok = 0; SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + } else if (override_ok) { auth_keyid = chk->auth_keyid; + override_ok = 0; } else if (chk->auth_keyid != auth_keyid) { /* different keyid, so done bundling */ break; @@ -11010,8 +11001,12 @@ one_chunk_around: &auth_offset, stcb, SCTP_DATA); + auth_keyid = fwd->auth_keyid; + override_ok = 0; SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + } else if (override_ok) { auth_keyid = fwd->auth_keyid; + override_ok = 0; } else if (fwd->auth_keyid != auth_keyid) { /* * different keyid, @@ -11059,28 +11054,13 @@ one_chunk_around: sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); tmr_started = 1; } - SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT); - if (m == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - return (ENOBUFS); - } - shdr = mtod(m, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); - /* - * if doing DATA auth, use the data chunk(s) key id, - * otherwise use the assoc's active key id - */ - if (!data_auth_reqd) - auth_keyid = stcb->asoc.authinfo.active_keyid; /* Now lets send it, if there is anything to send :> */ if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, m, auth_offset, auth, auth_keyid, - no_fragmentflg, 0, NULL, 0, net->port, so_locked, NULL))) { + no_fragmentflg, 0, NULL, 0, + inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { /* error, we could not output */ SCTP_STAT_INCR(sctps_lowlevelerr); return (error); @@ -12401,7 +12381,6 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked int sz; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; - struct sctphdr *shdr; /*- * Add an AUTH chunk, if chunk requires it and save the offset into @@ -12449,23 +12428,12 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked abort->ch.chunk_flags = 0; abort->ch.chunk_length = htons(sizeof(*abort) + sz); - /* prepend and fill in the SCTP header */ - SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT); - if (m_out == NULL) { - /* TSNH: no memory */ - return; - } - shdr = mtod(m_out, struct sctphdr *); - shdr->src_port = stcb->sctp_ep->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); - (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, stcb->asoc.primary_destination, (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr, - m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked, NULL); + m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, + stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), + stcb->asoc.primary_destination->port, so_locked, NULL); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } @@ -12475,26 +12443,24 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb, { /* formulate and SEND a SHUTDOWN-COMPLETE */ struct mbuf *m_shutdown_comp; - struct sctp_shutdown_complete_msg *comp_cp; + struct sctp_shutdown_complete_chunk *shutdown_complete; - m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_complete_msg), 0, M_DONTWAIT, 1, MT_HEADER); + m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_DONTWAIT, 1, MT_HEADER); if (m_shutdown_comp == NULL) { /* no mbuf's */ return; } - comp_cp = mtod(m_shutdown_comp, struct sctp_shutdown_complete_msg *); - comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; - comp_cp->shut_cmp.ch.chunk_flags = 0; - comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); - comp_cp->sh.src_port = stcb->sctp_ep->sctp_lport; - comp_cp->sh.dest_port = stcb->rport; - comp_cp->sh.v_tag = htonl(stcb->asoc.peer_vtag); - comp_cp->sh.checksum = 0; - - SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg); + shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *); + shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; + shutdown_complete->ch.chunk_flags = 0; + shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); + SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk); (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, (struct sockaddr *)&net->ro._l_addr, - m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED, NULL); + m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0, + stcb->sctp_ep->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, SCTP_SO_NOT_LOCKED, NULL); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); return; } @@ -12532,10 +12498,11 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (port) { len += sizeof(struct udphdr); } - mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); + mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA); if (mout == NULL) { return; } + SCTP_BUF_RESV_UF(mout, max_linkhdr); SCTP_BUF_LEN(mout) = len; SCTP_BUF_NEXT(mout) = NULL; iph_out = NULL; @@ -12596,6 +12563,7 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, #endif /* INET6 */ default: /* Currently not supported. */ + sctp_m_freem(mout); return; } if (port) { @@ -12621,8 +12589,6 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); - /* add checksum */ - comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out); if (iph_out != NULL) { sctp_route_t ro; int ret; @@ -12636,10 +12602,16 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) sctp_packet_log(mout, mlen); #endif - SCTP_ATTACH_CHAIN(o_pak, mout, mlen); if (port) { - SCTP_ENABLE_UDP_CSUM(o_pak); + comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out); + SCTP_STAT_INCR(sctps_sendswcrc); + SCTP_ENABLE_UDP_CSUM(mout); + } else { + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); } + SCTP_ATTACH_CHAIN(o_pak, mout, mlen); /* out it goes */ SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); @@ -12660,6 +12632,8 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) sctp_packet_log(mout, mlen); #endif + comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out); + SCTP_STAT_INCR(sctps_sendswcrc); SCTP_ATTACH_CHAIN(o_pak, mout, mlen); if (port) { if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), @@ -13493,17 +13467,22 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, break; #endif default: + if (err_cause) { + sctp_m_freem(err_cause); + } return; } if (port) { len += sizeof(struct udphdr); } - mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); + mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA); if (mout == NULL) { - if (err_cause) + if (err_cause) { sctp_m_freem(err_cause); + } return; } + SCTP_BUF_RESV_UF(mout, max_linkhdr); SCTP_BUF_LEN(mout) = len; SCTP_BUF_NEXT(mout) = err_cause; iph_out = NULL; @@ -13556,8 +13535,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif /* INET6 */ default: /* Currently not supported */ - if (err_cause) - sctp_m_freem(err_cause); sctp_m_freem(mout); return; } @@ -13608,8 +13585,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch)); } - /* add checksum */ - abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out); if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { /* no mbuf's */ sctp_m_freem(mout); @@ -13637,7 +13612,13 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { + abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); SCTP_ENABLE_UDP_CSUM(o_pak); + } else { + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); } SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); @@ -13664,6 +13645,8 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) sctp_packet_log(mout, len); #endif + abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { @@ -13679,6 +13662,7 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif SCTP_STAT_INCR(sctps_sendpackets); SCTP_STAT_INCR_COUNTER64(sctps_outpackets); + SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } void @@ -13686,211 +13670,219 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, uint32_t vrf_id, uint16_t port) { struct mbuf *o_pak; - struct sctphdr *ihdr; - int retcode; - struct sctphdr *ohdr; - struct sctp_chunkhdr *ophdr; - struct ip *iph; + struct sctphdr *sh, *sh_out; + struct sctp_chunkhdr *ch; + struct ip *iph, *iph_out; struct udphdr *udp = NULL; struct mbuf *mout; #ifdef INET6 -#ifdef SCTP_DEBUG - struct sockaddr_in6 lsa6, fsa6; + struct ip6_hdr *ip6, *ip6_out; #endif -#endif - uint32_t val; - struct mbuf *at; - int len; + int iphlen_out, len; iph = mtod(m, struct ip *); - ihdr = (struct sctphdr *)((caddr_t)iph + iphlen); - - SCTP_BUF_PREPEND(scm, (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)), M_DONTWAIT); - if (scm == NULL) { - /* can't send because we can't add a mbuf */ + sh = (struct sctphdr *)((caddr_t)iph + iphlen); + switch (iph->ip_v) { + case IPVERSION: + len = (sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + len = (sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)); + break; +#endif + default: + if (scm) { + sctp_m_freem(scm); + } return; } - ohdr = mtod(scm, struct sctphdr *); - ohdr->src_port = ihdr->dest_port; - ohdr->dest_port = ihdr->src_port; - ohdr->v_tag = vtag; - ohdr->checksum = 0; - ophdr = (struct sctp_chunkhdr *)(ohdr + 1); - ophdr->chunk_type = SCTP_OPERATION_ERROR; - ophdr->chunk_flags = 0; - len = 0; - at = scm; - while (at) { - len += SCTP_BUF_LEN(at); - at = SCTP_BUF_NEXT(at); + if (port) { + len += sizeof(struct udphdr); } - ophdr->chunk_length = htons(len - sizeof(struct sctphdr)); - if (len % 4) { - /* need padding */ - uint32_t cpthis = 0; - int padlen; - - padlen = 4 - (len % 4); - m_copyback(scm, len, padlen, (caddr_t)&cpthis); - len += padlen; + mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA); + if (mout == NULL) { + if (scm) { + sctp_m_freem(scm); + } + return; } - val = sctp_calculate_sum(scm, NULL, 0); + SCTP_BUF_RESV_UF(mout, max_linkhdr); + SCTP_BUF_LEN(mout) = len; + SCTP_BUF_NEXT(mout) = scm; + iph_out = NULL; #ifdef INET6 - if (port) { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA); + ip6_out = NULL; +#endif + switch (iph->ip_v) { + case IPVERSION: + iph_out = mtod(mout, struct ip *); + + /* Fill in the IP header for the ABORT */ + iph_out->ip_v = IPVERSION; + iph_out->ip_hl = (sizeof(struct ip) / 4); + iph_out->ip_tos = (u_char)0; + iph_out->ip_id = 0; + iph_out->ip_off = 0; + iph_out->ip_ttl = MAXTTL; + if (port) { + iph_out->ip_p = IPPROTO_UDP; + } else { + iph_out->ip_p = IPPROTO_SCTP; + } + iph_out->ip_src.s_addr = iph->ip_dst.s_addr; + iph_out->ip_dst.s_addr = iph->ip_src.s_addr; + /* let IP layer calculate this */ + iph_out->ip_sum = 0; + + iphlen_out = sizeof(struct ip); + sh_out = (struct sctphdr *)((caddr_t)iph_out + iphlen_out); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + ip6 = (struct ip6_hdr *)iph; + ip6_out = mtod(mout, struct ip6_hdr *); + + /* Fill in the IP6 header for the ABORT */ + ip6_out->ip6_flow = ip6->ip6_flow; + ip6_out->ip6_hlim = MODULE_GLOBAL(MOD_INET6, ip6_defhlim); + if (port) { + ip6_out->ip6_nxt = IPPROTO_UDP; + } else { + ip6_out->ip6_nxt = IPPROTO_SCTP; + } + ip6_out->ip6_src = ip6->ip6_dst; + ip6_out->ip6_dst = ip6->ip6_src; + + iphlen_out = sizeof(struct ip6_hdr); + sh_out = (struct sctphdr *)((caddr_t)ip6_out + iphlen_out); + break; +#endif /* INET6 */ + default: + /* Currently not supported */ + sctp_m_freem(mout); + return; } -#else + + udp = (struct udphdr *)sh_out; if (port) { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA); + udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); + udp->uh_dport = port; + /* set udp->uh_ulen later */ + udp->uh_sum = 0; + iphlen_out += sizeof(struct udphdr); + sh_out = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); } -#endif - if (mout == NULL) { - sctp_m_freem(scm); - return; + sh_out->src_port = sh->dest_port; + sh_out->dest_port = sh->src_port; + sh_out->v_tag = vtag; + sh_out->checksum = 0; + + ch = (struct sctp_chunkhdr *)((caddr_t)sh_out + sizeof(struct sctphdr)); + ch->chunk_type = SCTP_OPERATION_ERROR; + ch->chunk_flags = 0; + + if (scm) { + struct mbuf *m_tmp = scm; + int cause_len = 0; + + /* get length of the err_cause chain */ + while (m_tmp != NULL) { + cause_len += SCTP_BUF_LEN(m_tmp); + m_tmp = SCTP_BUF_NEXT(m_tmp); + } + len = SCTP_BUF_LEN(mout) + cause_len; + if (cause_len % 4) { + /* need pad at end of chunk */ + uint32_t cpthis = 0; + int padlen; + + padlen = 4 - (len % 4); + m_copyback(mout, len, padlen, (caddr_t)&cpthis); + len += padlen; + } + ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len); + } else { + len = SCTP_BUF_LEN(mout); + ch->chunk_length = htons(sizeof(struct sctp_chunkhdr)); } - SCTP_BUF_NEXT(mout) = scm; + if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { + /* no mbuf's */ sctp_m_freem(mout); return; } - ohdr->checksum = val; - switch (iph->ip_v) { - case IPVERSION: - { - /* V4 */ - struct ip *out; - sctp_route_t ro; - struct sctp_tcb *stcb = NULL; - - SCTP_BUF_LEN(mout) = sizeof(struct ip); - len += sizeof(struct ip); - if (port) { - SCTP_BUF_LEN(mout) += sizeof(struct udphdr); - len += sizeof(struct udphdr); - } - bzero(&ro, sizeof ro); - out = mtod(mout, struct ip *); - out->ip_v = iph->ip_v; - out->ip_hl = (sizeof(struct ip) / 4); - out->ip_tos = iph->ip_tos; - out->ip_id = iph->ip_id; - out->ip_off = 0; - out->ip_ttl = MAXTTL; - if (port) { - out->ip_p = IPPROTO_UDP; - } else { - out->ip_p = IPPROTO_SCTP; - } - out->ip_sum = 0; - out->ip_src = iph->ip_dst; - out->ip_dst = iph->ip_src; - out->ip_len = len; - if (port) { - udp = (struct udphdr *)(out + 1); - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_ulen = htons(len - sizeof(struct ip)); - udp->uh_sum = in_pseudo(out->ip_src.s_addr, out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); - } + if (iph_out != NULL) { + sctp_route_t ro; + struct sctp_tcb *stcb = NULL; + int ret; + + /* zap the stack pointer to the route */ + bzero(&ro, sizeof ro); + if (port) { + udp->uh_ulen = htons(len - sizeof(struct ip)); + udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); + } + /* set IPv4 length */ + iph_out->ip_len = len; + /* out it goes */ #ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) - sctp_packet_log(mout, len); + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) + sctp_packet_log(mout, len); #endif - SCTP_ATTACH_CHAIN(o_pak, mout, len); - if (port) { - SCTP_ENABLE_UDP_CSUM(o_pak); - } - SCTP_IP_OUTPUT(retcode, o_pak, &ro, stcb, vrf_id); - - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - /* Free the route if we got one back */ - if (ro.ro_rt) - RTFREE(ro.ro_rt); - break; + SCTP_ATTACH_CHAIN(o_pak, mout, len); + if (port) { + sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); + SCTP_ENABLE_UDP_CSUM(o_pak); + } else { + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); } + SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); + + /* Free the route if we got one back */ + if (ro.ro_rt) + RTFREE(ro.ro_rt); + } #ifdef INET6 - case IPV6_VERSION >> 4: - { - /* V6 */ - struct route_in6 ro; - int ret; - struct sctp_tcb *stcb = NULL; - struct ifnet *ifp = NULL; - struct ip6_hdr *out6, *in6; - - SCTP_BUF_LEN(mout) = sizeof(struct ip6_hdr); - len += sizeof(struct ip6_hdr); - bzero(&ro, sizeof ro); - if (port) { - SCTP_BUF_LEN(mout) += sizeof(struct udphdr); - len += sizeof(struct udphdr); - } - in6 = mtod(m, struct ip6_hdr *); - out6 = mtod(mout, struct ip6_hdr *); - out6->ip6_flow = in6->ip6_flow; - out6->ip6_hlim = MODULE_GLOBAL(MOD_INET6, ip6_defhlim); - if (port) { - out6->ip6_nxt = IPPROTO_UDP; - } else { - out6->ip6_nxt = IPPROTO_SCTP; - } - out6->ip6_src = in6->ip6_dst; - out6->ip6_dst = in6->ip6_src; - out6->ip6_plen = len - sizeof(struct ip6_hdr); - if (port) { - udp = (struct udphdr *)(out6 + 1); - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_ulen = htons(len - sizeof(struct ip6_hdr)); - udp->uh_sum = 0; - } -#ifdef SCTP_DEBUG - bzero(&lsa6, sizeof(lsa6)); - lsa6.sin6_len = sizeof(lsa6); - lsa6.sin6_family = AF_INET6; - lsa6.sin6_addr = out6->ip6_src; - bzero(&fsa6, sizeof(fsa6)); - fsa6.sin6_len = sizeof(fsa6); - fsa6.sin6_family = AF_INET6; - fsa6.sin6_addr = out6->ip6_dst; -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT2, "sctp_operr_to calling ipv6 output:\n"); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "src: "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&lsa6); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "dst "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&fsa6); + if (ip6_out != NULL) { + struct route_in6 ro; + int ret; + struct sctp_tcb *stcb = NULL; + struct ifnet *ifp = NULL; + /* zap the stack pointer to the route */ + bzero(&ro, sizeof(ro)); + if (port) { + udp->uh_ulen = htons(len - sizeof(struct ip6_hdr)); + } + ip6_out->ip6_plen = len - sizeof(*ip6_out); #ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) - sctp_packet_log(mout, len); + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) + sctp_packet_log(mout, len); #endif - SCTP_ATTACH_CHAIN(o_pak, mout, len); - if (port) { - if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { - udp->uh_sum = 0xffff; - } + sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); + SCTP_ATTACH_CHAIN(o_pak, mout, len); + if (port) { + if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { + udp->uh_sum = 0xffff; } - SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); - - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - /* Free the route if we got one back */ - if (ro.ro_rt) - RTFREE(ro.ro_rt); - break; } -#endif /* INET6 */ - default: - /* TSNH */ - break; + SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); + + /* Free the route if we got one back */ + if (ro.ro_rt) + RTFREE(ro.ro_rt); } +#endif + SCTP_STAT_INCR(sctps_sendpackets); + SCTP_STAT_INCR_COUNTER64(sctps_outpackets); + SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } static struct mbuf * diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 5f05dcd..291509e 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2504,7 +2504,9 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, /* Pull the tcb from the old association */ LIST_REMOVE(stcb, sctp_tcbhash); LIST_REMOVE(stcb, sctp_tcblist); - + if (stcb->asoc.in_asocid_hash) { + LIST_REMOVE(stcb, sctp_tcbasocidhash); + } /* Now insert the new_inp into the TCP connected hash */ head = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR((lport), SCTP_BASE_INFO(hashtcpmark))]; @@ -2520,7 +2522,13 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, * only have one connection? Probably not :> so lets get rid of it * and not suck up any kernel memory in that. */ + if (stcb->asoc.in_asocid_hash) { + struct sctpasochead *lhd; + lhd = &new_inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(stcb->asoc.assoc_id, + new_inp->hashasocidmark)]; + LIST_INSERT_HEAD(lhd, stcb, sctp_tcbasocidhash); + } /* Ok. Let's restart timer. */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, new_inp, @@ -4652,7 +4660,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } /* pull from vtag hash */ LIST_REMOVE(stcb, sctp_asocs); - sctp_add_vtag_to_timewait(asoc->my_vtag, inp->sctp_lport, stcb->rport, SCTP_TIME_WAIT); + sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_TIME_WAIT, inp->sctp_lport, stcb->rport); /* * Now restop the timers to be sure - this is paranoia at is finest! @@ -4763,7 +4771,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from send_queue\n", ccnt); ccnt = 0; } @@ -4788,7 +4796,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from sent_queue\n", ccnt); ccnt = 0; } @@ -4813,7 +4821,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from ctrl_queue\n", ccnt); ccnt = 0; } @@ -4839,7 +4847,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from asconf_queue\n", ccnt); ccnt = 0; } @@ -4863,7 +4871,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from reasm_queue\n", ccnt); ccnt = 0; } @@ -5776,7 +5784,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* ok get the v4 address and check/add */ phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf)); + (struct sctp_paramhdr *)&p4_buf, + sizeof(p4_buf)); if (plen != sizeof(struct sctp_ipv4addr_param) || phdr == NULL) { return (-5); @@ -5858,7 +5867,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, struct sctp_ipv6addr_param *p6, p6_buf; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf)); + (struct sctp_paramhdr *)&p6_buf, + sizeof(p6_buf)); if (plen != sizeof(struct sctp_ipv6addr_param) || phdr == NULL) { return (-14); @@ -5883,8 +5893,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, local_sa, stcb); atomic_add_int(&stcb->asoc.refcnt, -1); - if (stcb_tmp == NULL && (inp == stcb->sctp_ep || - inp == NULL)) { + if (stcb_tmp == NULL && + (inp == stcb->sctp_ep || inp == NULL)) { /* * we must validate the state again * here @@ -5965,7 +5975,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, return (-23); } phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&lstore, min(plen, sizeof(lstore))); + (struct sctp_paramhdr *)&lstore, + min(plen, sizeof(lstore))); if (phdr == NULL) { return (-24); } @@ -6154,6 +6165,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, break; } } + next_param: offset += SCTP_SIZE32(plen); if (offset >= limit) { @@ -6206,8 +6218,10 @@ next_param: bcopy(p_random->random_data, new_key->key, random_len); } #else - keylen = sizeof(*p_random) + random_len + sizeof(*chunks) + num_chunks + - sizeof(*hmacs) + hmacs_len; + keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; + if (chunks != NULL) { + keylen += sizeof(*chunks) + num_chunks; + } new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ @@ -6343,6 +6357,8 @@ skip_vtag_check: /* Audit expires this guy */ twait_block->vtag_block[i].tv_sec_at_expire = 0; twait_block->vtag_block[i].v_tag = 0; + twait_block->vtag_block[i].lport = 0; + twait_block->vtag_block[i].rport = 0; } else if ((twait_block->vtag_block[i].v_tag == tag) && (twait_block->vtag_block[i].lport == lport) && (twait_block->vtag_block[i].rport == rport)) { diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 66c5f7b..684ed5a 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -144,6 +144,7 @@ struct sctp_tagblock { struct sctp_epinfo { + struct socket *udp_tun_socket; struct sctpasochead *sctp_asochash; u_long hashasocmark; diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 6703daf..bcba5b5 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -120,6 +120,7 @@ sctp_init_sysctls() #endif } + /* It returns an upper limit. No filtering is done here */ static unsigned int number_of_addresses(struct sctp_inpcb *inp) @@ -408,6 +409,8 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xstcb.primary_addr = stcb->asoc.primary_destination->ro._l_addr; xstcb.heartbeat_interval = stcb->asoc.heart_beat_delay; xstcb.state = SCTP_GET_STATE(&stcb->asoc); /* FIXME */ + /* 7.0 does not support this */ + xstcb.assoc_id = sctp_get_associd(stcb); xstcb.in_streams = stcb->asoc.streamincnt; xstcb.out_streams = stcb->asoc.streamoutcnt; xstcb.max_nr_retrans = stcb->asoc.overall_error_count; @@ -506,7 +509,6 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) } - #define RANGECHK(var, min, max) \ if ((var) < (min)) { (var) = (min); } \ else if ((var) > (max)) { (var) = (max); } @@ -517,10 +519,17 @@ sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS) int error; uint32_t old_sctp_udp_tunneling_port; + SCTP_INP_INFO_RLOCK(); old_sctp_udp_tunneling_port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); + SCTP_INP_INFO_RUNLOCK(); error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (error == 0) { RANGECHK(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port), SCTPCTL_UDP_TUNNELING_PORT_MIN, SCTPCTL_UDP_TUNNELING_PORT_MAX); + if (old_sctp_udp_tunneling_port == SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) { + error = 0; + goto out; + } + SCTP_INP_INFO_WLOCK(); if (old_sctp_udp_tunneling_port) { sctp_over_udp_stop(); } @@ -529,7 +538,9 @@ sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS) SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = 0; } } + SCTP_INP_INFO_WUNLOCK(); } +out: return (error); } @@ -624,14 +635,15 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) static int sysctl_sctp_cleartrace(SYSCTL_HANDLER_ARGS) { + int error = 0; + memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); - return (0); + return (error); } #endif - /* * sysctl definitions */ diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 46e604f..27597ba 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -804,6 +804,10 @@ struct sctpstat { uint32_t sctps_recvexpress; /* total fast path receives all one * chunk */ uint32_t sctps_recvexpressm; /* total fast path multi-part data */ + uint32_t sctps_recvnocrc; + uint32_t sctps_recvswcrc; + uint32_t sctps_recvhwcrc; + /* output statistics: */ uint32_t sctps_sendpackets; /* total output packets */ uint32_t sctps_sendsacks; /* total output SACKs */ @@ -820,6 +824,9 @@ struct sctpstat { uint32_t sctps_sendecne;/* total output ECNE chunks */ uint32_t sctps_sendauth;/* total output AUTH chunks FIXME */ uint32_t sctps_senderrors; /* ip_output error counter */ + uint32_t sctps_sendnocrc; + uint32_t sctps_sendswcrc; + uint32_t sctps_sendhwcrc; /* PCKDROPREP statistics: */ uint32_t sctps_pdrpfmbox; /* Packet drop from middle box */ uint32_t sctps_pdrpfehos; /* P-drop from end host */ @@ -1009,6 +1016,7 @@ struct xsctp_tcb { uint16_t remote_port; /* sctpAssocEntry 4 */ struct sctp_timeval start_time; /* sctpAssocEntry 16 */ struct sctp_timeval discontinuity_time; /* sctpAssocEntry 17 */ + sctp_assoc_t assoc_id; /* sctpAssocEntry 1 */ }; struct xsctp_laddr { diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index c642762..9d04f56 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -908,6 +908,7 @@ sctp_disconnect(struct socket *so) sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); } } + soisdisconnecting(so); SCTP_TCB_UNLOCK(stcb); SCTP_INP_RUNLOCK(inp); return (0); @@ -980,6 +981,11 @@ sctp_shutdown(struct socket *so) struct sctp_tcb *stcb; struct sctp_association *asoc; + if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SCTP_INP_RUNLOCK(inp); + return (ENOTCONN); + } socantsendmore(so); stcb = LIST_FIRST(&inp->sctp_asoc_list); @@ -3515,6 +3521,22 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (events->sctp_sender_dry_event) { sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + stcb = LIST_FIRST(&inp->sctp_asoc_list); + if (stcb) { + SCTP_TCB_LOCK(stcb); + } + if (stcb && + TAILQ_EMPTY(&stcb->asoc.send_queue) && + TAILQ_EMPTY(&stcb->asoc.sent_queue) && + (stcb->asoc.stream_queue_cnt == 0)) { + sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); + } + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } + } } else { sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index ce06853..ac13717 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_output.h> #include <netinet/sctp_uio.h> #include <netinet/sctp_timer.h> -#include <netinet/sctp_crc32.h> #include <netinet/sctp_indata.h>/* for sctp_deliver_data() */ #include <netinet/sctp_auth.h> #include <netinet/sctp_asconf.h> @@ -53,9 +52,15 @@ __FBSDID("$FreeBSD$"); #define NUMBER_OF_MTU_SIZES 18 +#if defined(__Windows__) && !defined(SCTP_LOCAL_TRACE_BUF) +#include "eventrace_netinet.h" +#include "sctputil.tmh" /* this is the file that will be auto + * generated */ +#else #ifndef KTR_SCTP #define KTR_SCTP KTR_SUBSYS #endif +#endif void sctp_sblog(struct sockbuf *sb, @@ -2458,48 +2463,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; } -#ifdef SCTP_USE_ADLER32 -static uint32_t -update_adler32(uint32_t adler, uint8_t * buf, int32_t len) -{ - uint32_t s1 = adler & 0xffff; - uint32_t s2 = (adler >> 16) & 0xffff; - int n; - - for (n = 0; n < len; n++, buf++) { - /* s1 = (s1 + buf[n]) % BASE */ - /* first we add */ - s1 = (s1 + *buf); - /* - * now if we need to, we do a mod by subtracting. It seems a - * bit faster since I really will only ever do one subtract - * at the MOST, since buf[n] is a max of 255. - */ - if (s1 >= SCTP_ADLER32_BASE) { - s1 -= SCTP_ADLER32_BASE; - } - /* s2 = (s2 + s1) % BASE */ - /* first we add */ - s2 = (s2 + s1); - /* - * again, it is more efficent (it seems) to subtract since - * the most s2 will ever be is (BASE-1 + BASE-1) in the - * worse case. This would then be (2 * BASE) - 2, which will - * still only do one subtract. On Intel this is much better - * to do this way and avoid the divide. Have not -pg'd on - * sparc. - */ - if (s2 >= SCTP_ADLER32_BASE) { - s2 -= SCTP_ADLER32_BASE; - } - } - /* Return the adler32 of the bytes buf[0..len-1] */ - return ((s2 << 16) + s1); -} - -#endif - - uint32_t sctp_calculate_len(struct mbuf *m) { @@ -2514,132 +2477,6 @@ sctp_calculate_len(struct mbuf *m) return (tlen); } -#if defined(SCTP_WITH_NO_CSUM) - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - if (pktlen == NULL) - return (0); - *pktlen = sctp_calculate_len(m); - return (0); -} - -#elif defined(SCTP_USE_INCHKSUM) - -#include <machine/in_cksum.h> - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - int32_t tlen = 0; - struct mbuf *at; - uint32_t the_sum, retsum; - - at = m; - while (at) { - tlen += SCTP_BUF_LEN(at); - at = SCTP_BUF_NEXT(at); - } - the_sum = (uint32_t) (in_cksum_skip(m, tlen, offset)); - if (pktlen != NULL) - *pktlen = (tlen - offset); - retsum = htons(the_sum); - return (the_sum); -} - -#else - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - int32_t tlen = 0; - -#ifdef SCTP_USE_ADLER32 - uint32_t base = 1L; - -#else - uint32_t base = 0xffffffff; - -#endif - struct mbuf *at; - - at = m; - /* find the correct mbuf and offset into mbuf */ - while ((at != NULL) && (offset > (uint32_t) SCTP_BUF_LEN(at))) { - offset -= SCTP_BUF_LEN(at); /* update remaining offset - * left */ - at = SCTP_BUF_NEXT(at); - } - while (at != NULL) { - if ((SCTP_BUF_LEN(at) - offset) > 0) { -#ifdef SCTP_USE_ADLER32 - base = update_adler32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); -#else - if ((SCTP_BUF_LEN(at) - offset) < 4) { - /* Use old method if less than 4 bytes */ - base = old_update_crc32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } else { - base = update_crc32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } -#endif - tlen += SCTP_BUF_LEN(at) - offset; - /* we only offset once into the first mbuf */ - } - if (offset) { - if (offset < (uint32_t) SCTP_BUF_LEN(at)) - offset = 0; - else - offset -= SCTP_BUF_LEN(at); - } - at = SCTP_BUF_NEXT(at); - } - if (pktlen != NULL) { - *pktlen = tlen; - } -#ifdef SCTP_USE_ADLER32 - /* Adler32 */ - base = htonl(base); -#else - /* CRC-32c */ - base = sctp_csum_finalize(base); -#endif - return (base); -} - - -#endif - void sctp_mtu_size_reset(struct sctp_inpcb *inp, struct sctp_association *asoc, uint32_t mtu) @@ -3428,7 +3265,6 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb) } #endif socantsendmore(stcb->sctp_socket); - socantrcvmore(stcb->sctp_socket); #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -3596,6 +3432,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, /* If the socket is gone we are out of here */ return; } + if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { + return; + } if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) { if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || @@ -6708,14 +6547,163 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_ * so we can do UDP tunneling. In * the mean-time, we return error */ +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <sys/proc.h> +#include <netinet6/sctp6_var.h> + +static void +sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored) +{ + struct ip *iph; + struct mbuf *sp, *last; + struct udphdr *uhdr; + uint16_t port = 0, len; + int header_size = sizeof(struct udphdr) + sizeof(struct sctphdr); + + /* + * Split out the mbuf chain. Leave the IP header in m, place the + * rest in the sp. + */ + if ((m->m_flags & M_PKTHDR) == 0) { + /* Can't handle one that is not a pkt hdr */ + goto out; + } + /* pull the src port */ + iph = mtod(m, struct ip *); + uhdr = (struct udphdr *)((caddr_t)iph + off); + + port = uhdr->uh_sport; + sp = m_split(m, off, M_DONTWAIT); + if (sp == NULL) { + /* Gak, drop packet, we can't do a split */ + goto out; + } + if (sp->m_pkthdr.len < header_size) { + /* Gak, packet can't have an SCTP header in it - to small */ + m_freem(sp); + goto out; + } + /* ok now pull up the UDP header and SCTP header together */ + sp = m_pullup(sp, header_size); + if (sp == NULL) { + /* Gak pullup failed */ + goto out; + } + /* trim out the UDP header */ + m_adj(sp, sizeof(struct udphdr)); + + /* Now reconstruct the mbuf chain */ + /* 1) find last one */ + last = m; + while (last->m_next != NULL) { + last = last->m_next; + } + last->m_next = sp; + m->m_pkthdr.len += sp->m_pkthdr.len; + last = m; + while (last != NULL) { + last = last->m_next; + } + /* Now its ready for sctp_input or sctp6_input */ + iph = mtod(m, struct ip *); + switch (iph->ip_v) { + case IPVERSION: + { + /* its IPv4 */ + len = SCTP_GET_IPV4_LENGTH(iph); + len -= sizeof(struct udphdr); + SCTP_GET_IPV4_LENGTH(iph) = len; + sctp_input_with_port(m, off, port); + break; + } +#ifdef INET6 + case IPV6_VERSION >> 4: + { + /* its IPv6 - NOT supported */ + goto out; + break; + + } +#endif + default: + { + m_freem(m); + break; + } + } + return; +out: + m_freem(m); +} void sctp_over_udp_stop(void) { - return; + struct socket *sop; + + /* + * This function assumes sysctl caller holds sctp_sysctl_info_lock() + * for writting! + */ + if (SCTP_BASE_INFO(udp_tun_socket) == NULL) { + /* Nothing to do */ + return; + } + sop = SCTP_BASE_INFO(udp_tun_socket); + soclose(sop); + SCTP_BASE_INFO(udp_tun_socket) = NULL; } int sctp_over_udp_start(void) { - return (-1); + uint16_t port; + int ret; + struct sockaddr_in sin; + struct socket *sop = NULL; + struct thread *th; + struct ucred *cred; + + /* + * This function assumes sysctl caller holds sctp_sysctl_info_lock() + * for writting! + */ + port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); + if (port == 0) { + /* Must have a port set */ + return (EINVAL); + } + if (SCTP_BASE_INFO(udp_tun_socket) != NULL) { + /* Already running -- must stop first */ + return (EALREADY); + } + th = curthread; + cred = th->td_ucred; + if ((ret = socreate(PF_INET, &sop, + SOCK_DGRAM, IPPROTO_UDP, cred, th))) { + return (ret); + } + SCTP_BASE_INFO(udp_tun_socket) = sop; + /* call the special UDP hook */ + ret = udp_set_kernel_tunneling(sop, sctp_recv_udp_tunneled_packet); + if (ret) { + goto exit_stage_left; + } + /* Ok we have a socket, bind it to the port */ + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + ret = sobind(sop, (struct sockaddr *)&sin, th); + if (ret) { + /* Close up we cant get the port */ +exit_stage_left: + sctp_over_udp_stop(); + return (ret); + } + /* + * Ok we should now get UDP packets directly to our input routine + * sctp_recv_upd_tunneled_packet(). + */ + return (0); } diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index cc940b3..56c6729 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -94,8 +94,6 @@ sctp_timer_stop(int, struct sctp_inpcb *, struct sctp_tcb *, int sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id); -uint32_t sctp_calculate_sum(struct mbuf *, int32_t *, uint32_t); - void sctp_mtu_size_reset(struct sctp_inpcb *, struct sctp_association *, uint32_t); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 30b3fde..d3b91b6 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -117,6 +117,8 @@ int tcp_insecure_rst; int tcp_do_autorcvbuf; int tcp_autorcvbuf_inc; int tcp_autorcvbuf_max; +int tcp_do_rfc3465; +int tcp_abc_l_var; #endif SYSCTL_V_STRUCT(V_NET, vnet_inet, _net_inet_tcp, TCPCTL_STATS, stats, @@ -144,6 +146,13 @@ SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_tcp, OID_AUTO, rfc3390, CTLFLAG_RW, tcp_do_rfc3390, 0, "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)"); +SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_tcp, OID_AUTO, rfc3465, CTLFLAG_RW, + tcp_do_rfc3465, 0, + "Enable RFC 3465 (Appropriate Byte Counting)"); +SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_tcp, OID_AUTO, abc_l_var, CTLFLAG_RW, + tcp_abc_l_var, 2, + "Cap the max cwnd increment during slow-start to this number of segments"); + SYSCTL_NODE(_net_inet_tcp, OID_AUTO, ecn, CTLFLAG_RW, 0, "TCP ECN"); SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_tcp_ecn, OID_AUTO, enable, CTLFLAG_RW, tcp_do_ecn, 0, "TCP ECN support"); @@ -2293,20 +2302,59 @@ process_ACK: /* * When new data is acked, open the congestion window. - * If the window gives us less than ssthresh packets - * in flight, open exponentially (maxseg per packet). - * Otherwise open linearly: maxseg per window - * (maxseg^2 / cwnd per packet). - * If cwnd > maxseg^2, fix the cwnd increment at 1 byte - * to avoid capping cwnd (as suggested in RFC2581). + * Method depends on which congestion control state we're + * in (slow start or cong avoid) and if ABC (RFC 3465) is + * enabled. + * + * slow start: cwnd <= ssthresh + * cong avoid: cwnd > ssthresh + * + * slow start and ABC (RFC 3465): + * Grow cwnd exponentially by the amount of data + * ACKed capping the max increment per ACK to + * (abc_l_var * maxseg) bytes. + * + * slow start without ABC (RFC 2581): + * Grow cwnd exponentially by maxseg per ACK. + * + * cong avoid and ABC (RFC 3465): + * Grow cwnd linearly by maxseg per RTT for each + * cwnd worth of ACKed data. + * + * cong avoid without ABC (RFC 2581): + * Grow cwnd linearly by approximately maxseg per RTT using + * maxseg^2 / cwnd per ACK as the increment. + * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to + * avoid capping cwnd. */ if ((!V_tcp_do_newreno && !(tp->t_flags & TF_SACK_PERMIT)) || !IN_FASTRECOVERY(tp)) { u_int cw = tp->snd_cwnd; u_int incr = tp->t_maxseg; - if (cw > tp->snd_ssthresh) - incr = max((incr * incr / cw), 1); - tp->snd_cwnd = min(cw+incr, TCP_MAXWIN<<tp->snd_scale); + /* In congestion avoidance? */ + if (cw > tp->snd_ssthresh) { + if (V_tcp_do_rfc3465) { + tp->t_bytes_acked += acked; + if (tp->t_bytes_acked >= tp->snd_cwnd) + tp->t_bytes_acked -= cw; + else + incr = 0; + } + else + incr = max((incr * incr / cw), 1); + /* + * In slow-start with ABC enabled and no RTO in sight? + * (Must not use abc_l_var > 1 if slow starting after an + * RTO. On RTO, snd_nxt = snd_una, so the snd_nxt == + * snd_max check is sufficient to handle this). + */ + } else if (V_tcp_do_rfc3465 && + tp->snd_nxt == tp->snd_max) + incr = min(acked, + V_tcp_abc_l_var * tp->t_maxseg); + /* ABC is on by default, so (incr == 0) frequently. */ + if (incr > 0) + tp->snd_cwnd = min(cw+incr, TCP_MAXWIN<<tp->snd_scale); } SOCKBUF_LOCK(&so->so_snd); if (acked > so->so_snd.sb_cc) { @@ -2328,8 +2376,10 @@ process_ACK: tp->snd_recover = th->th_ack - 1; if ((V_tcp_do_newreno || (tp->t_flags & TF_SACK_PERMIT)) && IN_FASTRECOVERY(tp) && - SEQ_GEQ(th->th_ack, tp->snd_recover)) + SEQ_GEQ(th->th_ack, tp->snd_recover)) { EXIT_FASTRECOVERY(tp); + tp->t_bytes_acked = 0; + } tp->snd_una = th->th_ack; if (tp->t_flags & TF_SACK_PERMIT) { if (SEQ_GT(tp->snd_una, tp->snd_recover)) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 9cb941a..53fc882 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -316,6 +316,8 @@ tcp_init(void) V_tcp_do_autorcvbuf = 1; V_tcp_autorcvbuf_inc = 16*1024; V_tcp_autorcvbuf_max = 256*1024; + V_tcp_do_rfc3465 = 1; + V_tcp_abc_l_var = 2; V_tcp_mssdflt = TCP_MSS; #ifdef INET6 diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index 18fab28..9faca96 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -1070,8 +1070,6 @@ _syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, * have an initialized label we can use. */ mac_syncache_destroy(&maclabel); - KASSERT(sc->sc_label != NULL, - ("%s: label not initialized", __func__)); #endif /* Retransmit SYN|ACK and reset retransmit count. */ if ((s = tcp_log_addrs(&sc->sc_inc, th, NULL, NULL))) { diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index acce92f..6963d9c 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -587,6 +587,7 @@ tcp_timer_rexmt(void * xtp) tp->t_dupacks = 0; } EXIT_FASTRECOVERY(tp); + tp->t_bytes_acked = 0; (void) tcp_output(tp); out: diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index f6dcae1..89987c4 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -441,8 +441,8 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) if (sinp->sin_family == AF_INET && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) return (EAFNOSUPPORT); - if (prison_remote_ip4(td->td_ucred, &sinp->sin_addr) != 0) - return (EINVAL); + if ((error = prison_remote_ip4(td->td_ucred, &sinp->sin_addr)) != 0) + return (error); TCPDEBUG0; INP_INFO_WLOCK(&V_tcbinfo); @@ -508,10 +508,9 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) in6_sin6_2_sin(&sin, sin6p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; - if (prison_remote_ip4(td->td_ucred, &sin.sin_addr) != 0) { - error = EINVAL; + if ((error = prison_remote_ip4(td->td_ucred, + &sin.sin_addr)) != 0) goto out; - } if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0) goto out; error = tcp_output_connect(so, nam); @@ -520,10 +519,8 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; inp->inp_inc.inc_flags |= INC_ISIPV6; - if (prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr) != 0) { - error = EINVAL; + if ((error = prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr)) != 0) goto out; - } if ((error = tcp6_connect(tp, nam, td)) != 0) goto out; error = tcp_output_connect(so, nam); diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index a4392cb..c52506e 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -189,6 +189,7 @@ struct tcpcb { void *t_pspare[3]; /* toe usrreqs / toepcb * / congestion algo / vimage / 1 general use */ struct toe_usrreqs *t_tu; /* offload operations vector */ void *t_toe; /* TOE pcb pointer */ + int t_bytes_acked; /* # bytes acked during current RTT */ }; /* @@ -539,6 +540,8 @@ extern int tcp_insecure_rst; extern int tcp_do_autorcvbuf; extern int tcp_autorcvbuf_inc; extern int tcp_autorcvbuf_max; +extern int tcp_do_rfc3465; +extern int tcp_abc_l_var; extern int tcp_do_tso; extern int tcp_do_autosndbuf; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index e402297..804f5fe 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -488,10 +488,28 @@ udp_input(struct mbuf *m, int off) struct mbuf *n; n = m_copy(m, 0, M_COPYALL); - if (n != NULL) - udp_append(last, ip, n, iphlen + - sizeof(struct udphdr), &udp_in); - INP_RUNLOCK(last); + if (last->inp_ppcb == NULL) { + if (n != NULL) + udp_append(last, + ip, n, + iphlen + + sizeof(struct udphdr), + &udp_in); + INP_RUNLOCK(last); + } else { + /* + * Engage the tunneling protocol we + * will have to leave the info_lock + * up, since we are hunting through + * multiple UDP's. + * + */ + udp_tun_func_t tunnel_func; + + tunnel_func = (udp_tun_func_t)last->inp_ppcb; + tunnel_func(n, iphlen, last); + INP_RUNLOCK(last); + } } last = inp; /* @@ -516,10 +534,22 @@ udp_input(struct mbuf *m, int off) V_udpstat.udps_noportbcast++; goto badheadlocked; } - udp_append(last, ip, m, iphlen + sizeof(struct udphdr), - &udp_in); - INP_RUNLOCK(last); - INP_INFO_RUNLOCK(&V_udbinfo); + if (last->inp_ppcb == NULL) { + udp_append(last, ip, m, iphlen + sizeof(struct udphdr), + &udp_in); + INP_RUNLOCK(last); + INP_INFO_RUNLOCK(&V_udbinfo); + } else { + /* + * Engage the tunneling protocol. + */ + udp_tun_func_t tunnel_func; + + tunnel_func = (udp_tun_func_t)last->inp_ppcb; + tunnel_func(m, iphlen, last); + INP_RUNLOCK(last); + INP_INFO_RUNLOCK(&V_udbinfo); + } return; } @@ -563,6 +593,17 @@ udp_input(struct mbuf *m, int off) INP_RUNLOCK(inp); goto badunlocked; } + if (inp->inp_ppcb != NULL) { + /* + * Engage the tunneling protocol. + */ + udp_tun_func_t tunnel_func; + + tunnel_func = (udp_tun_func_t)inp->inp_ppcb; + tunnel_func(m, iphlen, inp); + INP_RUNLOCK(inp); + return; + } udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in); INP_RUNLOCK(inp); return; @@ -941,10 +982,9 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, * Jail may rewrite the destination address, so let it do * that before we use it. */ - if (prison_remote_ip4(td->td_ucred, &sin->sin_addr) != 0) { - error = EINVAL; + error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); + if (error) goto release; - } /* * If a local address or port hasn't yet been selected, or if @@ -1138,6 +1178,40 @@ udp_attach(struct socket *so, int proto, struct thread *td) INP_INFO_WUNLOCK(&V_udbinfo); inp->inp_vflag |= INP_IPV4; inp->inp_ip_ttl = V_ip_defttl; + /* + * UDP does not have a per-protocol pcb (inp->inp_ppcb). + * We use this pointer for kernel tunneling pointer. + * If we ever need to have a protocol block we will + * need to move this function pointer there. Null + * in this pointer means "do the normal thing". + */ + inp->inp_ppcb = NULL; + INP_WUNLOCK(inp); + return (0); +} + +int +udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f) +{ + struct inpcb *inp; + + inp = (struct inpcb *)so->so_pcb; + KASSERT(so->so_type == SOCK_DGRAM, ("udp_set_kernel_tunneling: !dgram")); + KASSERT(so->so_pcb != NULL, ("udp_set_kernel_tunneling: NULL inp")); + if (so->so_type != SOCK_DGRAM) { + /* Not UDP socket... sorry! */ + return (ENOTSUP); + } + if (inp == NULL) { + /* NULL INP? */ + return (EINVAL); + } + INP_WLOCK(inp); + if (inp->inp_ppcb != NULL) { + INP_WUNLOCK(inp); + return (EBUSY); + } + inp->inp_ppcb = f; INP_WUNLOCK(inp); return (0); } @@ -1196,10 +1270,11 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) return (EISCONN); } sin = (struct sockaddr_in *)nam; - if (prison_remote_ip4(td->td_ucred, &sin->sin_addr) != 0) { + error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); + if (error != 0) { INP_WUNLOCK(inp); INP_INFO_WUNLOCK(&V_udbinfo); - return (EAFNOSUPPORT); + return (error); } error = in_pcbconnect(inp, nam, td->td_ucred); if (error == 0) diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index 39805ed..76a31b8 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -110,6 +110,10 @@ void udp_init(void); void udp_input(struct mbuf *, int); struct inpcb *udp_notify(struct inpcb *inp, int errno); int udp_shutdown(struct socket *so); + + +typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *); +int udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f); #endif #endif diff --git a/sys/netinet/vinet.h b/sys/netinet/vinet.h index 449334e..618afaa 100644 --- a/sys/netinet/vinet.h +++ b/sys/netinet/vinet.h @@ -127,6 +127,8 @@ struct vnet_inet { int _drop_synfin; int _tcp_do_rfc3042; int _tcp_do_rfc3390; + int _tcp_do_rfc3465; + int _tcp_abc_l_var; int _tcp_do_ecn; int _tcp_ecn_maxretries; int _tcp_insecure_rst; @@ -291,6 +293,7 @@ extern struct vnet_inet vnet_inet_0; #define V_subnetsarelocal VNET_INET(subnetsarelocal) #define V_tcb VNET_INET(tcb) #define V_tcbinfo VNET_INET(tcbinfo) +#define V_tcp_abc_l_var VNET_INET(tcp_abc_l_var) #define V_tcp_autorcvbuf_inc VNET_INET(tcp_autorcvbuf_inc) #define V_tcp_autorcvbuf_max VNET_INET(tcp_autorcvbuf_max) #define V_tcp_autosndbuf_inc VNET_INET(tcp_autosndbuf_inc) @@ -303,6 +306,7 @@ extern struct vnet_inet vnet_inet_0; #define V_tcp_do_rfc1323 VNET_INET(tcp_do_rfc1323) #define V_tcp_do_rfc3042 VNET_INET(tcp_do_rfc3042) #define V_tcp_do_rfc3390 VNET_INET(tcp_do_rfc3390) +#define V_tcp_do_rfc3465 VNET_INET(tcp_do_rfc3465) #define V_tcp_do_sack VNET_INET(tcp_do_sack) #define V_tcp_do_tso VNET_INET(tcp_do_tso) #define V_tcp_ecn_maxretries VNET_INET(tcp_ecn_maxretries) |