| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* GTP according to GSM TS 09.60 / 3GPP TS 29.060 |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * (C) 2012-2014 by sysmocom - s.f.m.c. GmbH |
|---|
| .. | .. |
|---|
| 6 | 7 | * Author: Harald Welte <hwelte@sysmocom.de> |
|---|
| 7 | 8 | * Pablo Neira Ayuso <pablo@netfilter.org> |
|---|
| 8 | 9 | * Andreas Schultz <aschultz@travelping.com> |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public License |
|---|
| 12 | | - * as published by the Free Software Foundation; either version |
|---|
| 13 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 14 | 10 | */ |
|---|
| 15 | 11 | |
|---|
| 16 | 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 186 | 182 | static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, |
|---|
| 187 | 183 | unsigned int hdrlen, unsigned int role) |
|---|
| 188 | 184 | { |
|---|
| 189 | | - struct pcpu_sw_netstats *stats; |
|---|
| 190 | | - |
|---|
| 191 | 185 | if (!gtp_check_ms(skb, pctx, hdrlen, role)) { |
|---|
| 192 | 186 | netdev_dbg(pctx->dev, "No PDP ctx for this MS\n"); |
|---|
| 193 | 187 | return 1; |
|---|
| .. | .. |
|---|
| 208 | 202 | |
|---|
| 209 | 203 | skb->dev = pctx->dev; |
|---|
| 210 | 204 | |
|---|
| 211 | | - stats = this_cpu_ptr(pctx->dev->tstats); |
|---|
| 212 | | - u64_stats_update_begin(&stats->syncp); |
|---|
| 213 | | - stats->rx_packets++; |
|---|
| 214 | | - stats->rx_bytes += skb->len; |
|---|
| 215 | | - u64_stats_update_end(&stats->syncp); |
|---|
| 205 | + dev_sw_netstats_rx_add(pctx->dev, skb->len); |
|---|
| 216 | 206 | |
|---|
| 217 | 207 | netif_rx(skb); |
|---|
| 218 | 208 | return 0; |
|---|
| .. | .. |
|---|
| 301 | 291 | gtp->sk1u = NULL; |
|---|
| 302 | 292 | udp_sk(sk)->encap_type = 0; |
|---|
| 303 | 293 | rcu_assign_sk_user_data(sk, NULL); |
|---|
| 294 | + release_sock(sk); |
|---|
| 304 | 295 | sock_put(sk); |
|---|
| 296 | + return; |
|---|
| 305 | 297 | } |
|---|
| 306 | 298 | release_sock(sk); |
|---|
| 307 | 299 | } |
|---|
| .. | .. |
|---|
| 714 | 706 | hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) |
|---|
| 715 | 707 | pdp_context_delete(pctx); |
|---|
| 716 | 708 | |
|---|
| 717 | | - gtp_encap_disable(gtp); |
|---|
| 718 | 709 | list_del_rcu(>p->list); |
|---|
| 719 | 710 | unregister_netdevice_queue(dev, head); |
|---|
| 720 | 711 | } |
|---|
| .. | .. |
|---|
| 858 | 849 | |
|---|
| 859 | 850 | sk1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp); |
|---|
| 860 | 851 | if (IS_ERR(sk1u)) { |
|---|
| 861 | | - if (sk0) |
|---|
| 862 | | - gtp_encap_disable_sock(sk0); |
|---|
| 852 | + gtp_encap_disable_sock(sk0); |
|---|
| 863 | 853 | return PTR_ERR(sk1u); |
|---|
| 864 | 854 | } |
|---|
| 865 | 855 | } |
|---|
| .. | .. |
|---|
| 867 | 857 | if (data[IFLA_GTP_ROLE]) { |
|---|
| 868 | 858 | role = nla_get_u32(data[IFLA_GTP_ROLE]); |
|---|
| 869 | 859 | if (role > GTP_ROLE_SGSN) { |
|---|
| 870 | | - if (sk0) |
|---|
| 871 | | - gtp_encap_disable_sock(sk0); |
|---|
| 872 | | - if (sk1u) |
|---|
| 873 | | - gtp_encap_disable_sock(sk1u); |
|---|
| 860 | + gtp_encap_disable_sock(sk0); |
|---|
| 861 | + gtp_encap_disable_sock(sk1u); |
|---|
| 874 | 862 | return -EINVAL; |
|---|
| 875 | 863 | } |
|---|
| 876 | 864 | } |
|---|
| .. | .. |
|---|
| 935 | 923 | } |
|---|
| 936 | 924 | } |
|---|
| 937 | 925 | |
|---|
| 938 | | -static int gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, |
|---|
| 939 | | - struct genl_info *info) |
|---|
| 926 | +static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, |
|---|
| 927 | + struct genl_info *info) |
|---|
| 940 | 928 | { |
|---|
| 941 | 929 | struct pdp_ctx *pctx, *pctx_tid = NULL; |
|---|
| 942 | 930 | struct net_device *dev = gtp->dev; |
|---|
| .. | .. |
|---|
| 963 | 951 | |
|---|
| 964 | 952 | if (found) { |
|---|
| 965 | 953 | if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) |
|---|
| 966 | | - return -EEXIST; |
|---|
| 954 | + return ERR_PTR(-EEXIST); |
|---|
| 967 | 955 | if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE) |
|---|
| 968 | | - return -EOPNOTSUPP; |
|---|
| 956 | + return ERR_PTR(-EOPNOTSUPP); |
|---|
| 969 | 957 | |
|---|
| 970 | 958 | if (pctx && pctx_tid) |
|---|
| 971 | | - return -EEXIST; |
|---|
| 959 | + return ERR_PTR(-EEXIST); |
|---|
| 972 | 960 | if (!pctx) |
|---|
| 973 | 961 | pctx = pctx_tid; |
|---|
| 974 | 962 | |
|---|
| .. | .. |
|---|
| 981 | 969 | netdev_dbg(dev, "GTPv1-U: update tunnel id = %x/%x (pdp %p)\n", |
|---|
| 982 | 970 | pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx); |
|---|
| 983 | 971 | |
|---|
| 984 | | - return 0; |
|---|
| 972 | + return pctx; |
|---|
| 985 | 973 | |
|---|
| 986 | 974 | } |
|---|
| 987 | 975 | |
|---|
| 988 | 976 | pctx = kmalloc(sizeof(*pctx), GFP_ATOMIC); |
|---|
| 989 | 977 | if (pctx == NULL) |
|---|
| 990 | | - return -ENOMEM; |
|---|
| 978 | + return ERR_PTR(-ENOMEM); |
|---|
| 991 | 979 | |
|---|
| 992 | 980 | sock_hold(sk); |
|---|
| 993 | 981 | pctx->sk = sk; |
|---|
| .. | .. |
|---|
| 1025 | 1013 | break; |
|---|
| 1026 | 1014 | } |
|---|
| 1027 | 1015 | |
|---|
| 1028 | | - return 0; |
|---|
| 1016 | + return pctx; |
|---|
| 1029 | 1017 | } |
|---|
| 1030 | 1018 | |
|---|
| 1031 | 1019 | static void pdp_context_free(struct rcu_head *head) |
|---|
| .. | .. |
|---|
| 1043 | 1031 | call_rcu(&pctx->rcu_head, pdp_context_free); |
|---|
| 1044 | 1032 | } |
|---|
| 1045 | 1033 | |
|---|
| 1034 | +static int gtp_tunnel_notify(struct pdp_ctx *pctx, u8 cmd, gfp_t allocation); |
|---|
| 1035 | + |
|---|
| 1046 | 1036 | static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) |
|---|
| 1047 | 1037 | { |
|---|
| 1048 | 1038 | unsigned int version; |
|---|
| 1039 | + struct pdp_ctx *pctx; |
|---|
| 1049 | 1040 | struct gtp_dev *gtp; |
|---|
| 1050 | 1041 | struct sock *sk; |
|---|
| 1051 | 1042 | int err; |
|---|
| .. | .. |
|---|
| 1075 | 1066 | } |
|---|
| 1076 | 1067 | |
|---|
| 1077 | 1068 | rtnl_lock(); |
|---|
| 1078 | | - rcu_read_lock(); |
|---|
| 1079 | 1069 | |
|---|
| 1080 | 1070 | gtp = gtp_find_dev(sock_net(skb->sk), info->attrs); |
|---|
| 1081 | 1071 | if (!gtp) { |
|---|
| .. | .. |
|---|
| 1095 | 1085 | goto out_unlock; |
|---|
| 1096 | 1086 | } |
|---|
| 1097 | 1087 | |
|---|
| 1098 | | - err = gtp_pdp_add(gtp, sk, info); |
|---|
| 1088 | + pctx = gtp_pdp_add(gtp, sk, info); |
|---|
| 1089 | + if (IS_ERR(pctx)) { |
|---|
| 1090 | + err = PTR_ERR(pctx); |
|---|
| 1091 | + } else { |
|---|
| 1092 | + gtp_tunnel_notify(pctx, GTP_CMD_NEWPDP, GFP_KERNEL); |
|---|
| 1093 | + err = 0; |
|---|
| 1094 | + } |
|---|
| 1099 | 1095 | |
|---|
| 1100 | 1096 | out_unlock: |
|---|
| 1101 | | - rcu_read_unlock(); |
|---|
| 1102 | 1097 | rtnl_unlock(); |
|---|
| 1103 | 1098 | return err; |
|---|
| 1104 | 1099 | } |
|---|
| .. | .. |
|---|
| 1166 | 1161 | netdev_dbg(pctx->dev, "GTPv1-U: deleting tunnel id = %x/%x (pdp %p)\n", |
|---|
| 1167 | 1162 | pctx->u.v1.i_tei, pctx->u.v1.o_tei, pctx); |
|---|
| 1168 | 1163 | |
|---|
| 1164 | + gtp_tunnel_notify(pctx, GTP_CMD_DELPDP, GFP_ATOMIC); |
|---|
| 1169 | 1165 | pdp_context_delete(pctx); |
|---|
| 1170 | 1166 | |
|---|
| 1171 | 1167 | out_unlock: |
|---|
| .. | .. |
|---|
| 1174 | 1170 | } |
|---|
| 1175 | 1171 | |
|---|
| 1176 | 1172 | static struct genl_family gtp_genl_family; |
|---|
| 1173 | + |
|---|
| 1174 | +enum gtp_multicast_groups { |
|---|
| 1175 | + GTP_GENL_MCGRP, |
|---|
| 1176 | +}; |
|---|
| 1177 | + |
|---|
| 1178 | +static const struct genl_multicast_group gtp_genl_mcgrps[] = { |
|---|
| 1179 | + [GTP_GENL_MCGRP] = { .name = GTP_GENL_MCGRP_NAME }, |
|---|
| 1180 | +}; |
|---|
| 1177 | 1181 | |
|---|
| 1178 | 1182 | static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, |
|---|
| 1179 | 1183 | int flags, u32 type, struct pdp_ctx *pctx) |
|---|
| .. | .. |
|---|
| 1210 | 1214 | nla_put_failure: |
|---|
| 1211 | 1215 | genlmsg_cancel(skb, genlh); |
|---|
| 1212 | 1216 | return -EMSGSIZE; |
|---|
| 1217 | +} |
|---|
| 1218 | + |
|---|
| 1219 | +static int gtp_tunnel_notify(struct pdp_ctx *pctx, u8 cmd, gfp_t allocation) |
|---|
| 1220 | +{ |
|---|
| 1221 | + struct sk_buff *msg; |
|---|
| 1222 | + int ret; |
|---|
| 1223 | + |
|---|
| 1224 | + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, allocation); |
|---|
| 1225 | + if (!msg) |
|---|
| 1226 | + return -ENOMEM; |
|---|
| 1227 | + |
|---|
| 1228 | + ret = gtp_genl_fill_info(msg, 0, 0, 0, cmd, pctx); |
|---|
| 1229 | + if (ret < 0) { |
|---|
| 1230 | + nlmsg_free(msg); |
|---|
| 1231 | + return ret; |
|---|
| 1232 | + } |
|---|
| 1233 | + |
|---|
| 1234 | + ret = genlmsg_multicast_netns(>p_genl_family, dev_net(pctx->dev), msg, |
|---|
| 1235 | + 0, GTP_GENL_MCGRP, GFP_ATOMIC); |
|---|
| 1236 | + return ret; |
|---|
| 1213 | 1237 | } |
|---|
| 1214 | 1238 | |
|---|
| 1215 | 1239 | static int gtp_genl_get_pdp(struct sk_buff *skb, struct genl_info *info) |
|---|
| .. | .. |
|---|
| 1310 | 1334 | [GTPA_O_TEI] = { .type = NLA_U32, }, |
|---|
| 1311 | 1335 | }; |
|---|
| 1312 | 1336 | |
|---|
| 1313 | | -static const struct genl_ops gtp_genl_ops[] = { |
|---|
| 1337 | +static const struct genl_small_ops gtp_genl_ops[] = { |
|---|
| 1314 | 1338 | { |
|---|
| 1315 | 1339 | .cmd = GTP_CMD_NEWPDP, |
|---|
| 1340 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 1316 | 1341 | .doit = gtp_genl_new_pdp, |
|---|
| 1317 | | - .policy = gtp_genl_policy, |
|---|
| 1318 | 1342 | .flags = GENL_ADMIN_PERM, |
|---|
| 1319 | 1343 | }, |
|---|
| 1320 | 1344 | { |
|---|
| 1321 | 1345 | .cmd = GTP_CMD_DELPDP, |
|---|
| 1346 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 1322 | 1347 | .doit = gtp_genl_del_pdp, |
|---|
| 1323 | | - .policy = gtp_genl_policy, |
|---|
| 1324 | 1348 | .flags = GENL_ADMIN_PERM, |
|---|
| 1325 | 1349 | }, |
|---|
| 1326 | 1350 | { |
|---|
| 1327 | 1351 | .cmd = GTP_CMD_GETPDP, |
|---|
| 1352 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 1328 | 1353 | .doit = gtp_genl_get_pdp, |
|---|
| 1329 | 1354 | .dumpit = gtp_genl_dump_pdp, |
|---|
| 1330 | | - .policy = gtp_genl_policy, |
|---|
| 1331 | 1355 | .flags = GENL_ADMIN_PERM, |
|---|
| 1332 | 1356 | }, |
|---|
| 1333 | 1357 | }; |
|---|
| .. | .. |
|---|
| 1337 | 1361 | .version = 0, |
|---|
| 1338 | 1362 | .hdrsize = 0, |
|---|
| 1339 | 1363 | .maxattr = GTPA_MAX, |
|---|
| 1364 | + .policy = gtp_genl_policy, |
|---|
| 1340 | 1365 | .netnsok = true, |
|---|
| 1341 | 1366 | .module = THIS_MODULE, |
|---|
| 1342 | | - .ops = gtp_genl_ops, |
|---|
| 1343 | | - .n_ops = ARRAY_SIZE(gtp_genl_ops), |
|---|
| 1367 | + .small_ops = gtp_genl_ops, |
|---|
| 1368 | + .n_small_ops = ARRAY_SIZE(gtp_genl_ops), |
|---|
| 1369 | + .mcgrps = gtp_genl_mcgrps, |
|---|
| 1370 | + .n_mcgrps = ARRAY_SIZE(gtp_genl_mcgrps), |
|---|
| 1344 | 1371 | }; |
|---|
| 1345 | 1372 | |
|---|
| 1346 | 1373 | static int __net_init gtp_net_init(struct net *net) |
|---|