Add support for fragmenting ipv4 packets.
The packet filter may reassemble the ip fragments and return a packet that is larger than the MTU of the sending interface. There is no check for DF or icmp replies as we can only get a large packet to fragment by reassembling a previous fragment, and this only happens after a call to pfil(9). Obtained from: OpenBSD (mostly) Glanced at by: mlaier MFC after: 1 month
This commit is contained in:
parent
00dbaccdc4
commit
a5dbf412be
@ -263,6 +263,8 @@ static int bridge_ip_checkbasic(struct mbuf **mp);
|
||||
# ifdef INET6
|
||||
static int bridge_ip6_checkbasic(struct mbuf **mp);
|
||||
# endif /* INET6 */
|
||||
static int bridge_fragment(struct ifnet *, struct mbuf *,
|
||||
struct ether_header *, int, struct llc *);
|
||||
|
||||
SYSCTL_DECL(_net_link);
|
||||
SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
|
||||
@ -1497,13 +1499,22 @@ bridge_stop(struct ifnet *ifp, int disable)
|
||||
__inline void
|
||||
bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
|
||||
{
|
||||
int len, err;
|
||||
int len, err = 0;
|
||||
short mflags;
|
||||
struct mbuf *m0;
|
||||
|
||||
len = m->m_pkthdr.len;
|
||||
mflags = m->m_flags;
|
||||
|
||||
IFQ_ENQUEUE(&dst_ifp->if_snd, m, err);
|
||||
/* We may be sending a framgment so traverse the mbuf */
|
||||
for (; m; m = m0) {
|
||||
m0 = m->m_nextpkt;
|
||||
m->m_nextpkt = NULL;
|
||||
|
||||
if (err == 0)
|
||||
IFQ_ENQUEUE(&dst_ifp->if_snd, m, err);
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
|
||||
sc->sc_ifp->if_opackets++;
|
||||
@ -2761,13 +2772,24 @@ ipfwpass:
|
||||
error = pfil_run_hooks(&inet_pfil_hook, mp, bifp,
|
||||
dir, NULL);
|
||||
|
||||
/* Restore ip and the fields ntohs()'d. */
|
||||
if (*mp != NULL && error == 0) {
|
||||
ip = mtod(*mp, struct ip *);
|
||||
ip->ip_len = htons(ip->ip_len);
|
||||
ip->ip_off = htons(ip->ip_off);
|
||||
if (*mp == NULL || error != 0) /* filter may consume */
|
||||
break;
|
||||
|
||||
/* check if we need to fragment the packet */
|
||||
if (pfil_member && ifp != NULL && dir == PFIL_OUT) {
|
||||
i = (*mp)->m_pkthdr.len;
|
||||
if (i > ifp->if_mtu) {
|
||||
error = bridge_fragment(ifp, *mp, &eh2, snap,
|
||||
&llc1);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore ip and the fields ntohs()'d. */
|
||||
ip = mtod(*mp, struct ip *);
|
||||
ip->ip_len = htons(ip->ip_len);
|
||||
ip->ip_off = htons(ip->ip_off);
|
||||
|
||||
break;
|
||||
# ifdef INET6
|
||||
case ETHERTYPE_IPV6 :
|
||||
@ -2979,3 +3001,59 @@ bad:
|
||||
return -1;
|
||||
}
|
||||
# endif /* INET6 */
|
||||
|
||||
/*
|
||||
* bridge_fragment:
|
||||
*
|
||||
* Return a fragmented mbuf chain.
|
||||
*/
|
||||
static int
|
||||
bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh,
|
||||
int snap, struct llc *llc)
|
||||
{
|
||||
struct mbuf *m0;
|
||||
struct ip *ip;
|
||||
int error = -1;
|
||||
|
||||
if (m->m_len < sizeof(struct ip) &&
|
||||
(m = m_pullup(m, sizeof(struct ip))) == NULL)
|
||||
goto out;
|
||||
ip = mtod(m, struct ip *);
|
||||
|
||||
error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist,
|
||||
CSUM_DELAY_IP);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* walk the chain and re-add the Ethernet header */
|
||||
for (m0 = m; m0; m0 = m0->m_nextpkt) {
|
||||
if (error == 0) {
|
||||
if (snap) {
|
||||
M_PREPEND(m0, sizeof(struct llc), M_DONTWAIT);
|
||||
if (m0 == NULL) {
|
||||
error = ENOBUFS;
|
||||
continue;
|
||||
}
|
||||
bcopy(llc, mtod(m0, caddr_t),
|
||||
sizeof(struct llc));
|
||||
}
|
||||
M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT);
|
||||
if (m0 == NULL) {
|
||||
error = ENOBUFS;
|
||||
continue;
|
||||
}
|
||||
bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN);
|
||||
} else
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
ipstat.ips_fragmented++;
|
||||
|
||||
return (error);
|
||||
|
||||
out:
|
||||
if (m != NULL)
|
||||
m_freem(m);
|
||||
return (error);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user