+tcp_ctlinput(cmd, sa)
+ int cmd;
+ struct sockaddr *sa;
+{
+ extern u_char inetctlerrmap[];
+ struct sockaddr_in *sin;
+ int tcp_quench(), in_rtchange();
+
+ if ((unsigned)cmd > PRC_NCMDS)
+ return;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
+ return;
+ sin = (struct sockaddr_in *)sa;
+ if (sin->sin_addr.s_addr == INADDR_ANY)
+ return;
+
+ switch (cmd) {
+
+ case PRC_QUENCH:
+ in_pcbnotify(&tcb, &sin->sin_addr, 0, tcp_quench);
+ break;
+
+ case PRC_ROUTEDEAD:
+ case PRC_REDIRECT_NET:
+ case PRC_REDIRECT_HOST:
+ case PRC_REDIRECT_TOSNET:
+ case PRC_REDIRECT_TOSHOST:
+ in_pcbnotify(&tcb, &sin->sin_addr, 0, in_rtchange);
+ break;
+
+ default:
+ if (inetctlerrmap[cmd] == 0)
+ return; /* XXX */
+ in_pcbnotify(&tcb, &sin->sin_addr, (int)inetctlerrmap[cmd],
+ (int (*)())0);
+ }
+}
+
+/*
+ * When a source quench is received, close congestion window
+ * to 80% of the outstanding data (but not less than one segment).
+ */
+tcp_quench(inp)
+ struct inpcb *inp;