[SCTP] Update pmtu handling to be similar to tcp

Introduce new function sctp_transport_update_pmtu that updates
the transports and destination caches view of the path mtu.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Acked-by: Sridhar Samudrala <sri@us.ibm.com>
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 5e81984..dc0e70c 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1006,6 +1006,7 @@
 void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t);
 unsigned long sctp_transport_timeout(struct sctp_transport *);
 void sctp_transport_reset(struct sctp_transport *);
+void sctp_transport_update_pmtu(struct sctp_transport *, u32);
 
 
 /* This is the structure we use to queue packets as they come into
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 885109f..45d6a64 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -371,20 +371,8 @@
 		return;
 
 	if (t->param_flags & SPP_PMTUD_ENABLE) {
-		if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
-			printk(KERN_WARNING "%s: Reported pmtu %d too low, "
-			       "using default minimum of %d\n",
-			       __FUNCTION__, pmtu,
-			       SCTP_DEFAULT_MINSEGMENT);
-			/* Use default minimum segment size and disable
-			 * pmtu discovery on this transport.
-			 */
-			t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
-			t->param_flags = (t->param_flags & ~SPP_PMTUD) |
-				SPP_PMTUD_DISABLE;
-		} else {
-			t->pathmtu = pmtu;
-		}
+		/* Update transports view of the MTU */
+		sctp_transport_update_pmtu(t, pmtu);
 
 		/* Update association pmtu. */
 		sctp_assoc_sync_pmtu(asoc);
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 961df27..e14c271 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -241,6 +241,47 @@
 		transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
 }
 
+/* this is a complete rip-off from __sk_dst_check
+ * the cookie is always 0 since this is how it's used in the
+ * pmtu code
+ */
+static struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t)
+{
+	struct dst_entry *dst = t->dst;
+
+	if (dst && dst->obsolete && dst->ops->check(dst, 0) == NULL) {
+		dst_release(t->dst);
+		t->dst = NULL;
+		return NULL;
+	}
+
+	return dst;
+}
+
+void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
+{
+	struct dst_entry *dst;
+
+	if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
+		printk(KERN_WARNING "%s: Reported pmtu %d too low, "
+		       "using default minimum of %d\n",
+		       __FUNCTION__, pmtu,
+		       SCTP_DEFAULT_MINSEGMENT);
+		/* Use default minimum segment size and disable
+		 * pmtu discovery on this transport.
+		 */
+		t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
+		t->param_flags = (t->param_flags & ~SPP_PMTUD) |
+			SPP_PMTUD_DISABLE;
+	} else {
+		t->pathmtu = pmtu;
+	}
+
+	dst = sctp_transport_dst_check(t);
+	if (dst)
+		dst->ops->update_pmtu(dst, pmtu);
+}
+
 /* Caches the dst entry and source address for a transport's destination
  * address.
  */