diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -260,10 +260,9 @@ } void -sctp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip) +sctp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *inner_ip) { struct ip *outer_ip; - struct ip *inner_ip; struct sctphdr *sh; struct icmp *icmp; struct sctp_inpcb *inp; @@ -272,91 +271,85 @@ struct sctp_init_chunk *ch; struct sockaddr_in src, dst; - if (PRC_IS_REDIRECT(cmd)) { - ip = NULL; - } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { + if (inetctlerrmap[cmd] == 0) return; - } - if (ip != NULL) { - inner_ip = ip; - icmp = (struct icmp *)((caddr_t)inner_ip - - (sizeof(struct icmp) - sizeof(struct ip))); - outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); - sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); - memset(&src, 0, sizeof(struct sockaddr_in)); - src.sin_family = AF_INET; - src.sin_len = sizeof(struct sockaddr_in); - src.sin_port = sh->src_port; - src.sin_addr = inner_ip->ip_src; - memset(&dst, 0, sizeof(struct sockaddr_in)); - dst.sin_family = AF_INET; - dst.sin_len = sizeof(struct sockaddr_in); - dst.sin_port = sh->dest_port; - dst.sin_addr = inner_ip->ip_dst; - /* - * 'dst' holds the dest of the packet that failed to be - * sent. 'src' holds our local endpoint address. Thus we - * reverse the dst and the src in the lookup. - */ - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, - SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the verification tag */ - if (ntohl(sh->v_tag) != 0) { + + icmp = (struct icmp *)((caddr_t)inner_ip - + (sizeof(struct icmp) - sizeof(struct ip))); + outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); + sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + src.sin_port = sh->src_port; + src.sin_addr = inner_ip->ip_src; + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + dst.sin_port = sh->dest_port; + dst.sin_addr = inner_ip->ip_dst; + /* + * 'dst' holds the dest of the packet that failed to be + * sent. 'src' holds our local endpoint address. Thus we + * reverse the dst and the src in the lookup. + */ + inp = NULL; + net = NULL; + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, + (struct sockaddr *)&src, + &inp, &net, 1, + SCTP_DEFAULT_VRFID); + if ((stcb != NULL) && + (net != NULL) && + (inp != NULL)) { + /* Check the verification tag */ + if (ntohl(sh->v_tag) != 0) { + /* + * This must be the verification tag used + * for sending out packets. We don't + * consider packets reflecting the + * verification tag. + */ + if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + if (ntohs(outer_ip->ip_len) >= + sizeof(struct ip) + + 8 + (inner_ip->ip_hl << 2) + 20) { /* - * This must be the verification tag used - * for sending out packets. We don't - * consider packets reflecting the - * verification tag. + * In this case we can check if we + * got an INIT chunk and if the + * initiate tag matches. */ - if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { + ch = (struct sctp_init_chunk *)(sh + 1); + if ((ch->ch.chunk_type != SCTP_INITIATION) || + (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { SCTP_TCB_UNLOCK(stcb); return; } } else { - if (ntohs(outer_ip->ip_len) >= - sizeof(struct ip) + - 8 + (inner_ip->ip_hl << 2) + 20) { - /* - * In this case we can check if we - * got an INIT chunk and if the - * initiate tag matches. - */ - ch = (struct sctp_init_chunk *)(sh + 1); - if ((ch->ch.chunk_type != SCTP_INITIATION) || - (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - } - sctp_notify(inp, stcb, net, - icmp->icmp_type, - icmp->icmp_code, - ntohs(inner_ip->ip_len), - (uint32_t)ntohs(icmp->icmp_nextmtu)); - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { SCTP_TCB_UNLOCK(stcb); + return; } } + sctp_notify(inp, stcb, net, + icmp->icmp_type, + icmp->icmp_code, + ntohs(inner_ip->ip_len), + (uint32_t)ntohs(icmp->icmp_nextmtu)); + } else { + if ((stcb == NULL) && (inp != NULL)) { + /* reduce ref-count */ + SCTP_INP_WLOCK(inp); + SCTP_INP_DECR_REF(inp); + SCTP_INP_WUNLOCK(inp); + } + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } } - return; } #endif diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -2866,39 +2866,27 @@ tcp_seq icmp_tcp_seq; int mtu; - if (cmd == PRC_MSGSIZE) + switch (cmd) { + case PRC_MSGSIZE: notify = tcp_mtudisc_notify; - else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || - cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL || - cmd == PRC_TIMXCEED_INTRANS) && ip) - notify = tcp_drop_syn_sent; - - /* - * Hostdead is ugly because it goes linearly through all PCBs. - * XXX: We never get this from ICMP, otherwise it makes an - * excellent DoS attack on machines with many connections. - */ - else if (cmd == PRC_HOSTDEAD) - ip = NULL; - else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) - return; + break; + case PRC_UNREACH_PORT: + case PRC_UNREACH_PROTOCOL: + case PRC_TIMXCEED_INTRANS: + case PRC_UNREACH_ADMIN_PROHIB: + if (V_icmp_may_rst) + notify = tcp_drop_syn_sent; + break; + } - if (ip == NULL) { - in_pcbnotifyall(&V_tcbinfo, sin->sin_addr, inetctlerrmap[cmd], - notify); + if (inetctlerrmap[cmd] == 0) return; - } icp = (struct icmp *)((caddr_t)ip - offsetof(struct icmp, icmp_ip)); th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); + icmp_tcp_seq = th->th_seq; inp = in_pcblookup(&V_tcbinfo, sin->sin_addr, th->th_dport, ip->ip_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL); - if (inp != NULL && PRC_IS_REDIRECT(cmd)) { - /* signal EHOSTDOWN, as it flushes the cached route */ - inp = (*notify)(inp, EHOSTDOWN); - goto out; - } - icmp_tcp_seq = th->th_seq; if (inp != NULL) { if (!(inp->inp_flags & INP_TIMEWAIT) && !(inp->inp_flags & INP_DROPPED) && @@ -3029,7 +3017,6 @@ struct inpcb *inp; struct tcpcb *tp; struct icmp6_hdr *icmp6; - const struct sockaddr_in6 *sa6_src = NULL; struct in_conninfo inc; struct tcp_ports { uint16_t th_sport; @@ -3039,44 +3026,27 @@ unsigned int mtu; unsigned int off; - /* if the parameter is from icmp6, decode it. */ - if (ip6cp != NULL) { - icmp6 = ip6cp->ip6c_icmp6; - m = ip6cp->ip6c_m; - ip6 = ip6cp->ip6c_ip6; - off = ip6cp->ip6c_off; - sa6_src = ip6cp->ip6c_src; - dst = ip6cp->ip6c_finaldst; - } else { - m = NULL; - ip6 = NULL; - off = 0; /* fool gcc */ - sa6_src = &sa6_any; - dst = NULL; - } + icmp6 = ip6cp->ip6c_icmp6; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + dst = ip6cp->ip6c_finaldst; - if (cmd == PRC_MSGSIZE) + switch (cmd) { + case PRC_MSGSIZE: notify = tcp_mtudisc_notify; - else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || - cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL || - cmd == PRC_TIMXCEED_INTRANS) && ip6 != NULL) - notify = tcp_drop_syn_sent; - - /* - * Hostdead is ugly because it goes linearly through all PCBs. - * XXX: We never get this from ICMP, otherwise it makes an - * excellent DoS attack on machines with many connections. - */ - else if (cmd == PRC_HOSTDEAD) - ip6 = NULL; - else if ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0) - return; + break; + case PRC_UNREACH_ADMIN_PROHIB: + case PRC_UNREACH_PORT: + case PRC_UNREACH_PROTOCOL: + case PRC_TIMXCEED_INTRANS: + if (V_icmp_may_rst) + notify = tcp_drop_syn_sent; + break; + } - if (ip6 == NULL) { - in6_pcbnotify(&V_tcbinfo, sin6, 0, sa6_src, 0, cmd, NULL, - notify); + if (inet6ctlerrmap[cmd] == 0) return; - } /* Check if we can safely get the ports from the tcp hdr */ if (m == NULL || @@ -3088,11 +3058,6 @@ m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports); inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport, &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL); - if (inp != NULL && PRC_IS_REDIRECT(cmd)) { - /* signal EHOSTDOWN, as it flushes the cached route */ - inp = (*notify)(inp, EHOSTDOWN); - goto out; - } off += sizeof(struct tcp_ports); if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) { goto out; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -746,53 +746,34 @@ struct udphdr *uh; struct inpcb *inp; - if (PRC_IS_REDIRECT(cmd)) { - /* signal EHOSTDOWN, as it flushes the cached route */ - in_pcbnotifyall(pcbinfo, sin->sin_addr, EHOSTDOWN, udp_notify); + if (inetctlerrmap[cmd] == 0) return; - } - /* - * Hostdead is ugly because it goes linearly through all PCBs. - * - * XXX: We never get this from ICMP, otherwise it makes an excellent - * DoS attack on machines with many connections. - */ - if (cmd == PRC_HOSTDEAD) - ip = NULL; - else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) - return; - if (ip != NULL) { - uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); + uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); + inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport, ip->ip_src, + uh->uh_sport, INPLOOKUP_WLOCKPCB, NULL); + if (inp != NULL) { + INP_WLOCK_ASSERT(inp); + if (inp->inp_socket != NULL) + udp_notify(inp, inetctlerrmap[cmd]); + INP_WUNLOCK(inp); + } else { inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport, - ip->ip_src, uh->uh_sport, INPLOOKUP_WLOCKPCB, NULL); + ip->ip_src, uh->uh_sport, + INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL); if (inp != NULL) { - INP_WLOCK_ASSERT(inp); - if (inp->inp_socket != NULL) { - udp_notify(inp, inetctlerrmap[cmd]); - } - INP_WUNLOCK(inp); - } else { - inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport, - ip->ip_src, uh->uh_sport, - INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL); - if (inp != NULL) { - struct udpcb *up; - void *ctx; - udp_tun_icmp_t *func; - - up = intoudpcb(inp); - ctx = up->u_tun_ctx; - func = up->u_icmp_func; - INP_RUNLOCK(inp); - if (func != NULL) - (*func)(cmd, (struct sockaddr *)sin, - ip, ctx); - } + struct udpcb *up; + void *ctx; + udp_tun_icmp_t *func; + + up = intoudpcb(inp); + ctx = up->u_tun_ctx; + func = up->u_icmp_func; + INP_RUNLOCK(inp); + if (func != NULL) + (*func)(cmd, (struct sockaddr *)sin, ip, ctx); } - } else - in_pcbnotifyall(pcbinfo, sin->sin_addr, inetctlerrmap[cmd], - udp_notify); + } } static void diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -256,124 +256,112 @@ struct sctphdr sh; struct sockaddr_in6 src, dst; - if ((unsigned)cmd >= PRC_NCMDS) { + if (inet6ctlerrmap[cmd] == 0) return; - } - if (PRC_IS_REDIRECT(cmd)) { - ip6cp = NULL; - } else if (inet6ctlerrmap[cmd] == 0) { + + if (ip6cp->ip6c_m == NULL) { return; } - if (ip6cp != NULL) { - /* - * XXX: We assume that when IPV6 is non NULL, M and OFF are - * valid. - */ - if (ip6cp->ip6c_m == NULL) { - return; - } - - /* - * Check if we can safely examine the ports and the - * verification tag of the SCTP common header. - */ - if (ip6cp->ip6c_m->m_pkthdr.len < - (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { - return; - } + /* + * Check if we can safely examine the ports and the + * verification tag of the SCTP common header. + */ + if (ip6cp->ip6c_m->m_pkthdr.len < + (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { + return; + } - /* Copy out the port numbers and the verification tag. */ - memset(&sh, 0, sizeof(sh)); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off, - sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), - (caddr_t)&sh); - memset(&src, 0, sizeof(struct sockaddr_in6)); - src.sin6_family = AF_INET6; - src.sin6_len = sizeof(struct sockaddr_in6); - src.sin6_port = sh.src_port; - src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; - if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { - return; - } - memset(&dst, 0, sizeof(struct sockaddr_in6)); - dst.sin6_family = AF_INET6; - dst.sin6_len = sizeof(struct sockaddr_in6); - dst.sin6_port = sh.dest_port; - dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; - if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { - return; - } - inp = NULL; - net = NULL; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, - (struct sockaddr *)&src, - &inp, &net, 1, SCTP_DEFAULT_VRFID); - if ((stcb != NULL) && - (net != NULL) && - (inp != NULL)) { - /* Check the verification tag */ - if (ntohl(sh.v_tag) != 0) { + /* Copy out the port numbers and the verification tag. */ + memset(&sh, 0, sizeof(sh)); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off, + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), + (caddr_t)&sh); + memset(&src, 0, sizeof(struct sockaddr_in6)); + src.sin6_family = AF_INET6; + src.sin6_len = sizeof(struct sockaddr_in6); + src.sin6_port = sh.src_port; + src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; + if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } + memset(&dst, 0, sizeof(struct sockaddr_in6)); + dst.sin6_family = AF_INET6; + dst.sin6_len = sizeof(struct sockaddr_in6); + dst.sin6_port = sh.dest_port; + dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; + if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } + inp = NULL; + net = NULL; + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, + (struct sockaddr *)&src, + &inp, &net, 1, SCTP_DEFAULT_VRFID); + if ((stcb != NULL) && + (net != NULL) && + (inp != NULL)) { + /* Check the verification tag */ + if (ntohl(sh.v_tag) != 0) { + /* + * This must be the verification tag used + * for sending out packets. We don't + * consider packets reflecting the + * verification tag. + */ + if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + if (ip6cp->ip6c_m->m_pkthdr.len >= + ip6cp->ip6c_off + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr) + + offsetof(struct sctp_init, a_rwnd)) { /* - * This must be the verification tag used - * for sending out packets. We don't - * consider packets reflecting the - * verification tag. + * In this case we can check if we + * got an INIT chunk and if the + * initiate tag matches. */ - if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { + uint32_t initiate_tag; + uint8_t chunk_type; + + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + + sizeof(struct sctphdr), + sizeof(uint8_t), + (caddr_t)&chunk_type); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr), + sizeof(uint32_t), + (caddr_t)&initiate_tag); + if ((chunk_type != SCTP_INITIATION) || + (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { SCTP_TCB_UNLOCK(stcb); return; } } else { - if (ip6cp->ip6c_m->m_pkthdr.len >= - ip6cp->ip6c_off + sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr) + - offsetof(struct sctp_init, a_rwnd)) { - /* - * In this case we can check if we - * got an INIT chunk and if the - * initiate tag matches. - */ - uint32_t initiate_tag; - uint8_t chunk_type; - - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + - sizeof(struct sctphdr), - sizeof(uint8_t), - (caddr_t)&chunk_type); - m_copydata(ip6cp->ip6c_m, - ip6cp->ip6c_off + - sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr), - sizeof(uint32_t), - (caddr_t)&initiate_tag); - if ((chunk_type != SCTP_INITIATION) || - (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - } else { - SCTP_TCB_UNLOCK(stcb); - return; - } - } - sctp6_notify(inp, stcb, net, - ip6cp->ip6c_icmp6->icmp6_type, - ip6cp->ip6c_icmp6->icmp6_code, - ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); - } else { - if ((stcb == NULL) && (inp != NULL)) { - /* reduce inp's ref-count */ - SCTP_INP_WLOCK(inp); - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - } - if (stcb) { SCTP_TCB_UNLOCK(stcb); + return; } } + sctp6_notify(inp, stcb, net, + ip6cp->ip6c_icmp6->icmp6_type, + ip6cp->ip6c_icmp6->icmp6_code, + ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); + } else { + if ((stcb == NULL) && (inp != NULL)) { + /* reduce inp's ref-count */ + SCTP_INP_WLOCK(inp); + SCTP_INP_DECR_REF(inp); + SCTP_INP_WUNLOCK(inp); + } + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } } } diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -553,8 +553,8 @@ struct udphdr uh; struct ip6_hdr *ip6; struct mbuf *m; + struct inpcb *inp; int off = 0; - const struct sockaddr_in6 *sa6_src = NULL; void *cmdarg; struct inpcb *(*notify)(struct inpcb *, int) = udp_notify; struct udp_portonly { @@ -562,70 +562,38 @@ u_int16_t uh_dport; } *uhp; - if ((unsigned)cmd >= PRC_NCMDS) + if (inet6ctlerrmap[cmd] == 0) return; - if (PRC_IS_REDIRECT(cmd)) - notify = in6_rtchange, ip6cp = NULL; - else if (cmd == PRC_HOSTDEAD) - ip6cp = NULL; - else if (inet6ctlerrmap[cmd] == 0) + + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + cmdarg = ip6cp->ip6c_cmdarg; + + /* Check if we can safely examine src and dst ports. */ + if (m->m_pkthdr.len < off + sizeof(*uhp)) return; - /* if the parameter is from icmp6, decode it. */ - if (ip6cp != NULL) { - m = ip6cp->ip6c_m; - ip6 = ip6cp->ip6c_ip6; - off = ip6cp->ip6c_off; - cmdarg = ip6cp->ip6c_cmdarg; - sa6_src = ip6cp->ip6c_src; - } else { - m = NULL; - ip6 = NULL; - cmdarg = NULL; - sa6_src = &sa6_any; - } + bzero(&uh, sizeof(uh)); + m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); - if (ip6) { - /* - * XXX: We assume that when IPV6 is non NULL, - * M and OFF are valid. - */ + /* Check to see if its tunneled */ + inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_dst, uh.uh_dport, + &ip6->ip6_src, uh.uh_sport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, + m->m_pkthdr.rcvif, m); + if (inp != NULL) { + struct udpcb *up; + udp_tun_icmp_t *func; - /* Check if we can safely examine src and dst ports. */ - if (m->m_pkthdr.len < off + sizeof(*uhp)) - return; - - bzero(&uh, sizeof(uh)); - m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); - - if (!PRC_IS_REDIRECT(cmd)) { - /* Check to see if its tunneled */ - struct inpcb *inp; - inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_dst, - uh.uh_dport, &ip6->ip6_src, uh.uh_sport, - INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, - m->m_pkthdr.rcvif, m); - if (inp != NULL) { - struct udpcb *up; - - up = intoudpcb(inp); - if (up->u_icmp_func) { - /* Yes it is. */ - INP_RUNLOCK(inp); - (*up->u_icmp_func)(cmd, (struct sockaddr *)ip6cp->ip6c_src, - ip6cp, up->u_tun_ctx); - return; - } else { - /* Can't find it. */ - INP_RUNLOCK(inp); - } - } - } - in6_pcbnotify(pcbinfo, sin6, uh.uh_dport, ip6cp->ip6c_src, - uh.uh_sport, cmd, cmdarg, notify); - } else - in6_pcbnotify(pcbinfo, sin6, 0, sa6_src, 0, cmd, cmdarg, - notify); + up = intoudpcb(inp); + func = up->u_icmp_func; + INP_RUNLOCK(inp); + if (func != NULL) + func(cmd, (struct sockaddr *)ip6cp->ip6c_src, ip6cp, + up->u_tun_ctx); + } + in6_pcbnotify(pcbinfo, sin6, uh.uh_dport, ip6cp->ip6c_src, + uh.uh_sport, cmd, cmdarg, notify); } static void