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