Author: tuexen
Date: Tue Apr 12 21:40:54 2016
New Revision: 297880
URL: https://svnweb.freebsd.org/changeset/base/297880

Log:
  Refactor the handling of ICMP/IPv4 packets for SCTP/IPv4.
  
  This cleansup the code and prepares upcoming handling of ICMP/IPv4 packets
  for SCTP/UDP/IPv4 packets. IPv6 changes will follow...
  
  MFC after:    3 days

Modified:
  head/sys/netinet/sctp_usrreq.c

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c      Tue Apr 12 21:34:04 2016        
(r297879)
+++ head/sys/netinet/sctp_usrreq.c      Tue Apr 12 21:40:54 2016        
(r297880)
@@ -144,102 +144,33 @@ sctp_pathmtu_adjustment(struct sctp_tcb 
 
 #ifdef INET
 static void
-sctp_notify_mbuf(struct sctp_inpcb *inp,
-    struct sctp_tcb *stcb,
-    struct sctp_nets *net,
-    struct ip *ip)
-{
-       struct icmp *icmph;
-       int totsz, tmr_stopped = 0;
-       uint16_t nxtsz;
-
-       /* protection */
-       if ((inp == NULL) || (stcb == NULL) || (net == NULL) || (ip == NULL)) {
-               if (stcb != NULL) {
-                       SCTP_TCB_UNLOCK(stcb);
-               }
-               return;
-       }
-       icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
-           sizeof(struct ip)));
-       if (icmph->icmp_type != ICMP_UNREACH) {
-               /* We only care about unreachable */
-               SCTP_TCB_UNLOCK(stcb);
-               return;
-       }
-       if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
-               /* not a unreachable message due to frag. */
-               SCTP_TCB_UNLOCK(stcb);
-               return;
-       }
-       totsz = ntohs(ip->ip_len);
-
-       nxtsz = ntohs(icmph->icmp_nextmtu);
-       if (nxtsz == 0) {
-               /*
-                * old type router that does not tell us what the next size
-                * mtu is. Rats we will have to guess (in a educated fashion
-                * of course)
-                */
-               nxtsz = sctp_get_prev_mtu(totsz);
-       }
-       /* Stop any PMTU timer */
-       if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
-               tmr_stopped = 1;
-               sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
-                   SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
-       }
-       /* Adjust destination size limit */
-       if (net->mtu > nxtsz) {
-               net->mtu = nxtsz;
-               if (net->port) {
-                       net->mtu -= sizeof(struct udphdr);
-               }
-       }
-       /* now what about the ep? */
-       if (stcb->asoc.smallest_mtu > nxtsz) {
-               sctp_pathmtu_adjustment(stcb, nxtsz);
-       }
-       if (tmr_stopped)
-               sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
-
-       SCTP_TCB_UNLOCK(stcb);
-}
-
-static void
 sctp_notify(struct sctp_inpcb *inp,
-    struct ip *ip,
-    struct sockaddr *to,
     struct sctp_tcb *stcb,
-    struct sctp_nets *net)
+    struct sctp_nets *net,
+    uint8_t icmp_type,
+    uint8_t icmp_code,
+    uint16_t ip_len,
+    uint16_t next_mtu)
 {
 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
        struct socket *so;
 
 #endif
-       struct icmp *icmph;
+       int timer_stopped;
 
-       /* protection */
-       if ((inp == NULL) || (stcb == NULL) || (net == NULL) || (to == NULL)) {
-               if (stcb)
-                       SCTP_TCB_UNLOCK(stcb);
-               return;
-       }
-       icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
-           sizeof(struct ip)));
-       if (icmph->icmp_type != ICMP_UNREACH) {
+       if (icmp_type != ICMP_UNREACH) {
                /* We only care about unreachable */
                SCTP_TCB_UNLOCK(stcb);
                return;
        }
-       if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
-           (icmph->icmp_code == ICMP_UNREACH_HOST) ||
-           (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
-           (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
-           (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
-           (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
-           (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
-           (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
+       if ((icmp_code == ICMP_UNREACH_NET) ||
+           (icmp_code == ICMP_UNREACH_HOST) ||
+           (icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
+           (icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
+           (icmp_code == ICMP_UNREACH_ISOLATED) ||
+           (icmp_code == ICMP_UNREACH_NET_PROHIB) ||
+           (icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
+           (icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
 
                /*
                 * Hmm reachablity problems we must examine closely. If its
@@ -248,7 +179,7 @@ sctp_notify(struct sctp_inpcb *inp,
                 * it a OOTB abort.
                 */
                if (net->dest_state & SCTP_ADDR_REACHABLE) {
-                       /* Ok that destination is NOT reachable */
+                       /* OK, that destination is NOT reachable. */
                        net->dest_state &= ~SCTP_ADDR_REACHABLE;
                        net->dest_state &= ~SCTP_ADDR_PF;
                        sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
@@ -256,8 +187,8 @@ sctp_notify(struct sctp_inpcb *inp,
                            (void *)net, SCTP_SO_NOT_LOCKED);
                }
                SCTP_TCB_UNLOCK(stcb);
-       } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
-           (icmph->icmp_code == ICMP_UNREACH_PORT)) {
+       } else if ((icmp_code == ICMP_UNREACH_PROTOCOL) ||
+           (icmp_code == ICMP_UNREACH_PORT)) {
                /*
                 * Here the peer is either playing tricks on us, including
                 * an address that belongs to someone who does not support
@@ -281,19 +212,51 @@ sctp_notify(struct sctp_inpcb *inp,
                /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
 #endif
                /* no need to unlock here, since the TCB is gone */
+       } else if (icmp_code == ICMP_UNREACH_NEEDFRAG) {
+               /* Find the next (smaller) MTU */
+               if (next_mtu == 0) {
+                       /*
+                        * Old type router that does not tell us what the
+                        * next MTU is. Rats we will have to guess (in a
+                        * educated fashion of course).
+                        */
+                       next_mtu = sctp_get_prev_mtu(ip_len);
+               }
+               /* Stop the PMTU timer. */
+               if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
+                       timer_stopped = 1;
+                       sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, 
stcb, net,
+                           SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
+               } else {
+                       timer_stopped = 0;
+               }
+               /* Update the path MTU. */
+               if (net->mtu > next_mtu) {
+                       net->mtu = next_mtu;
+                       if (net->port) {
+                               net->mtu -= sizeof(struct udphdr);
+                       }
+               }
+               /* Update the association MTU */
+               if (stcb->asoc.smallest_mtu > next_mtu) {
+                       sctp_pathmtu_adjustment(stcb, next_mtu);
+               }
+               /* Finally, start the PMTU timer if it was running before. */
+               if (timer_stopped) {
+                       sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, 
stcb, net);
+               }
+               SCTP_TCB_UNLOCK(stcb);
        } else {
                SCTP_TCB_UNLOCK(stcb);
        }
 }
 
-#endif
-
-#ifdef INET
 void
 sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 {
        struct ip *ip = vip;
        struct sctphdr *sh;
+       struct icmp *icmph;
        uint32_t vrf_id;
 
        /* FIX, for non-bsd is this right? */
@@ -313,6 +276,9 @@ sctp_ctlinput(int cmd, struct sockaddr *
                struct sctp_nets *net = NULL;
                struct sockaddr_in to, from;
 
+               icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
+                   sizeof(struct ip)));
+
                sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
                bzero(&to, sizeof(to));
                bzero(&from, sizeof(from));
@@ -322,7 +288,6 @@ sctp_ctlinput(int cmd, struct sockaddr *
                from.sin_addr = ip->ip_src;
                to.sin_port = sh->dest_port;
                to.sin_addr = ip->ip_dst;
-
                /*
                 * 'to' holds the dest of the packet that failed to be sent.
                 * 'from' holds our local endpoint address. Thus we reverse
@@ -332,6 +297,7 @@ sctp_ctlinput(int cmd, struct sockaddr *
                    (struct sockaddr *)&from,
                    &inp, &net, 1, vrf_id);
                if ((stcb != NULL) &&
+                   (net != NULL) &&
                    (inp != NULL) &&
                    (inp->sctp_socket != NULL)) {
                        /* Check the verification tag */
@@ -342,7 +308,7 @@ sctp_ctlinput(int cmd, struct sockaddr *
                                 * consider packets reflecting the
                                 * verification tag.
                                 */
-                               if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 
{
+                               if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
                                        SCTP_TCB_UNLOCK(stcb);
                                        return;
                                }
@@ -355,14 +321,11 @@ sctp_ctlinput(int cmd, struct sockaddr *
                                SCTP_TCB_UNLOCK(stcb);
                                return;
                        }
-                       if (cmd != PRC_MSGSIZE) {
-                               sctp_notify(inp, ip,
-                                   (struct sockaddr *)&to, stcb,
-                                   net);
-                       } else {
-                               /* handle possible ICMP size messages */
-                               sctp_notify_mbuf(inp, stcb, net, ip);
-                       }
+                       sctp_notify(inp, stcb, net,
+                           icmph->icmp_type,
+                           icmph->icmp_code,
+                           ntohs(ip->ip_len),
+                           ntohs(icmph->icmp_nextmtu));
                } else {
                        if ((stcb == NULL) && (inp != NULL)) {
                                /* reduce ref-count */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to