Lines Matching +full:max +full:- +full:reason
1 // SPDX-License-Identifier: GPL-2.0
56 * as well. Or notify me, at least. --ANK
58 static const char ip_frag_cache_name[] = "ip4-frags";
87 struct net *net = q->fqdir->net; in ip4_frag_init()
90 q->key.v4 = *key; in ip4_frag_init()
91 qp->ecn = 0; in ip4_frag_init()
92 if (q->fqdir->max_dist) { in ip4_frag_init()
94 p = inet_getpeer_v4(net->ipv4.peers, key->saddr, key->vif); in ip4_frag_init()
95 if (p && !refcount_inc_not_zero(&p->refcnt)) in ip4_frag_init()
99 qp->peer = p; in ip4_frag_init()
107 if (qp->peer) in ip4_frag_free()
108 inet_putpeer(qp->peer); in ip4_frag_free()
125 enum skb_drop_reason reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; in ip_expire() local
134 net = qp->q.fqdir->net; in ip_expire()
139 if (READ_ONCE(qp->q.fqdir->dead)) in ip_expire()
142 spin_lock(&qp->q.lock); in ip_expire()
144 if (qp->q.flags & INET_FRAG_COMPLETE) in ip_expire()
147 qp->q.flags |= INET_FRAG_DROP; in ip_expire()
148 inet_frag_kill(&qp->q, &refs); in ip_expire()
152 if (!(qp->q.flags & INET_FRAG_FIRST_IN)) in ip_expire()
157 * deal with head->dev. in ip_expire()
159 head = inet_frag_pull_head(&qp->q); in ip_expire()
162 head->dev = dev_get_by_index_rcu(net, qp->iif); in ip_expire()
163 if (!head->dev) in ip_expire()
169 reason = ip_route_input_noref(head, iph->daddr, iph->saddr, in ip_expire()
170 ip4h_dscp(iph), head->dev); in ip_expire()
171 if (reason) in ip_expire()
177 reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; in ip_expire()
178 if (frag_expire_skip_icmp(qp->q.key.v4.user) && in ip_expire()
179 (skb_rtable(head)->rt_type != RTN_LOCAL)) in ip_expire()
182 spin_unlock(&qp->q.lock); in ip_expire()
187 spin_unlock(&qp->q.lock); in ip_expire()
190 kfree_skb_reason(head, reason); in ip_expire()
191 inet_frag_putn(&qp->q, refs); in ip_expire()
201 .saddr = iph->saddr, in ip_find()
202 .daddr = iph->daddr, in ip_find()
205 .id = iph->id, in ip_find()
206 .protocol = iph->protocol, in ip_find()
210 q = inet_frag_find(net->ipv4.fqdir, &key); in ip_find()
220 struct inet_peer *peer = qp->peer; in ip_frag_too_far()
221 unsigned int max = qp->q.fqdir->max_dist; in ip_frag_too_far() local
226 if (!peer || !max) in ip_frag_too_far()
229 start = qp->rid; in ip_frag_too_far()
230 end = atomic_inc_return(&peer->rid); in ip_frag_too_far()
231 qp->rid = end; in ip_frag_too_far()
233 rc = qp->q.fragments_tail && (end - start) > max; in ip_frag_too_far()
236 __IP_INC_STATS(qp->q.fqdir->net, IPSTATS_MIB_REASMFAILS); in ip_frag_too_far()
245 if (!mod_timer(&qp->q.timer, jiffies + qp->q.fqdir->timeout)) { in ip_frag_reinit()
246 refcount_inc(&qp->q.refcnt); in ip_frag_reinit()
247 return -ETIMEDOUT; in ip_frag_reinit()
250 sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments, in ip_frag_reinit()
252 sub_frag_mem_limit(qp->q.fqdir, sum_truesize); in ip_frag_reinit()
254 qp->q.flags = 0; in ip_frag_reinit()
255 qp->q.len = 0; in ip_frag_reinit()
256 qp->q.meat = 0; in ip_frag_reinit()
257 qp->q.rb_fragments = RB_ROOT; in ip_frag_reinit()
258 qp->q.fragments_tail = NULL; in ip_frag_reinit()
259 qp->q.last_run_head = NULL; in ip_frag_reinit()
260 qp->iif = 0; in ip_frag_reinit()
261 qp->ecn = 0; in ip_frag_reinit()
269 struct net *net = qp->q.fqdir->net; in ip_frag_queue()
274 int err = -ENOENT; in ip_frag_queue()
275 SKB_DR(reason); in ip_frag_queue()
279 if (qp->q.flags & INET_FRAG_COMPLETE) { in ip_frag_queue()
280 SKB_DR_SET(reason, DUP_FRAG); in ip_frag_queue()
284 if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && in ip_frag_queue()
287 inet_frag_kill(&qp->q, refs); in ip_frag_queue()
291 ecn = ip4_frag_ecn(ip_hdr(skb)->tos); in ip_frag_queue()
292 offset = ntohs(ip_hdr(skb)->frag_off); in ip_frag_queue()
295 offset <<= 3; /* offset is in 8-byte chunks */ in ip_frag_queue()
299 end = offset + skb->len - skb_network_offset(skb) - ihl; in ip_frag_queue()
300 err = -EINVAL; in ip_frag_queue()
307 if (end < qp->q.len || in ip_frag_queue()
308 ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) in ip_frag_queue()
310 qp->q.flags |= INET_FRAG_LAST_IN; in ip_frag_queue()
311 qp->q.len = end; in ip_frag_queue()
315 if (skb->ip_summed != CHECKSUM_UNNECESSARY) in ip_frag_queue()
316 skb->ip_summed = CHECKSUM_NONE; in ip_frag_queue()
318 if (end > qp->q.len) { in ip_frag_queue()
319 /* Some bits beyond end -> corruption. */ in ip_frag_queue()
320 if (qp->q.flags & INET_FRAG_LAST_IN) in ip_frag_queue()
322 qp->q.len = end; in ip_frag_queue()
328 err = -ENOMEM; in ip_frag_queue()
332 err = pskb_trim_rcsum(skb, end - offset); in ip_frag_queue()
336 /* Note : skb->rbnode and skb->dev share the same location. */ in ip_frag_queue()
337 dev = skb->dev; in ip_frag_queue()
341 prev_tail = qp->q.fragments_tail; in ip_frag_queue()
342 err = inet_frag_queue_insert(&qp->q, skb, offset, end); in ip_frag_queue()
347 qp->iif = dev->ifindex; in ip_frag_queue()
349 qp->q.stamp = skb->tstamp; in ip_frag_queue()
350 qp->q.tstamp_type = skb->tstamp_type; in ip_frag_queue()
351 qp->q.meat += skb->len; in ip_frag_queue()
352 qp->ecn |= ecn; in ip_frag_queue()
353 add_frag_mem_limit(qp->q.fqdir, skb->truesize); in ip_frag_queue()
355 qp->q.flags |= INET_FRAG_FIRST_IN; in ip_frag_queue()
357 fragsize = skb->len + ihl; in ip_frag_queue()
359 if (fragsize > qp->q.max_size) in ip_frag_queue()
360 qp->q.max_size = fragsize; in ip_frag_queue()
362 if (ip_hdr(skb)->frag_off & htons(IP_DF) && in ip_frag_queue()
363 fragsize > qp->max_df_size) in ip_frag_queue()
364 qp->max_df_size = fragsize; in ip_frag_queue()
366 if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && in ip_frag_queue()
367 qp->q.meat == qp->q.len) { in ip_frag_queue()
368 unsigned long orefdst = skb->_skb_refdst; in ip_frag_queue()
370 skb->_skb_refdst = 0UL; in ip_frag_queue()
372 skb->_skb_refdst = orefdst; in ip_frag_queue()
374 inet_frag_kill(&qp->q, refs); in ip_frag_queue()
380 return -EINPROGRESS; in ip_frag_queue()
384 SKB_DR_SET(reason, DUP_FRAG); in ip_frag_queue()
385 err = -EINVAL; in ip_frag_queue()
388 err = -EINVAL; in ip_frag_queue()
391 inet_frag_kill(&qp->q, refs); in ip_frag_queue()
394 kfree_skb_reason(skb, reason); in ip_frag_queue()
400 return qp->q.key.v4.user == IP_DEFRAG_LOCAL_DELIVER; in ip_frag_coalesce_ok()
408 struct net *net = qp->q.fqdir->net; in ip_frag_reasm()
414 inet_frag_kill(&qp->q, refs); in ip_frag_reasm()
416 ecn = ip_frag_ecn_table[qp->ecn]; in ip_frag_reasm()
418 err = -EINVAL; in ip_frag_reasm()
423 reasm_data = inet_frag_reasm_prepare(&qp->q, skb, prev_tail); in ip_frag_reasm()
427 len = ip_hdrlen(skb) + qp->q.len; in ip_frag_reasm()
428 err = -E2BIG; in ip_frag_reasm()
432 inet_frag_reasm_finish(&qp->q, skb, reasm_data, in ip_frag_reasm()
435 skb->dev = dev; in ip_frag_reasm()
436 IPCB(skb)->frag_max_size = max(qp->max_df_size, qp->q.max_size); in ip_frag_reasm()
439 iph->tot_len = htons(len); in ip_frag_reasm()
440 iph->tos |= ecn; in ip_frag_reasm()
443 * call to ip_fragment to avoid forwarding a DF-skb of size s while in ip_frag_reasm()
447 * frag seen to avoid sending tiny DF-fragments in case skb was built in ip_frag_reasm()
448 * from one very small df-fragment and one large non-df frag. in ip_frag_reasm()
450 if (qp->max_df_size == qp->q.max_size) { in ip_frag_reasm()
451 IPCB(skb)->flags |= IPSKB_FRAG_PMTU; in ip_frag_reasm()
452 iph->frag_off = htons(IP_DF); in ip_frag_reasm()
454 iph->frag_off = 0; in ip_frag_reasm()
460 qp->q.rb_fragments = RB_ROOT; in ip_frag_reasm()
461 qp->q.fragments_tail = NULL; in ip_frag_reasm()
462 qp->q.last_run_head = NULL; in ip_frag_reasm()
467 err = -ENOMEM; in ip_frag_reasm()
470 net_info_ratelimited("Oversized IP packet from %pI4\n", &qp->q.key.v4.saddr); in ip_frag_reasm()
479 struct net_device *dev = skb->dev ? : skb_dst(skb)->dev; in ip_defrag()
491 spin_lock(&qp->q.lock); in ip_defrag()
495 spin_unlock(&qp->q.lock); in ip_defrag()
497 inet_frag_putn(&qp->q, refs); in ip_defrag()
504 return -ENOMEM; in ip_defrag()
514 if (skb->protocol != htons(ETH_P_IP)) in ip_check_defrag()
526 if (skb->len < netoff + len || len < (iph.ihl * 4)) in ip_check_defrag()
605 table[0].data = &net->ipv4.fqdir->high_thresh; in ip4_frags_ns_ctl_register()
606 table[0].extra1 = &net->ipv4.fqdir->low_thresh; in ip4_frags_ns_ctl_register()
607 table[1].data = &net->ipv4.fqdir->low_thresh; in ip4_frags_ns_ctl_register()
608 table[1].extra2 = &net->ipv4.fqdir->high_thresh; in ip4_frags_ns_ctl_register()
609 table[2].data = &net->ipv4.fqdir->timeout; in ip4_frags_ns_ctl_register()
610 table[3].data = &net->ipv4.fqdir->max_dist; in ip4_frags_ns_ctl_register()
617 net->ipv4.frags_hdr = hdr; in ip4_frags_ns_ctl_register()
624 return -ENOMEM; in ip4_frags_ns_ctl_register()
631 table = net->ipv4.frags_hdr->ctl_table_arg; in ip4_frags_ns_ctl_unregister()
632 unregister_net_sysctl_table(net->ipv4.frags_hdr); in ip4_frags_ns_ctl_unregister()
659 res = fqdir_init(&net->ipv4.fqdir, &ip4_frags, net); in ipv4_frags_init_net()
676 net->ipv4.fqdir->high_thresh = 4 * 1024 * 1024; in ipv4_frags_init_net()
677 net->ipv4.fqdir->low_thresh = 3 * 1024 * 1024; in ipv4_frags_init_net()
683 net->ipv4.fqdir->timeout = IP_FRAG_TIME; in ipv4_frags_init_net()
685 net->ipv4.fqdir->max_dist = 64; in ipv4_frags_init_net()
689 fqdir_exit(net->ipv4.fqdir); in ipv4_frags_init_net()
695 fqdir_pre_exit(net->ipv4.fqdir); in ipv4_frags_pre_exit_net()
701 fqdir_exit(net->ipv4.fqdir); in ipv4_frags_exit_net()
721 return jhash2((const u32 *)&fq->key.v4, in ip4_obj_hashfn()
727 const struct frag_v4_compare_key *key = arg->key; in ip4_obj_cmpfn()
730 return !!memcmp(&fq->key, key, sizeof(*key)); in ip4_obj_cmpfn()