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