- 论坛徽章:
- 0
|
- /*
- * linux-2.6.22.1/net/ipv4/ip_fragment.c
- *
- * Oops, a fragment queue timed out.
- * Kill it and send an ICMP reply.
- *
- * sisi 2007-8-13 02:27pm
- */
- static void ip_expire(unsigned long arg)
- {
- struct ipq *qp = (struct ipq *) arg;
- spin_lock(&qp->lock);
- if (qp->last_in & COMPLETE)
- goto out;
- ipq_kill(qp);
- IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
- IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
- if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
- struct sk_buff *head = qp->fragments;
- /*
- * Send an ICMP "Fragment Reassembly Timeout" message.
- *
- * 由这里引发
- */
- if ((head->dev = dev_get_by_index(qp->iif)) != NULL) {
- icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
- dev_put(head->dev);
- }
- }
- out:
- spin_unlock(&qp->lock);
- ipq_put(qp, NULL);
- }
- void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
- {
- struct iphdr *iph;
- int room;
- struct icmp_bxm icmp_param;
- struct rtable *rt = (struct rtable *)skb_in->dst;
- struct ipcm_cookie ipc;
- __be32 saddr;
- u8 tos;
- if (!rt) {
- /* 在这里兑现,
- *
- * defarg, if issued by netfilter,
- * at PRE_ROUTING in normal cases,
- * 谁给skb_in->dst赋值?
- *
- * 本应发送Fragment Reassembly Timeout message,
- * 确没有发。
- */
- goto out;
- }
- /*
- * Find the original header. It is expected to be valid, of course.
- * Check this, icmp_send is called from the most obscure devices
- * sometimes.
- */
- iph = ip_hdr(skb_in);
- if ((u8 *)iph < skb_in->head ||
- (skb_in->network_header + sizeof(*iph)) > skb_in->tail)
- goto out;
- /*
- * No replies to physical multicast/broadcast
- */
- if (skb_in->pkt_type != PACKET_HOST)
- goto out;
- /*
- * Now check at the protocol level
- */
- if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
- goto out;
- /*
- * Only reply to fragment 0. We byte re-order the constant
- * mask for efficiency.
- */
- if (iph->frag_off & htons(IP_OFFSET))
- goto out;
- /*
- * If we send an ICMP error to an ICMP error a mess would result..
- */
- if (icmp_pointers[type].error) {
- /*
- * We are an error, check if we are replying to an
- * ICMP error
- */
- if (iph->protocol == IPPROTO_ICMP) {
- u8 _inner_type, *itp;
- itp = skb_header_pointer(skb_in,
- skb_network_header(skb_in) +
- (iph->ihl << 2) +
- offsetof(struct icmphdr,
- type) -
- skb_in->data,
- sizeof(_inner_type),
- &_inner_type);
- if (itp == NULL)
- goto out;
- /*
- * Assume any unknown ICMP type is an error. This
- * isn't specified by the RFC, but think about it..
- */
- if (*itp > NR_ICMP_TYPES ||
- icmp_pointers[*itp].error)
- goto out;
- }
- }
- if (icmp_xmit_lock())
- return;
- /*
- * Construct source address and options.
- */
- saddr = iph->daddr;
- if (!(rt->rt_flags & RTCF_LOCAL)) {
- struct net_device *dev = NULL;
- if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr)
- dev = dev_get_by_index(rt->fl.iif);
- if (dev) {
- saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK);
- dev_put(dev);
- } else
- saddr = 0;
- }
- tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
- IPTOS_PREC_INTERNETCONTROL) :
- iph->tos;
- if (ip_options_echo(&icmp_param.replyopts, skb_in))
- goto out_unlock;
- /*
- * Prepare data for ICMP header.
- */
- icmp_param.data.icmph.type = type;
- icmp_param.data.icmph.code = code;
- icmp_param.data.icmph.un.gateway = info;
- icmp_param.data.icmph.checksum = 0;
- icmp_param.skb = skb_in;
- icmp_param.offset = skb_network_offset(skb_in);
- icmp_out_count(icmp_param.data.icmph.type);
- inet_sk(icmp_socket->sk)->tos = tos;
- ipc.addr = iph->saddr;
- ipc.opt = &icmp_param.replyopts;
- {
- struct flowi fl = {
- .nl_u = {
- .ip4_u = {
- .daddr = icmp_param.replyopts.srr ?
- icmp_param.replyopts.faddr :
- iph->saddr,
- .saddr = saddr,
- .tos = RT_TOS(tos)
- }
- },
- .proto = IPPROTO_ICMP,
- .uli_u = {
- .icmpt = {
- .type = type,
- .code = code
- }
- }
- };
- security_skb_classify_flow(skb_in, &fl);
- if (ip_route_output_key(&rt, &fl))
- goto out_unlock;
- }
- if (!icmpv4_xrlim_allow(rt, type, code))
- goto ende;
- /* RFC says return as much as we can without exceeding 576 bytes. */
- room = dst_mtu(&rt->u.dst);
- if (room > 576)
- room = 576;
- room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
- room -= sizeof(struct icmphdr);
- icmp_param.data_len = skb_in->len - icmp_param.offset;
- if (icmp_param.data_len > room)
- icmp_param.data_len = room;
- icmp_param.head_len = sizeof(struct icmphdr);
- icmp_push_reply(&icmp_param, &ipc, rt);
- ende:
- ip_rt_put(rt);
- out_unlock:
- icmp_xmit_unlock();
- out:;
- }
复制代码
[ 本帖最后由 sisi8408 于 2007-8-13 15:56 编辑 ] |
|