/*** * * ipv4/ip_input.c - process incoming IP packets * * Copyright (C) 2002 Ulrich Marx * 2003-2005 Jan Kiszka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_ADDON_PROXY) #include rt_ip_fallback_handler_t rt_ip_fallback_handler = NULL; EXPORT_SYMBOL_GPL(rt_ip_fallback_handler); #endif /* CONFIG_XENO_DRIVERS_NET_ADDON_PROXY */ /*** * rt_ip_local_deliver */ static inline void 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 err; 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; sock = skb->sk; } else { /* Get the destination socket */ if ((sock = ipprot->dest_socket(skb)) == NULL) { #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_ADDON_PROXY) if (rt_ip_fallback_handler) { __rtskb_push(skb, iph->ihl * 4); rt_ip_fallback_handler(skb); return; } #endif kfree_rtskb(skb); return; } /* Acquire the rtskb, to unlock the device skb pool */ err = rtskb_acquire(skb, &sock->skb_pool); if (err) { kfree_rtskb(skb); rt_socket_dereference(sock); return; } } /* Deliver the packet to the next layer */ ipprot->rcv_handler(skb); /* Packet is queued, socket can be released */ rt_socket_dereference(sock); #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_ADDON_PROXY) } else if (rt_ip_fallback_handler) { /* If a fallback handler for IP protocol has been installed, * call it. */ rt_ip_fallback_handler(skb); #endif /* CONFIG_XENO_DRIVERS_NET_ADDON_PROXY */ } else { if (IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4_DEBUG)) rtdm_printk("RTnet: no protocol found\n"); kfree_rtskb(skb); } } /*** * rt_ip_rcv */ int rt_ip_rcv(struct rtskb *skb, struct rtpacket_type *pt) { struct iphdr *iph; __u32 len; /* When the interface is in promisc. mode, drop all the crap * that it receives, do not try to analyse it. */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; iph = skb->nh.iph; /* * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. * * Is the datagram acceptable? * * 1. Length at least the size of an ip header * 2. Version of 4 * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] * 4. Doesn't have a bogus length */ if (iph->ihl < 5 || iph->version != 4) goto drop; if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) goto drop; len = ntohs(iph->tot_len); if ((skb->len < len) || (len < ((__u32)iph->ihl << 2))) goto drop; rtskb_trim(skb, len); #ifdef CONFIG_XENO_DRIVERS_NET_RTIPV4_ROUTER if (rt_ip_route_forward(skb, iph->daddr)) return 0; #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4_ROUTER */ rt_ip_local_deliver(skb); return 0; drop: kfree_rtskb(skb); return 0; }