/* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6 *codenow.Ifyouchangesomethinghere,_PLEASE_updateipv6/reassembly.c *aswell.Ornotifyme,atleast.--ANK
*/ staticconstchar ip_frag_cache_name[] = "ip4-frags";
/* Describe an entry in the "incomplete datagrams" queue. */ struct ipq { struct inet_frag_queue q;
u8 ecn; /* RFC3168 support */
u16 max_df_size; /* largest frag with DF set seen */ int iif; unsignedint rid; struct inet_peer *peer;
};
if (!(qp->q.flags & INET_FRAG_FIRST_IN)) goto out;
/* sk_buff::dev and sk_buff::rbnode are unionized. So we *pulltheheadoutofthetreeinordertobeableto *dealwithhead->dev.
*/
head = inet_frag_pull_head(&qp->q); if (!head) goto out;
head->dev = dev_get_by_index_rcu(net, qp->iif); if (!head->dev) goto out;
/* skb has no dst, perform route lookup again */
iph = ip_hdr(head);
reason = ip_route_input_noref(head, iph->daddr, iph->saddr,
ip4h_dscp(iph), head->dev); if (reason) goto out;
/* Only an end host needs to send an ICMP *"FragmentReassemblyTimeout"message,perRFC792.
*/
reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; if (frag_expire_skip_icmp(qp->q.key.v4.user) &&
(skb_rtable(head)->rt_type != RTN_LOCAL)) goto out;
/* Find the correct entry in the "incomplete datagrams" queue for *thisIPdatagram,andcreatenewone,ifnothingisfound.
*/ staticstruct ipq *ip_find(struct net *net, struct iphdr *iph,
u32 user, int vif)
{ struct frag_v4_compare_key key = {
.saddr = iph->saddr,
.daddr = iph->daddr,
.user = user,
.vif = vif,
.id = iph->id,
.protocol = iph->protocol,
}; struct inet_frag_queue *q;
q = inet_frag_find(net->ipv4.fqdir, &key); if (!q) return NULL;
return container_of(q, struct ipq, q);
}
/* Is the fragment too far ahead to be part of ipq? */ staticint ip_frag_too_far(struct ipq *qp)
{ struct inet_peer *peer = qp->peer; unsignedint max = qp->q.fqdir->max_dist; unsignedint start, end;
int rc;
if (!peer || !max) return0;
start = qp->rid;
end = atomic_inc_return(&peer->rid);
qp->rid = end;
rc = qp->q.fragments_tail && (end - start) > max;
if (rc)
__IP_INC_STATS(qp->q.fqdir->net, IPSTATS_MIB_REASMFAILS);
/* Determine the position of this fragment. */
end = offset + skb->len - skb_network_offset(skb) - ihl;
err = -EINVAL;
/* Is this the final fragment? */ if ((flags & IP_MF) == 0) { /* If we already have some bits beyond end *orhavedifferentend,thesegmentiscorrupted.
*/ if (end < qp->q.len ||
((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) goto discard_qp;
qp->q.flags |= INET_FRAG_LAST_IN;
qp->q.len = end;
} else { if (end&7) {
end &= ~7; if (skb->ip_summed != CHECKSUM_UNNECESSARY)
skb->ip_summed = CHECKSUM_NONE;
} if (end > qp->q.len) { /* Some bits beyond end -> corruption. */ if (qp->q.flags & INET_FRAG_LAST_IN) goto discard_qp;
qp->q.len = end;
}
} if (end == offset) goto discard_qp;
err = -ENOMEM; if (!pskb_pull(skb, skb_network_offset(skb) + ihl)) goto discard_qp;
err = pskb_trim_rcsum(skb, end - offset); if (err) goto discard_qp;
/* Note : skb->rbnode and skb->dev share the same location. */
dev = skb->dev; /* Makes sure compiler wont do silly aliasing games */
barrier();
/* Build a new IP datagram from all its fragments. */ staticint ip_frag_reasm(struct ipq *qp, struct sk_buff *skb, struct sk_buff *prev_tail, struct net_device *dev, int *refs)
{ struct net *net = qp->q.fqdir->net; struct iphdr *iph; void *reasm_data; int len, err;
u8 ecn;
/* When we set IP_DF on a refragmented skb we must also force a *calltoip_fragmenttoavoidforwardingaDF-skbofsizeswhile *originalsenderonlysentfragmentsofsizef(wheref<s). * *WeonlysetDF/IPSKB_FRAG_PMTUifsuchDFfragmentwasthelargest *fragseentoavoidsendingtinyDF-fragmentsincaseskbwasbuilt *fromoneverysmalldf-fragmentandonelargenon-dffrag.
*/ if (qp->max_df_size == qp->q.max_size) {
IPCB(skb)->flags |= IPSKB_FRAG_PMTU;
iph->frag_off = htons(IP_DF);
} else {
iph->frag_off = 0;
}
out_nomem:
net_dbg_ratelimited("queue_glue: no memory for gluing queue %p\n", qp);
err = -ENOMEM; goto out_fail;
out_oversize:
net_info_ratelimited("Oversized IP packet from %pI4\n", &qp->q.key.v4.saddr);
out_fail:
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); return err;
}
/* Process an incoming IP datagram fragment. */ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
{ struct net_device *dev; struct ipq *qp; int vif;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.20Bemerkung:
(vorverarbeitet am 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.