+
+u_char inetctlerrmap[] = {
+ ECONNABORTED, ECONNABORTED, 0, 0,
+ 0, 0,
+ EHOSTDOWN, EHOSTUNREACH, ENETUNREACH, EHOSTUNREACH,
+ ECONNREFUSED, ECONNREFUSED, EMSGSIZE, 0,
+ 0, 0, 0, 0
+};
+
+ip_ctlinput(cmd, arg)
+ int cmd;
+ caddr_t arg;
+{
+ struct in_addr *sin;
+ int tcp_abort(), udp_abort();
+ extern struct inpcb tcb, udb;
+
+ if (cmd < 0 || cmd > PRC_NCMDS)
+ return;
+ if (inetctlerrmap[cmd] == 0)
+ return; /* XXX */
+ if (cmd == PRC_IFDOWN)
+ sin = &((struct sockaddr_in *)arg)->sin_addr;
+ else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH)
+ sin = (struct in_addr *)arg;
+ else
+ sin = &((struct icmp *)arg)->icmp_ip.ip_dst;
+ in_pcbnotify(&tcb, sin, inetctlerrmap[cmd], tcp_abort);
+ in_pcbnotify(&udb, sin, inetctlerrmap[cmd], udp_abort);
+}
+
+int ipprintfs = 0;
+int ipforwarding = 1;
+/*
+ * Forward a packet. If some error occurs return the sender
+ * and icmp packet. Note we can't always generate a meaningful
+ * icmp message because icmp doesn't have a large enough repetoire
+ * of codes and types.
+ */
+ip_forward(ip)
+ register struct ip *ip;
+{
+ register int error, type, code;
+ struct mbuf *mopt, *mcopy;
+
+ if (ipprintfs)
+ printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
+ ip->ip_dst, ip->ip_ttl);
+ if (ipforwarding == 0) {
+ /* can't tell difference between net and host */
+ type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
+ goto sendicmp;
+ }
+ if (ip->ip_ttl < IPTTLDEC) {
+ type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
+ goto sendicmp;
+ }
+ ip->ip_ttl -= IPTTLDEC;
+ mopt = m_get(M_DONTWAIT);
+ if (mopt == 0) {
+ m_freem(dtom(ip));
+ return;
+ }
+
+ /*
+ * Save at most 64 bytes of the packet in case
+ * we need to generate an ICMP message to the src.
+ */
+ mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64));
+ ip_stripoptions(ip, mopt);
+
+ /* last 0 here means no directed broadcast */
+ if ((error = ip_output(dtom(ip), mopt, 0, 0)) == 0) {
+ if (mcopy)
+ m_freem(mcopy);
+ return;
+ }
+ ip = mtod(mcopy, struct ip *);
+ type = ICMP_UNREACH, code = 0; /* need ``undefined'' */
+ switch (error) {
+
+ case ENETUNREACH:
+ case ENETDOWN:
+ code = ICMP_UNREACH_NET;
+ break;
+
+ case EMSGSIZE:
+ code = ICMP_UNREACH_NEEDFRAG;
+ break;
+
+ case EPERM:
+ code = ICMP_UNREACH_PORT;
+ break;
+
+ case ENOBUFS:
+ type = ICMP_SOURCEQUENCH;
+ break;
+
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ code = ICMP_UNREACH_HOST;
+ break;
+ }
+sendicmp:
+ icmp_error(ip, type, code);
+}