From 60723c32606f318dd3816d81ba433654f812312b Mon Sep 17 00:00:00 2001 From: mlaier Date: Wed, 18 Feb 2004 00:04:52 +0000 Subject: 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) --- sys/netinet/ip_input.c | 182 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 122 insertions(+), 60 deletions(-) (limited to 'sys/netinet/ip_input.c') 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 #include -#include #include #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 { -- cgit v1.1