xref: /OK3568_Linux_fs/kernel/net/ipv6/seg6.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  SR-IPv6 implementation
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Author:
6*4882a593Smuzhiyun  *  David Lebrun <david.lebrun@uclouvain.be>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/errno.h>
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <linux/socket.h>
12*4882a593Smuzhiyun #include <linux/net.h>
13*4882a593Smuzhiyun #include <linux/in6.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/rhashtable.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <net/ipv6.h>
18*4882a593Smuzhiyun #include <net/protocol.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <net/seg6.h>
21*4882a593Smuzhiyun #include <net/genetlink.h>
22*4882a593Smuzhiyun #include <linux/seg6.h>
23*4882a593Smuzhiyun #include <linux/seg6_genl.h>
24*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
25*4882a593Smuzhiyun #include <net/seg6_hmac.h>
26*4882a593Smuzhiyun #endif
27*4882a593Smuzhiyun 
seg6_validate_srh(struct ipv6_sr_hdr * srh,int len,bool reduced)28*4882a593Smuzhiyun bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	unsigned int tlv_offset;
31*4882a593Smuzhiyun 	int max_last_entry;
32*4882a593Smuzhiyun 	int trailing;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	if (srh->type != IPV6_SRCRT_TYPE_4)
35*4882a593Smuzhiyun 		return false;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (((srh->hdrlen + 1) << 3) != len)
38*4882a593Smuzhiyun 		return false;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	if (!reduced && srh->segments_left > srh->first_segment) {
41*4882a593Smuzhiyun 		return false;
42*4882a593Smuzhiyun 	} else {
43*4882a593Smuzhiyun 		max_last_entry = (srh->hdrlen / 2) - 1;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 		if (srh->first_segment > max_last_entry)
46*4882a593Smuzhiyun 			return false;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 		if (srh->segments_left > srh->first_segment + 1)
49*4882a593Smuzhiyun 			return false;
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	tlv_offset = sizeof(*srh) + ((srh->first_segment + 1) << 4);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	trailing = len - tlv_offset;
55*4882a593Smuzhiyun 	if (trailing < 0)
56*4882a593Smuzhiyun 		return false;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	while (trailing) {
59*4882a593Smuzhiyun 		struct sr6_tlv *tlv;
60*4882a593Smuzhiyun 		unsigned int tlv_len;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 		if (trailing < sizeof(*tlv))
63*4882a593Smuzhiyun 			return false;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		tlv = (struct sr6_tlv *)((unsigned char *)srh + tlv_offset);
66*4882a593Smuzhiyun 		tlv_len = sizeof(*tlv) + tlv->len;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 		trailing -= tlv_len;
69*4882a593Smuzhiyun 		if (trailing < 0)
70*4882a593Smuzhiyun 			return false;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 		tlv_offset += tlv_len;
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	return true;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun static struct genl_family seg6_genl_family;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
81*4882a593Smuzhiyun 	[SEG6_ATTR_DST]				= { .type = NLA_BINARY,
82*4882a593Smuzhiyun 		.len = sizeof(struct in6_addr) },
83*4882a593Smuzhiyun 	[SEG6_ATTR_DSTLEN]			= { .type = NLA_S32, },
84*4882a593Smuzhiyun 	[SEG6_ATTR_HMACKEYID]		= { .type = NLA_U32, },
85*4882a593Smuzhiyun 	[SEG6_ATTR_SECRET]			= { .type = NLA_BINARY, },
86*4882a593Smuzhiyun 	[SEG6_ATTR_SECRETLEN]		= { .type = NLA_U8, },
87*4882a593Smuzhiyun 	[SEG6_ATTR_ALGID]			= { .type = NLA_U8, },
88*4882a593Smuzhiyun 	[SEG6_ATTR_HMACINFO]		= { .type = NLA_NESTED, },
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
92*4882a593Smuzhiyun 
seg6_genl_sethmac(struct sk_buff * skb,struct genl_info * info)93*4882a593Smuzhiyun static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	struct net *net = genl_info_net(info);
96*4882a593Smuzhiyun 	struct seg6_pernet_data *sdata;
97*4882a593Smuzhiyun 	struct seg6_hmac_info *hinfo;
98*4882a593Smuzhiyun 	u32 hmackeyid;
99*4882a593Smuzhiyun 	char *secret;
100*4882a593Smuzhiyun 	int err = 0;
101*4882a593Smuzhiyun 	u8 algid;
102*4882a593Smuzhiyun 	u8 slen;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	sdata = seg6_pernet(net);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
107*4882a593Smuzhiyun 	    !info->attrs[SEG6_ATTR_SECRETLEN] ||
108*4882a593Smuzhiyun 	    !info->attrs[SEG6_ATTR_ALGID])
109*4882a593Smuzhiyun 		return -EINVAL;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
112*4882a593Smuzhiyun 	slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
113*4882a593Smuzhiyun 	algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (hmackeyid == 0)
116*4882a593Smuzhiyun 		return -EINVAL;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (slen > SEG6_HMAC_SECRET_LEN)
119*4882a593Smuzhiyun 		return -EINVAL;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	mutex_lock(&sdata->lock);
122*4882a593Smuzhiyun 	hinfo = seg6_hmac_info_lookup(net, hmackeyid);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (!slen) {
125*4882a593Smuzhiyun 		if (!hinfo)
126*4882a593Smuzhiyun 			err = -ENOENT;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		err = seg6_hmac_info_del(net, hmackeyid);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 		goto out_unlock;
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (!info->attrs[SEG6_ATTR_SECRET]) {
134*4882a593Smuzhiyun 		err = -EINVAL;
135*4882a593Smuzhiyun 		goto out_unlock;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (slen > nla_len(info->attrs[SEG6_ATTR_SECRET])) {
139*4882a593Smuzhiyun 		err = -EINVAL;
140*4882a593Smuzhiyun 		goto out_unlock;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (hinfo) {
144*4882a593Smuzhiyun 		err = seg6_hmac_info_del(net, hmackeyid);
145*4882a593Smuzhiyun 		if (err)
146*4882a593Smuzhiyun 			goto out_unlock;
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	hinfo = kzalloc(sizeof(*hinfo), GFP_KERNEL);
152*4882a593Smuzhiyun 	if (!hinfo) {
153*4882a593Smuzhiyun 		err = -ENOMEM;
154*4882a593Smuzhiyun 		goto out_unlock;
155*4882a593Smuzhiyun 	}
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	memcpy(hinfo->secret, secret, slen);
158*4882a593Smuzhiyun 	hinfo->slen = slen;
159*4882a593Smuzhiyun 	hinfo->alg_id = algid;
160*4882a593Smuzhiyun 	hinfo->hmackeyid = hmackeyid;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	err = seg6_hmac_info_add(net, hmackeyid, hinfo);
163*4882a593Smuzhiyun 	if (err)
164*4882a593Smuzhiyun 		kfree(hinfo);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun out_unlock:
167*4882a593Smuzhiyun 	mutex_unlock(&sdata->lock);
168*4882a593Smuzhiyun 	return err;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun #else
172*4882a593Smuzhiyun 
seg6_genl_sethmac(struct sk_buff * skb,struct genl_info * info)173*4882a593Smuzhiyun static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	return -ENOTSUPP;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun #endif
179*4882a593Smuzhiyun 
seg6_genl_set_tunsrc(struct sk_buff * skb,struct genl_info * info)180*4882a593Smuzhiyun static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct net *net = genl_info_net(info);
183*4882a593Smuzhiyun 	struct in6_addr *val, *t_old, *t_new;
184*4882a593Smuzhiyun 	struct seg6_pernet_data *sdata;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	sdata = seg6_pernet(net);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (!info->attrs[SEG6_ATTR_DST])
189*4882a593Smuzhiyun 		return -EINVAL;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	val = nla_data(info->attrs[SEG6_ATTR_DST]);
192*4882a593Smuzhiyun 	t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
193*4882a593Smuzhiyun 	if (!t_new)
194*4882a593Smuzhiyun 		return -ENOMEM;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	mutex_lock(&sdata->lock);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	t_old = sdata->tun_src;
199*4882a593Smuzhiyun 	rcu_assign_pointer(sdata->tun_src, t_new);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	mutex_unlock(&sdata->lock);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	synchronize_net();
204*4882a593Smuzhiyun 	kfree(t_old);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
seg6_genl_get_tunsrc(struct sk_buff * skb,struct genl_info * info)209*4882a593Smuzhiyun static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct net *net = genl_info_net(info);
212*4882a593Smuzhiyun 	struct in6_addr *tun_src;
213*4882a593Smuzhiyun 	struct sk_buff *msg;
214*4882a593Smuzhiyun 	void *hdr;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
217*4882a593Smuzhiyun 	if (!msg)
218*4882a593Smuzhiyun 		return -ENOMEM;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
221*4882a593Smuzhiyun 			  &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
222*4882a593Smuzhiyun 	if (!hdr)
223*4882a593Smuzhiyun 		goto free_msg;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	rcu_read_lock();
226*4882a593Smuzhiyun 	tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
229*4882a593Smuzhiyun 		goto nla_put_failure;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	rcu_read_unlock();
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	genlmsg_end(msg, hdr);
234*4882a593Smuzhiyun 	return genlmsg_reply(msg, info);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun nla_put_failure:
237*4882a593Smuzhiyun 	rcu_read_unlock();
238*4882a593Smuzhiyun free_msg:
239*4882a593Smuzhiyun 	nlmsg_free(msg);
240*4882a593Smuzhiyun 	return -ENOMEM;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
244*4882a593Smuzhiyun 
__seg6_hmac_fill_info(struct seg6_hmac_info * hinfo,struct sk_buff * msg)245*4882a593Smuzhiyun static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
246*4882a593Smuzhiyun 				 struct sk_buff *msg)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
249*4882a593Smuzhiyun 	    nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
250*4882a593Smuzhiyun 	    nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
251*4882a593Smuzhiyun 	    nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
252*4882a593Smuzhiyun 		return -1;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	return 0;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
__seg6_genl_dumphmac_element(struct seg6_hmac_info * hinfo,u32 portid,u32 seq,u32 flags,struct sk_buff * skb,u8 cmd)257*4882a593Smuzhiyun static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
258*4882a593Smuzhiyun 					u32 portid, u32 seq, u32 flags,
259*4882a593Smuzhiyun 					struct sk_buff *skb, u8 cmd)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	void *hdr;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
264*4882a593Smuzhiyun 	if (!hdr)
265*4882a593Smuzhiyun 		return -ENOMEM;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (__seg6_hmac_fill_info(hinfo, skb) < 0)
268*4882a593Smuzhiyun 		goto nla_put_failure;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	genlmsg_end(skb, hdr);
271*4882a593Smuzhiyun 	return 0;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun nla_put_failure:
274*4882a593Smuzhiyun 	genlmsg_cancel(skb, hdr);
275*4882a593Smuzhiyun 	return -EMSGSIZE;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
seg6_genl_dumphmac_start(struct netlink_callback * cb)278*4882a593Smuzhiyun static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	struct net *net = sock_net(cb->skb->sk);
281*4882a593Smuzhiyun 	struct seg6_pernet_data *sdata;
282*4882a593Smuzhiyun 	struct rhashtable_iter *iter;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	sdata = seg6_pernet(net);
285*4882a593Smuzhiyun 	iter = (struct rhashtable_iter *)cb->args[0];
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	if (!iter) {
288*4882a593Smuzhiyun 		iter = kmalloc(sizeof(*iter), GFP_KERNEL);
289*4882a593Smuzhiyun 		if (!iter)
290*4882a593Smuzhiyun 			return -ENOMEM;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 		cb->args[0] = (long)iter;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	rhashtable_walk_enter(&sdata->hmac_infos, iter);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return 0;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
seg6_genl_dumphmac_done(struct netlink_callback * cb)300*4882a593Smuzhiyun static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	rhashtable_walk_exit(iter);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	kfree(iter);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return 0;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
seg6_genl_dumphmac(struct sk_buff * skb,struct netlink_callback * cb)311*4882a593Smuzhiyun static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
314*4882a593Smuzhiyun 	struct seg6_hmac_info *hinfo;
315*4882a593Smuzhiyun 	int ret;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	rhashtable_walk_start(iter);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	for (;;) {
320*4882a593Smuzhiyun 		hinfo = rhashtable_walk_next(iter);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 		if (IS_ERR(hinfo)) {
323*4882a593Smuzhiyun 			if (PTR_ERR(hinfo) == -EAGAIN)
324*4882a593Smuzhiyun 				continue;
325*4882a593Smuzhiyun 			ret = PTR_ERR(hinfo);
326*4882a593Smuzhiyun 			goto done;
327*4882a593Smuzhiyun 		} else if (!hinfo) {
328*4882a593Smuzhiyun 			break;
329*4882a593Smuzhiyun 		}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 		ret = __seg6_genl_dumphmac_element(hinfo,
332*4882a593Smuzhiyun 						   NETLINK_CB(cb->skb).portid,
333*4882a593Smuzhiyun 						   cb->nlh->nlmsg_seq,
334*4882a593Smuzhiyun 						   NLM_F_MULTI,
335*4882a593Smuzhiyun 						   skb, SEG6_CMD_DUMPHMAC);
336*4882a593Smuzhiyun 		if (ret)
337*4882a593Smuzhiyun 			goto done;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	ret = skb->len;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun done:
343*4882a593Smuzhiyun 	rhashtable_walk_stop(iter);
344*4882a593Smuzhiyun 	return ret;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun #else
348*4882a593Smuzhiyun 
seg6_genl_dumphmac_start(struct netlink_callback * cb)349*4882a593Smuzhiyun static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	return 0;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
seg6_genl_dumphmac_done(struct netlink_callback * cb)354*4882a593Smuzhiyun static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	return 0;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
seg6_genl_dumphmac(struct sk_buff * skb,struct netlink_callback * cb)359*4882a593Smuzhiyun static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	return -ENOTSUPP;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun #endif
365*4882a593Smuzhiyun 
seg6_net_init(struct net * net)366*4882a593Smuzhiyun static int __net_init seg6_net_init(struct net *net)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	struct seg6_pernet_data *sdata;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	sdata = kzalloc(sizeof(*sdata), GFP_KERNEL);
371*4882a593Smuzhiyun 	if (!sdata)
372*4882a593Smuzhiyun 		return -ENOMEM;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	mutex_init(&sdata->lock);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	sdata->tun_src = kzalloc(sizeof(*sdata->tun_src), GFP_KERNEL);
377*4882a593Smuzhiyun 	if (!sdata->tun_src) {
378*4882a593Smuzhiyun 		kfree(sdata);
379*4882a593Smuzhiyun 		return -ENOMEM;
380*4882a593Smuzhiyun 	}
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	net->ipv6.seg6_data = sdata;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
385*4882a593Smuzhiyun 	seg6_hmac_net_init(net);
386*4882a593Smuzhiyun #endif
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	return 0;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
seg6_net_exit(struct net * net)391*4882a593Smuzhiyun static void __net_exit seg6_net_exit(struct net *net)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	struct seg6_pernet_data *sdata = seg6_pernet(net);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
396*4882a593Smuzhiyun 	seg6_hmac_net_exit(net);
397*4882a593Smuzhiyun #endif
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	kfree(sdata->tun_src);
400*4882a593Smuzhiyun 	kfree(sdata);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun static struct pernet_operations ip6_segments_ops = {
404*4882a593Smuzhiyun 	.init = seg6_net_init,
405*4882a593Smuzhiyun 	.exit = seg6_net_exit,
406*4882a593Smuzhiyun };
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun static const struct genl_ops seg6_genl_ops[] = {
409*4882a593Smuzhiyun 	{
410*4882a593Smuzhiyun 		.cmd	= SEG6_CMD_SETHMAC,
411*4882a593Smuzhiyun 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
412*4882a593Smuzhiyun 		.doit	= seg6_genl_sethmac,
413*4882a593Smuzhiyun 		.flags	= GENL_ADMIN_PERM,
414*4882a593Smuzhiyun 	},
415*4882a593Smuzhiyun 	{
416*4882a593Smuzhiyun 		.cmd	= SEG6_CMD_DUMPHMAC,
417*4882a593Smuzhiyun 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
418*4882a593Smuzhiyun 		.start	= seg6_genl_dumphmac_start,
419*4882a593Smuzhiyun 		.dumpit	= seg6_genl_dumphmac,
420*4882a593Smuzhiyun 		.done	= seg6_genl_dumphmac_done,
421*4882a593Smuzhiyun 		.flags	= GENL_ADMIN_PERM,
422*4882a593Smuzhiyun 	},
423*4882a593Smuzhiyun 	{
424*4882a593Smuzhiyun 		.cmd	= SEG6_CMD_SET_TUNSRC,
425*4882a593Smuzhiyun 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
426*4882a593Smuzhiyun 		.doit	= seg6_genl_set_tunsrc,
427*4882a593Smuzhiyun 		.flags	= GENL_ADMIN_PERM,
428*4882a593Smuzhiyun 	},
429*4882a593Smuzhiyun 	{
430*4882a593Smuzhiyun 		.cmd	= SEG6_CMD_GET_TUNSRC,
431*4882a593Smuzhiyun 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
432*4882a593Smuzhiyun 		.doit	= seg6_genl_get_tunsrc,
433*4882a593Smuzhiyun 		.flags	= GENL_ADMIN_PERM,
434*4882a593Smuzhiyun 	},
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun static struct genl_family seg6_genl_family __ro_after_init = {
438*4882a593Smuzhiyun 	.hdrsize	= 0,
439*4882a593Smuzhiyun 	.name		= SEG6_GENL_NAME,
440*4882a593Smuzhiyun 	.version	= SEG6_GENL_VERSION,
441*4882a593Smuzhiyun 	.maxattr	= SEG6_ATTR_MAX,
442*4882a593Smuzhiyun 	.policy = seg6_genl_policy,
443*4882a593Smuzhiyun 	.netnsok	= true,
444*4882a593Smuzhiyun 	.parallel_ops	= true,
445*4882a593Smuzhiyun 	.ops		= seg6_genl_ops,
446*4882a593Smuzhiyun 	.n_ops		= ARRAY_SIZE(seg6_genl_ops),
447*4882a593Smuzhiyun 	.module		= THIS_MODULE,
448*4882a593Smuzhiyun };
449*4882a593Smuzhiyun 
seg6_init(void)450*4882a593Smuzhiyun int __init seg6_init(void)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	int err;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	err = genl_register_family(&seg6_genl_family);
455*4882a593Smuzhiyun 	if (err)
456*4882a593Smuzhiyun 		goto out;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	err = register_pernet_subsys(&ip6_segments_ops);
459*4882a593Smuzhiyun 	if (err)
460*4882a593Smuzhiyun 		goto out_unregister_genl;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
463*4882a593Smuzhiyun 	err = seg6_iptunnel_init();
464*4882a593Smuzhiyun 	if (err)
465*4882a593Smuzhiyun 		goto out_unregister_pernet;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	err = seg6_local_init();
468*4882a593Smuzhiyun 	if (err)
469*4882a593Smuzhiyun 		goto out_unregister_pernet;
470*4882a593Smuzhiyun #endif
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
473*4882a593Smuzhiyun 	err = seg6_hmac_init();
474*4882a593Smuzhiyun 	if (err)
475*4882a593Smuzhiyun 		goto out_unregister_iptun;
476*4882a593Smuzhiyun #endif
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	pr_info("Segment Routing with IPv6\n");
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun out:
481*4882a593Smuzhiyun 	return err;
482*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
483*4882a593Smuzhiyun out_unregister_iptun:
484*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
485*4882a593Smuzhiyun 	seg6_local_exit();
486*4882a593Smuzhiyun 	seg6_iptunnel_exit();
487*4882a593Smuzhiyun #endif
488*4882a593Smuzhiyun #endif
489*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
490*4882a593Smuzhiyun out_unregister_pernet:
491*4882a593Smuzhiyun 	unregister_pernet_subsys(&ip6_segments_ops);
492*4882a593Smuzhiyun #endif
493*4882a593Smuzhiyun out_unregister_genl:
494*4882a593Smuzhiyun 	genl_unregister_family(&seg6_genl_family);
495*4882a593Smuzhiyun 	goto out;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
seg6_exit(void)498*4882a593Smuzhiyun void seg6_exit(void)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_HMAC
501*4882a593Smuzhiyun 	seg6_hmac_exit();
502*4882a593Smuzhiyun #endif
503*4882a593Smuzhiyun #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
504*4882a593Smuzhiyun 	seg6_iptunnel_exit();
505*4882a593Smuzhiyun #endif
506*4882a593Smuzhiyun 	unregister_pernet_subsys(&ip6_segments_ops);
507*4882a593Smuzhiyun 	genl_unregister_family(&seg6_genl_family);
508*4882a593Smuzhiyun }
509