Commit 94a6d9fb authored by Taehee Yoo's avatar Taehee Yoo Committed by Jakub Kicinski

gtp: fix wrong condition in gtp_genl_dump_pdp()

gtp_genl_dump_pdp() is ->dumpit() callback of GTP module and it is used
to dump pdp contexts. it would be re-executed because of dump packet size.

If dump packet size is too big, it saves current dump pointer
(gtp interface pointer, bucket, TID value) then it restarts dump from
last pointer.
Current GTP code allows adding zero TID pdp context but dump code
ignores zero TID value. So, last dump pointer will not be found.

In addition, this patch adds missing rcu_read_lock() in
gtp_genl_dump_pdp().

Fixes: 459aa660 ("gtp: add initial driver for datapath of GPRS Tunneling Protocol (GTP-U)")
Signed-off-by: default avatarTaehee Yoo <ap420073@gmail.com>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
parent 6b01b1d9
...@@ -38,7 +38,6 @@ struct pdp_ctx { ...@@ -38,7 +38,6 @@ struct pdp_ctx {
struct hlist_node hlist_addr; struct hlist_node hlist_addr;
union { union {
u64 tid;
struct { struct {
u64 tid; u64 tid;
u16 flow; u16 flow;
...@@ -1244,43 +1243,46 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb, ...@@ -1244,43 +1243,46 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb,
struct netlink_callback *cb) struct netlink_callback *cb)
{ {
struct gtp_dev *last_gtp = (struct gtp_dev *)cb->args[2], *gtp; struct gtp_dev *last_gtp = (struct gtp_dev *)cb->args[2], *gtp;
int i, j, bucket = cb->args[0], skip = cb->args[1];
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct gtp_net *gn = net_generic(net, gtp_net_id);
unsigned long tid = cb->args[1];
int i, k = cb->args[0], ret;
struct pdp_ctx *pctx; struct pdp_ctx *pctx;
struct gtp_net *gn;
gn = net_generic(net, gtp_net_id);
if (cb->args[4]) if (cb->args[4])
return 0; return 0;
rcu_read_lock();
list_for_each_entry_rcu(gtp, &gn->gtp_dev_list, list) { list_for_each_entry_rcu(gtp, &gn->gtp_dev_list, list) {
if (last_gtp && last_gtp != gtp) if (last_gtp && last_gtp != gtp)
continue; continue;
else else
last_gtp = NULL; last_gtp = NULL;
for (i = k; i < gtp->hash_size; i++) { for (i = bucket; i < gtp->hash_size; i++) {
hlist_for_each_entry_rcu(pctx, &gtp->tid_hash[i], hlist_tid) { j = 0;
if (tid && tid != pctx->u.tid) hlist_for_each_entry_rcu(pctx, &gtp->tid_hash[i],
continue; hlist_tid) {
else if (j >= skip &&
tid = 0; gtp_genl_fill_info(skb,
NETLINK_CB(cb->skb).portid,
ret = gtp_genl_fill_info(skb, cb->nlh->nlmsg_seq,
NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_type, pctx)) {
cb->nlh->nlmsg_seq,
cb->nlh->nlmsg_type, pctx);
if (ret < 0) {
cb->args[0] = i; cb->args[0] = i;
cb->args[1] = pctx->u.tid; cb->args[1] = j;
cb->args[2] = (unsigned long)gtp; cb->args[2] = (unsigned long)gtp;
goto out; goto out;
} }
j++;
} }
skip = 0;
} }
bucket = 0;
} }
cb->args[4] = 1; cb->args[4] = 1;
out: out:
rcu_read_unlock();
return skb->len; return skb->len;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment