• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Based on net/ipv6/ip6_input.c
4  *	Authors:
5  *	Pedro Roque		<roque@di.fc.ul.pt>
6  *	Ian P. Morris		<I.P.Morris@soton.ac.uk>
7  *
8  * Changes
9  *
10  *	Mitsuru KANDA @USAGI and
11  *	YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
12  *
13  * NewIP input
14  * Linux NewIP INET implementation
15  */
16 #define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
17 
18 #include <linux/errno.h>
19 #include <linux/types.h>
20 #include <linux/socket.h>
21 #include <linux/net.h>
22 #include <linux/netdevice.h>
23 #include <linux/nip.h>
24 
25 #include <net/sock.h>
26 #include <net/protocol.h>
27 #include <net/dst_metadata.h>
28 #include <net/transp_nip.h>
29 #include <net/nip_route.h>
30 #include <net/nip.h>
31 
32 #include "nip_hdr.h"
33 #include "tcp_nip_parameter.h"
34 
_nip_update_recv_skb_len(struct sk_buff * skb,struct nip_hdr_decap * niph)35 static int _nip_update_recv_skb_len(struct sk_buff *skb,
36 				    struct nip_hdr_decap *niph)
37 {
38 	if (!niph->include_total_len)
39 		return 0;
40 
41 	if (niph->total_len > skb->len) {
42 		nip_dbg("total_len(%u) is bigger than skb_len(%u), Drop a packet",
43 			niph->total_len, skb->len);
44 		return NET_RX_DROP;
45 	}
46 
47 	/* At present, NewIP only uses linear regions, uses skb_trim to remove end from a buffer;
48 	 * If the nonlinear region is also used later, use pskb_trim to remove end from a buffer;
49 	 */
50 	skb_trim(skb, niph->total_len);
51 	return 0;
52 }
53 
nip_rcv_finish(struct sk_buff * skb)54 static int nip_rcv_finish(struct sk_buff *skb)
55 {
56 	struct net *net = dev_net(skb->dev);
57 	void (*edemux)(struct sk_buff *skb) = NULL;
58 	int err = 0;
59 
60 	/* set /proc/sys/net/ipv4/ip_early_demux to change sysctl_ip_early_demux,
61 	 * which is used by ipv4, ipv6 and newip
62 	 */
63 	if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && !skb->sk) {
64 		const struct ninet_protocol *ipprot;
65 
66 		nip_dbg("try to early demux skb, nexthdr=0x%x", nipcb(skb)->nexthdr);
67 		ipprot = rcu_dereference(ninet_protos[nipcb(skb)->nexthdr]);
68 		if (ipprot)
69 			edemux = READ_ONCE(ipprot->early_demux);
70 		if (edemux)
71 			edemux(skb);
72 	}
73 
74 	/* nip_route_input will set nip_null_entry
75 	 * instead of NULL in skb when looking up failed.
76 	 */
77 	if (!skb_valid_dst(skb))
78 		err = nip_route_input(skb);
79 	if (err) {
80 		nip_dbg("nip_route_input lookup route exception, release skb");
81 		kfree_skb(skb);
82 		return 0;
83 	}
84 	return dst_input(skb);
85 }
86 
nip_rcv(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt,struct net_device * orig_dev)87 int nip_rcv(struct sk_buff *skb, struct net_device *dev,
88 	    struct packet_type *pt, struct net_device *orig_dev)
89 {
90 	int offset = 0;
91 	struct nip_hdr_decap niph = {0};
92 
93 	if (skb->pkt_type == PACKET_OTHERHOST) {
94 		kfree_skb(skb);
95 		return NET_RX_DROP;
96 	}
97 
98 	skb = skb_share_check(skb, GFP_ATOMIC);
99 	if (!skb)
100 		goto out;
101 
102 	memset(nipcb(skb), 0, sizeof(struct ninet_skb_parm));
103 	offset = nip_hdr_parse(skb->data, skb->len, &niph);
104 	if (offset <= 0 || offset > skb->len) {
105 		nip_dbg("check in failure, errcode=%d, Drop a packet (nexthdr=%u, hdr_len=%u)",
106 			offset, niph.nexthdr, niph.hdr_len);
107 		goto drop;
108 	}
109 
110 	if (niph.nexthdr != IPPROTO_UDP && niph.nexthdr != IPPROTO_TCP &&
111 	    niph.nexthdr != IPPROTO_NIP_ICMP) {
112 		nip_dbg("nexthdr(%u) invalid, Drop a packet", niph.nexthdr);
113 		goto drop;
114 	}
115 
116 	niph.total_len = ntohs(niph.total_len);
117 	nipcb(skb)->dstaddr = niph.daddr;
118 	nipcb(skb)->srcaddr = niph.saddr;
119 	nipcb(skb)->nexthdr = niph.nexthdr;
120 	skb->transport_header = skb->network_header + offset;
121 	skb_orphan(skb);
122 
123 	/* SKB refreshes the length after replication */
124 	if (_nip_update_recv_skb_len(skb, &niph))
125 		goto drop;
126 
127 	return nip_rcv_finish(skb);
128 drop:
129 	kfree_skb(skb);
130 out:
131 	return NET_RX_DROP;
132 }
133 
134 /* Deliver the packet to transport layer,
135  * including TCP, UDP and ICMP.
136  * Caller must hold rcu.
137  */
nip_protocol_deliver_rcu(struct sk_buff * skb)138 void nip_protocol_deliver_rcu(struct sk_buff *skb)
139 {
140 	const struct ninet_protocol *ipprot;
141 
142 	if (!pskb_pull(skb, skb_transport_offset(skb)))
143 		goto discard;
144 
145 	ipprot = rcu_dereference(ninet_protos[nipcb(skb)->nexthdr]);
146 	if (ipprot) {
147 		ipprot->handler(skb);
148 	} else {
149 		kfree_skb(skb);
150 		nip_dbg("not found transport protol, drop this packet");
151 	}
152 	return;
153 
154 discard:
155 	kfree_skb(skb);
156 }
157 
158 /* Generally called by dst_input */
nip_input(struct sk_buff * skb)159 int nip_input(struct sk_buff *skb)
160 {
161 	rcu_read_lock();
162 	nip_protocol_deliver_rcu(skb);
163 	rcu_read_unlock();
164 
165 	return 0;
166 }
167