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