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";
86 struct net *net = q->fqdir->net; in ip4_frag_init()
89 q->key.v4 = *key; in ip4_frag_init()
90 qp->ecn = 0; in ip4_frag_init()
91 if (q->fqdir->max_dist) { in ip4_frag_init()
93 p = inet_getpeer_v4(net->ipv4.peers, key->saddr, key->vif); in ip4_frag_init()
94 if (p && !refcount_inc_not_zero(&p->refcnt)) in ip4_frag_init()
98 qp->peer = p; in ip4_frag_init()
106 if (qp->peer) in ip4_frag_free()
107 inet_putpeer(qp->peer); in ip4_frag_free()
115 inet_frag_put(&ipq->q); in ipq_put()
123 inet_frag_kill(&ipq->q); in ipq_kill()
140 enum skb_drop_reason reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; in ip_expire() local
148 net = qp->q.fqdir->net; in ip_expire()
153 if (READ_ONCE(qp->q.fqdir->dead)) in ip_expire()
156 spin_lock(&qp->q.lock); in ip_expire()
158 if (qp->q.flags & INET_FRAG_COMPLETE) in ip_expire()
161 qp->q.flags |= INET_FRAG_DROP; in ip_expire()
166 if (!(qp->q.flags & INET_FRAG_FIRST_IN)) in ip_expire()
171 * deal with head->dev. in ip_expire()
173 head = inet_frag_pull_head(&qp->q); in ip_expire()
176 head->dev = dev_get_by_index_rcu(net, qp->iif); in ip_expire()
177 if (!head->dev) in ip_expire()
183 reason = ip_route_input_noref(head, iph->daddr, iph->saddr, in ip_expire()
184 ip4h_dscp(iph), head->dev); in ip_expire()
185 if (reason) in ip_expire()
191 reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT; in ip_expire()
192 if (frag_expire_skip_icmp(qp->q.key.v4.user) && in ip_expire()
193 (skb_rtable(head)->rt_type != RTN_LOCAL)) in ip_expire()
196 spin_unlock(&qp->q.lock); in ip_expire()
201 spin_unlock(&qp->q.lock); in ip_expire()
204 kfree_skb_reason(head, reason); in ip_expire()
215 .saddr = iph->saddr, in ip_find()
216 .daddr = iph->daddr, in ip_find()
219 .id = iph->id, in ip_find()
220 .protocol = iph->protocol, in ip_find()
224 q = inet_frag_find(net->ipv4.fqdir, &key); in ip_find()
234 struct inet_peer *peer = qp->peer; in ip_frag_too_far()
235 unsigned int max = qp->q.fqdir->max_dist; in ip_frag_too_far() local
240 if (!peer || !max) in ip_frag_too_far()
243 start = qp->rid; in ip_frag_too_far()
244 end = atomic_inc_return(&peer->rid); in ip_frag_too_far()
245 qp->rid = end; in ip_frag_too_far()
247 rc = qp->q.fragments_tail && (end - start) > max; in ip_frag_too_far()
250 __IP_INC_STATS(qp->q.fqdir->net, IPSTATS_MIB_REASMFAILS); in ip_frag_too_far()
259 if (!mod_timer(&qp->q.timer, jiffies + qp->q.fqdir->timeout)) { in ip_frag_reinit()
260 refcount_inc(&qp->q.refcnt); in ip_frag_reinit()
261 return -ETIMEDOUT; in ip_frag_reinit()
264 sum_truesize = inet_frag_rbtree_purge(&qp->q.rb_fragments, in ip_frag_reinit()
266 sub_frag_mem_limit(qp->q.fqdir, sum_truesize); in ip_frag_reinit()
268 qp->q.flags = 0; in ip_frag_reinit()
269 qp->q.len = 0; in ip_frag_reinit()
270 qp->q.meat = 0; in ip_frag_reinit()
271 qp->q.rb_fragments = RB_ROOT; in ip_frag_reinit()
272 qp->q.fragments_tail = NULL; in ip_frag_reinit()
273 qp->q.last_run_head = NULL; in ip_frag_reinit()
274 qp->iif = 0; in ip_frag_reinit()
275 qp->ecn = 0; in ip_frag_reinit()
283 struct net *net = qp->q.fqdir->net; in ip_frag_queue()
288 int err = -ENOENT; in ip_frag_queue()
289 SKB_DR(reason); in ip_frag_queue()
293 if (qp->q.flags & INET_FRAG_COMPLETE) { in ip_frag_queue()
294 SKB_DR_SET(reason, DUP_FRAG); in ip_frag_queue()
298 if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && in ip_frag_queue()
305 ecn = ip4_frag_ecn(ip_hdr(skb)->tos); in ip_frag_queue()
306 offset = ntohs(ip_hdr(skb)->frag_off); in ip_frag_queue()
309 offset <<= 3; /* offset is in 8-byte chunks */ in ip_frag_queue()
313 end = offset + skb->len - skb_network_offset(skb) - ihl; in ip_frag_queue()
314 err = -EINVAL; in ip_frag_queue()
321 if (end < qp->q.len || in ip_frag_queue()
322 ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) in ip_frag_queue()
324 qp->q.flags |= INET_FRAG_LAST_IN; in ip_frag_queue()
325 qp->q.len = end; in ip_frag_queue()
329 if (skb->ip_summed != CHECKSUM_UNNECESSARY) in ip_frag_queue()
330 skb->ip_summed = CHECKSUM_NONE; in ip_frag_queue()
332 if (end > qp->q.len) { in ip_frag_queue()
333 /* Some bits beyond end -> corruption. */ in ip_frag_queue()
334 if (qp->q.flags & INET_FRAG_LAST_IN) in ip_frag_queue()
336 qp->q.len = end; in ip_frag_queue()
342 err = -ENOMEM; in ip_frag_queue()
346 err = pskb_trim_rcsum(skb, end - offset); in ip_frag_queue()
350 /* Note : skb->rbnode and skb->dev share the same location. */ in ip_frag_queue()
351 dev = skb->dev; in ip_frag_queue()
355 prev_tail = qp->q.fragments_tail; in ip_frag_queue()
356 err = inet_frag_queue_insert(&qp->q, skb, offset, end); in ip_frag_queue()
361 qp->iif = dev->ifindex; in ip_frag_queue()
363 qp->q.stamp = skb->tstamp; in ip_frag_queue()
364 qp->q.tstamp_type = skb->tstamp_type; in ip_frag_queue()
365 qp->q.meat += skb->len; in ip_frag_queue()
366 qp->ecn |= ecn; in ip_frag_queue()
367 add_frag_mem_limit(qp->q.fqdir, skb->truesize); in ip_frag_queue()
369 qp->q.flags |= INET_FRAG_FIRST_IN; in ip_frag_queue()
371 fragsize = skb->len + ihl; in ip_frag_queue()
373 if (fragsize > qp->q.max_size) in ip_frag_queue()
374 qp->q.max_size = fragsize; in ip_frag_queue()
376 if (ip_hdr(skb)->frag_off & htons(IP_DF) && in ip_frag_queue()
377 fragsize > qp->max_df_size) in ip_frag_queue()
378 qp->max_df_size = fragsize; in ip_frag_queue()
380 if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && in ip_frag_queue()
381 qp->q.meat == qp->q.len) { in ip_frag_queue()
382 unsigned long orefdst = skb->_skb_refdst; in ip_frag_queue()
384 skb->_skb_refdst = 0UL; in ip_frag_queue()
386 skb->_skb_refdst = orefdst; in ip_frag_queue()
388 inet_frag_kill(&qp->q); in ip_frag_queue()
394 return -EINPROGRESS; in ip_frag_queue()
398 SKB_DR_SET(reason, DUP_FRAG); in ip_frag_queue()
399 err = -EINVAL; in ip_frag_queue()
402 err = -EINVAL; in ip_frag_queue()
405 inet_frag_kill(&qp->q); in ip_frag_queue()
408 kfree_skb_reason(skb, reason); in ip_frag_queue()
414 return qp->q.key.v4.user == IP_DEFRAG_LOCAL_DELIVER; in ip_frag_coalesce_ok()
421 struct net *net = qp->q.fqdir->net; in ip_frag_reasm()
429 ecn = ip_frag_ecn_table[qp->ecn]; in ip_frag_reasm()
431 err = -EINVAL; in ip_frag_reasm()
436 reasm_data = inet_frag_reasm_prepare(&qp->q, skb, prev_tail); in ip_frag_reasm()
440 len = ip_hdrlen(skb) + qp->q.len; in ip_frag_reasm()
441 err = -E2BIG; in ip_frag_reasm()
445 inet_frag_reasm_finish(&qp->q, skb, reasm_data, in ip_frag_reasm()
448 skb->dev = dev; in ip_frag_reasm()
449 IPCB(skb)->frag_max_size = max(qp->max_df_size, qp->q.max_size); in ip_frag_reasm()
452 iph->tot_len = htons(len); in ip_frag_reasm()
453 iph->tos |= ecn; in ip_frag_reasm()
456 * call to ip_fragment to avoid forwarding a DF-skb of size s while in ip_frag_reasm()
460 * frag seen to avoid sending tiny DF-fragments in case skb was built in ip_frag_reasm()
461 * from one very small df-fragment and one large non-df frag. in ip_frag_reasm()
463 if (qp->max_df_size == qp->q.max_size) { in ip_frag_reasm()
464 IPCB(skb)->flags |= IPSKB_FRAG_PMTU; in ip_frag_reasm()
465 iph->frag_off = htons(IP_DF); in ip_frag_reasm()
467 iph->frag_off = 0; in ip_frag_reasm()
473 qp->q.rb_fragments = RB_ROOT; in ip_frag_reasm()
474 qp->q.fragments_tail = NULL; in ip_frag_reasm()
475 qp->q.last_run_head = NULL; in ip_frag_reasm()
480 err = -ENOMEM; in ip_frag_reasm()
483 net_info_ratelimited("Oversized IP packet from %pI4\n", &qp->q.key.v4.saddr); in ip_frag_reasm()
492 struct net_device *dev = skb->dev ? : skb_dst(skb)->dev; in ip_defrag()
503 spin_lock(&qp->q.lock); in ip_defrag()
507 spin_unlock(&qp->q.lock); in ip_defrag()
514 return -ENOMEM; in ip_defrag()
524 if (skb->protocol != htons(ETH_P_IP)) in ip_check_defrag()
536 if (skb->len < netoff + len || len < (iph.ihl * 4)) in ip_check_defrag()
615 table[0].data = &net->ipv4.fqdir->high_thresh; in ip4_frags_ns_ctl_register()
616 table[0].extra1 = &net->ipv4.fqdir->low_thresh; in ip4_frags_ns_ctl_register()
617 table[1].data = &net->ipv4.fqdir->low_thresh; in ip4_frags_ns_ctl_register()
618 table[1].extra2 = &net->ipv4.fqdir->high_thresh; in ip4_frags_ns_ctl_register()
619 table[2].data = &net->ipv4.fqdir->timeout; in ip4_frags_ns_ctl_register()
620 table[3].data = &net->ipv4.fqdir->max_dist; in ip4_frags_ns_ctl_register()
627 net->ipv4.frags_hdr = hdr; in ip4_frags_ns_ctl_register()
634 return -ENOMEM; in ip4_frags_ns_ctl_register()
641 table = net->ipv4.frags_hdr->ctl_table_arg; in ip4_frags_ns_ctl_unregister()
642 unregister_net_sysctl_table(net->ipv4.frags_hdr); in ip4_frags_ns_ctl_unregister()
669 res = fqdir_init(&net->ipv4.fqdir, &ip4_frags, net); in ipv4_frags_init_net()
686 net->ipv4.fqdir->high_thresh = 4 * 1024 * 1024; in ipv4_frags_init_net()
687 net->ipv4.fqdir->low_thresh = 3 * 1024 * 1024; in ipv4_frags_init_net()
693 net->ipv4.fqdir->timeout = IP_FRAG_TIME; in ipv4_frags_init_net()
695 net->ipv4.fqdir->max_dist = 64; in ipv4_frags_init_net()
699 fqdir_exit(net->ipv4.fqdir); in ipv4_frags_init_net()
705 fqdir_pre_exit(net->ipv4.fqdir); in ipv4_frags_pre_exit_net()
711 fqdir_exit(net->ipv4.fqdir); in ipv4_frags_exit_net()
731 return jhash2((const u32 *)&fq->key.v4, in ip4_obj_hashfn()
737 const struct frag_v4_compare_key *key = arg->key; in ip4_obj_cmpfn()
740 return !!memcmp(&fq->key, key, sizeof(*key)); in ip4_obj_cmpfn()