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