summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_input.c
diff options
context:
space:
mode:
authormlaier <mlaier@FreeBSD.org>2004-02-18 00:04:52 +0000
committermlaier <mlaier@FreeBSD.org>2004-02-18 00:04:52 +0000
commit60723c32606f318dd3816d81ba433654f812312b (patch)
tree8161989612a5d1dd2b4c63580a9c95cb85146c14 /sys/netinet/ip_input.c
parent9a383d1448d0eecb2082f01c9fa00232399e77a0 (diff)
downloadFreeBSD-src-60723c32606f318dd3816d81ba433654f812312b.zip
FreeBSD-src-60723c32606f318dd3816d81ba433654f812312b.tar.gz
Backout MT_TAG removal (i.e. bring back MT_TAGs) for now, as dummynet is
not working properly with the patch in place. Approved by: bms(mentor)
Diffstat (limited to 'sys/netinet/ip_input.c')
-rw-r--r--sys/netinet/ip_input.c182
1 files changed, 122 insertions, 60 deletions
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 68a69bb..e82b1ad 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -78,7 +78,6 @@
#include <sys/socketvar.h>
#include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
#include <netinet/ip_dummynet.h>
#ifdef IPSEC
@@ -240,7 +239,8 @@ static int ip_dooptions(struct mbuf *m, int,
static void ip_forward(struct mbuf *m, int srcrt,
struct sockaddr_in *next_hop);
static void ip_freef(struct ipqhead *, struct ipq *);
-static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *);
+static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *,
+ struct ipq *, u_int32_t *, u_int16_t *);
/*
* IP initialization: fill in IP protocol switch table.
@@ -300,18 +300,17 @@ ip_input(struct mbuf *m)
struct in_ifaddr *ia = NULL;
struct ifaddr *ifa;
int i, checkif, hlen = 0;
+ int ours = 0;
u_short sum;
struct in_addr pkt_dst;
- struct m_tag *mtag;
-#ifdef IPDIVERT
- u_int32_t divert_info; /* packet divert/tee info */
-#endif
+ u_int32_t divert_info = 0; /* packet divert/tee info */
struct ip_fw_args args;
int dchg = 0; /* dest changed after fw */
#ifdef PFIL_HOOKS
struct in_addr odst; /* original dst address */
#endif
#ifdef FAST_IPSEC
+ struct m_tag *mtag;
struct tdb_ident *tdbi;
struct secpolicy *sp;
int s, error;
@@ -319,19 +318,60 @@ ip_input(struct mbuf *m)
args.eh = NULL;
args.oif = NULL;
- args.next_hop = ip_claim_next_hop(m);
- args.rule = ip_dn_find_rule(m);
+ args.rule = NULL;
+ args.divert_rule = 0; /* divert cookie */
+ args.next_hop = NULL;
+
+ /*
+ * Grab info from MT_TAG mbufs prepended to the chain.
+ *
+ * XXX: This is ugly. These pseudo mbuf prepend tags should really
+ * be real m_tags. Before these have always been allocated on the
+ * callers stack, so we didn't have to free them. Now with
+ * ip_fastforward they are true mbufs and we have to free them
+ * otherwise we have a leak. Must rewrite ipfw to use m_tags.
+ */
+ for (; m && m->m_type == MT_TAG;) {
+ struct mbuf *m0;
- M_ASSERTPKTHDR(m);
+ switch(m->_m_tag_id) {
+ default:
+ printf("ip_input: unrecognised MT_TAG tag %d\n",
+ m->_m_tag_id);
+ break;
- if (m->m_flags & M_FASTFWD_OURS) {
- /* ip_fastforward firewall changed dest to local */
- m->m_flags &= ~M_FASTFWD_OURS; /* just in case... */
- goto ours;
+ case PACKET_TAG_DUMMYNET:
+ args.rule = ((struct dn_pkt *)m)->rule;
+ break;
+
+ case PACKET_TAG_DIVERT:
+ args.divert_rule = (intptr_t)m->m_hdr.mh_data & 0xffff;
+ break;
+
+ case PACKET_TAG_IPFORWARD:
+ args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
+ break;
+
+ case PACKET_TAG_IPFASTFWD_OURS:
+ ours = 1;
+ break;
+ }
+
+ m0 = m;
+ m = m->m_next;
+ /* XXX: This is set by ip_fastforward */
+ if (m0->m_nextpkt == (struct mbuf *)1)
+ m_free(m0);
}
- if (args.rule) { /* dummynet already filtered us */
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2;
+
+ M_ASSERTPKTHDR(m);
+
+ if (ours) /* ip_fastforward firewall changed dest to local */
+ goto ours;
+
+ if (args.rule) { /* dummynet already filtered us */
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
goto iphack ;
}
@@ -491,6 +531,7 @@ iphack:
#ifdef IPDIVERT
if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
/* Divert or tee packet */
+ divert_info = i;
goto ours;
}
#endif
@@ -798,11 +839,13 @@ found:
/*
* Attempt reassembly; if it succeeds, proceed.
- * ip_reass() will return a different mbuf.
+ * ip_reass() will return a different mbuf, and update
+ * the divert info in divert_info and args.divert_rule.
*/
ipstat.ips_fragments++;
m->m_pkthdr.header = ip;
- m = ip_reass(m, &ipq[sum], fp);
+ m = ip_reass(m,
+ &ipq[sum], fp, &divert_info, &args.divert_rule);
IPQ_UNLOCK();
if (m == 0)
return;
@@ -812,7 +855,7 @@ found:
hlen = ip->ip_hl << 2;
#ifdef IPDIVERT
/* Restore original checksum before diverting packet */
- if (divert_find_info(m) != 0) {
+ if (divert_info != 0) {
ip->ip_len += hlen;
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
@@ -833,15 +876,12 @@ found:
/*
* Divert or tee packet to the divert protocol if required.
*/
- divert_info = divert_find_info(m);
if (divert_info != 0) {
- struct mbuf *clone;
+ struct mbuf *clone = NULL;
/* Clone packet if we're doing a 'tee' */
if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
- clone = divert_clone(m);
- else
- clone = NULL;
+ clone = m_dup(m, M_DONTWAIT);
/* Restore packet header fields to original values */
ip->ip_len += hlen;
@@ -849,7 +889,7 @@ found:
ip->ip_off = htons(ip->ip_off);
/* Deliver packet to divert input routine */
- divert_packet(m, 1);
+ divert_packet(m, 1, divert_info & 0xffff, args.divert_rule);
ipstat.ips_delivered++;
/* If 'tee', continue with original packet */
@@ -860,11 +900,12 @@ found:
ip->ip_len += hlen;
/*
* Jump backwards to complete processing of the
- * packet. We do not need to clear args.next_hop
- * as that will not be used again and the cloned packet
- * doesn't contain a divert packet tag so we won't
- * re-entry this block.
+ * packet. But first clear divert_info to avoid
+ * entering this block again.
+ * We do not need to clear args.divert_rule
+ * or args.next_hop as they will not be used.
*/
+ divert_info = 0;
goto pass;
}
#endif
@@ -927,18 +968,19 @@ DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/
ipstat.ips_delivered++;
NET_PICKUP_GIANT();
if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
- /* attach next hop info for TCP */
- mtag = m_tag_get(PACKET_TAG_IPFORWARD,
- sizeof(struct sockaddr_in *), M_NOWAIT);
- if (mtag == NULL) {
- /* XXX statistic */
- NET_DROP_GIANT();
- goto bad;
- }
- *(struct sockaddr_in **)(mtag+1) = args.next_hop;
- m_tag_prepend(m, mtag);
- }
- (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
+ /* TCP needs IPFORWARD info if available */
+ struct m_hdr tag;
+
+ tag.mh_type = MT_TAG;
+ tag.mh_flags = PACKET_TAG_IPFORWARD;
+ tag.mh_data = (caddr_t)args.next_hop;
+ tag.mh_next = m;
+ tag.mh_nextpkt = NULL;
+
+ (*inetsw[ip_protox[ip->ip_p]].pr_input)(
+ (struct mbuf *)&tag, hlen);
+ } else
+ (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
NET_DROP_GIANT();
return;
bad:
@@ -957,7 +999,8 @@ bad:
*/
static struct mbuf *
-ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
+ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp,
+ u_int32_t *divinfo, u_int16_t *divert_rule)
{
struct ip *ip = mtod(m, struct ip *);
register struct mbuf *p, *q, *nq;
@@ -999,6 +1042,10 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
fp->ipq_dst = ip->ip_dst;
fp->ipq_frags = m;
m->m_nextpkt = NULL;
+#ifdef IPDIVERT
+ fp->ipq_div_info = 0;
+ fp->ipq_div_cookie = 0;
+#endif
goto inserted;
} else {
fp->ipq_nfrags++;
@@ -1082,15 +1129,16 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
inserted:
#ifdef IPDIVERT
- if (ip->ip_off != 0) {
- /*
- * Strip any divert information; only the info
- * on the first fragment is used/kept.
- */
- struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
- if (mtag)
- m_tag_delete(m, mtag);
+ /*
+ * Transfer firewall instructions to the fragment structure.
+ * Only trust info in the fragment at offset 0.
+ */
+ if (ip->ip_off == 0) {
+ fp->ipq_div_info = *divinfo;
+ fp->ipq_div_cookie = *divert_rule;
}
+ *divinfo = 0;
+ *divert_rule = 0;
#endif
/*
@@ -1156,6 +1204,14 @@ inserted:
mac_destroy_ipq(fp);
#endif
+#ifdef IPDIVERT
+ /*
+ * Extract firewall instructions from the fragment structure.
+ */
+ *divinfo = fp->ipq_div_info;
+ *divert_rule = fp->ipq_div_cookie;
+#endif
+
/*
* Create header for new ip packet by
* modifying header of first packet;
@@ -1176,6 +1232,10 @@ inserted:
return (m);
dropfrag:
+#ifdef IPDIVERT
+ *divinfo = 0;
+ *divert_rule = 0;
+#endif
ipstat.ips_fragdropped++;
if (fp != NULL)
fp->ipq_nfrags--;
@@ -1721,7 +1781,6 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
struct in_ifaddr *ia;
int error, type = 0, code = 0;
struct mbuf *mcopy;
- struct m_tag *mtag;
n_long dest;
struct in_addr pkt_dst;
struct ifnet *destifp;
@@ -1854,18 +1913,21 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
RTFREE(rt);
}
+ {
+ struct m_hdr tag;
+
if (next_hop) {
- mtag = m_tag_get(PACKET_TAG_IPFORWARD,
- sizeof(struct sockaddr_in *), M_NOWAIT);
- if (mtag == NULL) {
- /* XXX statistic */
- m_freem(m);
- return;
- }
- *(struct sockaddr_in **)(mtag+1) = next_hop;
- m_tag_prepend(m, mtag);
+ /* Pass IPFORWARD info if available */
+
+ tag.mh_type = MT_TAG;
+ tag.mh_flags = PACKET_TAG_IPFORWARD;
+ tag.mh_data = (caddr_t)next_hop;
+ tag.mh_next = m;
+ tag.mh_nextpkt = NULL;
+ m = (struct mbuf *)&tag;
}
error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL);
+ }
if (error)
ipstat.ips_cantforward++;
else {
OpenPOWER on IntegriCloud