/*** * common reply function */ static void rt_icmp_send_reply(struct icmp_bxm *icmp_param, struct rtskb *skb) { struct dest_route rt; int err; icmp_param->head.icmph.checksum = 0; icmp_param->csum = 0; /* route back to the source address via the incoming device */ if (rt_ip_route_output(&rt, skb->nh.iph->saddr, skb->rtdev->local_ip) != 0) return; rt_socket_reference(icmp_socket); err = rt_ip_build_xmit(icmp_socket, rt_icmp_glue_reply_bits, icmp_param, sizeof(struct icmphdr) + icmp_param->data_len, &rt, MSG_DONTWAIT); if (err) rt_socket_dereference(icmp_socket); rtdev_dereference(rt.rtdev); RTNET_ASSERT(err == 0, rtdm_printk("RTnet: %s() error in xmit\n", __FUNCTION__););
/* * This function returns an rtskb that contains the complete, accumulated IP message. * If not all fragments of the IP message have been received yet, it returns NULL * Note: the IP header must have already been pulled from the rtskb! * */ struct rtskb *rt_ip_defrag(struct rtskb *skb, struct rtinet_protocol *ipprot) { unsigned int more_frags; unsigned int offset; struct rtsocket *sock; struct iphdr *iph = skb->nh.iph; int ret; counter++; /* Parse the IP header */ offset = ntohs(iph->frag_off); more_frags = offset & IP_MF; offset &= IP_OFFSET; offset <<= 3; /* offset is in 8-byte chunks */ /* First fragment? */ if (offset == 0) { /* Get the destination socket */ if ((sock = ipprot->dest_socket(skb)) == NULL) { /* Drop the rtskb */ kfree_rtskb(skb); return NULL; } /* Acquire the rtskb at the expense of the protocol pool */ ret = rtskb_acquire(skb, &sock->skb_pool); /* socket is now implicitely locked by the rtskb */ rt_socket_dereference(sock); if (ret != 0) { /* Drop the rtskb */ kfree_rtskb(skb); } else { /* Allocates a new collector */ alloc_collector(skb, sock); } return NULL; } else { /* Add to an existing collector */ return add_to_collector(skb, offset, more_frags); } }
/*** * rt_ip_local_deliver */ static inline int rt_ip_local_deliver(struct rtskb *skb) { struct iphdr *iph = skb->nh.iph; unsigned short protocol = iph->protocol; struct rtinet_protocol *ipprot; struct rtsocket *sock; int ret; ipprot = rt_inet_protocols[rt_inet_hashkey(protocol)]; /* Check if we are supporting the protocol */ if ((ipprot != NULL) && (ipprot->protocol == protocol)) { __rtskb_pull(skb, iph->ihl*4); /* Point into the IP datagram, just past the header. */ skb->h.raw = skb->data; /* Reassemble IP fragments */ if (iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = rt_ip_defrag(skb, ipprot); if (!skb) return 0; } else { /* Get the destination socket */ if ((sock = ipprot->dest_socket(skb)) == NULL) { kfree_rtskb(skb); return 0; } /* Acquire the rtskb at the expense of the protocol pool */ ret = rtskb_acquire(skb, &sock->skb_pool); /* Socket is now implicitely locked by the rtskb */ rt_socket_dereference(sock); if (ret != 0) { kfree_rtskb(skb); return 0; } } /* Deliver the packet to the next layer */ ret = ipprot->rcv_handler(skb); } else { #ifdef CONFIG_RTNET_ADDON_PROXY /* If a fallback handler for IP protocol has been installed, * call it! */ if (ip_fallback_handler) { ret = ip_fallback_handler(skb); if (ret) { rtos_print("RTnet: fallback handler failed\n"); } return ret; } #endif /* CONFIG_RTNET_ADDON_PROXY */ rtos_print("RTnet: no protocol found\n"); kfree_rtskb(skb); ret = 0; } return ret; }