diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 55 |
1 files changed, 46 insertions, 9 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a4957bf2ca60..a2eb965207d3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -455,9 +455,14 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
| 455 | if (nl_table[protocol].registered && | 455 | if (nl_table[protocol].registered && |
| 456 | try_module_get(nl_table[protocol].module)) | 456 | try_module_get(nl_table[protocol].module)) |
| 457 | module = nl_table[protocol].module; | 457 | module = nl_table[protocol].module; |
| 458 | else | ||
| 459 | err = -EPROTONOSUPPORT; | ||
| 458 | cb_mutex = nl_table[protocol].cb_mutex; | 460 | cb_mutex = nl_table[protocol].cb_mutex; |
| 459 | netlink_unlock_table(); | 461 | netlink_unlock_table(); |
| 460 | 462 | ||
| 463 | if (err < 0) | ||
| 464 | goto out; | ||
| 465 | |||
| 461 | err = __netlink_create(net, sock, cb_mutex, protocol); | 466 | err = __netlink_create(net, sock, cb_mutex, protocol); |
| 462 | if (err < 0) | 467 | if (err < 0) |
| 463 | goto out_module; | 468 | goto out_module; |
| @@ -540,7 +545,7 @@ static int netlink_autobind(struct socket *sock) | |||
| 540 | struct hlist_head *head; | 545 | struct hlist_head *head; |
| 541 | struct sock *osk; | 546 | struct sock *osk; |
| 542 | struct hlist_node *node; | 547 | struct hlist_node *node; |
| 543 | s32 pid = current->tgid; | 548 | s32 pid = task_tgid_vnr(current); |
| 544 | int err; | 549 | int err; |
| 545 | static s32 rover = -4097; | 550 | static s32 rover = -4097; |
| 546 | 551 | ||
| @@ -678,6 +683,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, | |||
| 678 | struct netlink_sock *nlk = nlk_sk(sk); | 683 | struct netlink_sock *nlk = nlk_sk(sk); |
| 679 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 684 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
| 680 | 685 | ||
| 686 | if (alen < sizeof(addr->sa_family)) | ||
| 687 | return -EINVAL; | ||
| 688 | |||
| 681 | if (addr->sa_family == AF_UNSPEC) { | 689 | if (addr->sa_family == AF_UNSPEC) { |
| 682 | sk->sk_state = NETLINK_UNCONNECTED; | 690 | sk->sk_state = NETLINK_UNCONNECTED; |
| 683 | nlk->dst_pid = 0; | 691 | nlk->dst_pid = 0; |
| @@ -970,6 +978,8 @@ struct netlink_broadcast_data { | |||
| 970 | int delivered; | 978 | int delivered; |
| 971 | gfp_t allocation; | 979 | gfp_t allocation; |
| 972 | struct sk_buff *skb, *skb2; | 980 | struct sk_buff *skb, *skb2; |
| 981 | int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data); | ||
| 982 | void *tx_data; | ||
| 973 | }; | 983 | }; |
| 974 | 984 | ||
| 975 | static inline int do_one_broadcast(struct sock *sk, | 985 | static inline int do_one_broadcast(struct sock *sk, |
| @@ -1012,6 +1022,9 @@ static inline int do_one_broadcast(struct sock *sk, | |||
| 1012 | p->failure = 1; | 1022 | p->failure = 1; |
| 1013 | if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR) | 1023 | if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR) |
| 1014 | p->delivery_failure = 1; | 1024 | p->delivery_failure = 1; |
| 1025 | } else if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { | ||
| 1026 | kfree_skb(p->skb2); | ||
| 1027 | p->skb2 = NULL; | ||
| 1015 | } else if (sk_filter(sk, p->skb2)) { | 1028 | } else if (sk_filter(sk, p->skb2)) { |
| 1016 | kfree_skb(p->skb2); | 1029 | kfree_skb(p->skb2); |
| 1017 | p->skb2 = NULL; | 1030 | p->skb2 = NULL; |
| @@ -1030,8 +1043,10 @@ out: | |||
| 1030 | return 0; | 1043 | return 0; |
| 1031 | } | 1044 | } |
| 1032 | 1045 | ||
| 1033 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | 1046 | int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid, |
| 1034 | u32 group, gfp_t allocation) | 1047 | u32 group, gfp_t allocation, |
| 1048 | int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data), | ||
| 1049 | void *filter_data) | ||
| 1035 | { | 1050 | { |
| 1036 | struct net *net = sock_net(ssk); | 1051 | struct net *net = sock_net(ssk); |
| 1037 | struct netlink_broadcast_data info; | 1052 | struct netlink_broadcast_data info; |
| @@ -1051,6 +1066,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | |||
| 1051 | info.allocation = allocation; | 1066 | info.allocation = allocation; |
| 1052 | info.skb = skb; | 1067 | info.skb = skb; |
| 1053 | info.skb2 = NULL; | 1068 | info.skb2 = NULL; |
| 1069 | info.tx_filter = filter; | ||
| 1070 | info.tx_data = filter_data; | ||
| 1054 | 1071 | ||
| 1055 | /* While we sleep in clone, do not allow to change socket list */ | 1072 | /* While we sleep in clone, do not allow to change socket list */ |
| 1056 | 1073 | ||
| @@ -1075,6 +1092,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | |||
| 1075 | } | 1092 | } |
| 1076 | return -ESRCH; | 1093 | return -ESRCH; |
| 1077 | } | 1094 | } |
| 1095 | EXPORT_SYMBOL(netlink_broadcast_filtered); | ||
| 1096 | |||
| 1097 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | ||
| 1098 | u32 group, gfp_t allocation) | ||
| 1099 | { | ||
| 1100 | return netlink_broadcast_filtered(ssk, skb, pid, group, allocation, | ||
| 1101 | NULL, NULL); | ||
| 1102 | } | ||
| 1078 | EXPORT_SYMBOL(netlink_broadcast); | 1103 | EXPORT_SYMBOL(netlink_broadcast); |
| 1079 | 1104 | ||
| 1080 | struct netlink_set_err_data { | 1105 | struct netlink_set_err_data { |
| @@ -1088,6 +1113,7 @@ static inline int do_one_set_err(struct sock *sk, | |||
| 1088 | struct netlink_set_err_data *p) | 1113 | struct netlink_set_err_data *p) |
| 1089 | { | 1114 | { |
| 1090 | struct netlink_sock *nlk = nlk_sk(sk); | 1115 | struct netlink_sock *nlk = nlk_sk(sk); |
| 1116 | int ret = 0; | ||
| 1091 | 1117 | ||
| 1092 | if (sk == p->exclude_sk) | 1118 | if (sk == p->exclude_sk) |
| 1093 | goto out; | 1119 | goto out; |
| @@ -1099,10 +1125,15 @@ static inline int do_one_set_err(struct sock *sk, | |||
| 1099 | !test_bit(p->group - 1, nlk->groups)) | 1125 | !test_bit(p->group - 1, nlk->groups)) |
| 1100 | goto out; | 1126 | goto out; |
| 1101 | 1127 | ||
| 1128 | if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) { | ||
| 1129 | ret = 1; | ||
| 1130 | goto out; | ||
| 1131 | } | ||
| 1132 | |||
| 1102 | sk->sk_err = p->code; | 1133 | sk->sk_err = p->code; |
| 1103 | sk->sk_error_report(sk); | 1134 | sk->sk_error_report(sk); |
| 1104 | out: | 1135 | out: |
| 1105 | return 0; | 1136 | return ret; |
| 1106 | } | 1137 | } |
| 1107 | 1138 | ||
| 1108 | /** | 1139 | /** |
| @@ -1111,12 +1142,16 @@ out: | |||
| 1111 | * @pid: the PID of a process that we want to skip (if any) | 1142 | * @pid: the PID of a process that we want to skip (if any) |
| 1112 | * @groups: the broadcast group that will notice the error | 1143 | * @groups: the broadcast group that will notice the error |
| 1113 | * @code: error code, must be negative (as usual in kernelspace) | 1144 | * @code: error code, must be negative (as usual in kernelspace) |
| 1145 | * | ||
| 1146 | * This function returns the number of broadcast listeners that have set the | ||
| 1147 | * NETLINK_RECV_NO_ENOBUFS socket option. | ||
| 1114 | */ | 1148 | */ |
| 1115 | void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | 1149 | int netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) |
| 1116 | { | 1150 | { |
| 1117 | struct netlink_set_err_data info; | 1151 | struct netlink_set_err_data info; |
| 1118 | struct hlist_node *node; | 1152 | struct hlist_node *node; |
| 1119 | struct sock *sk; | 1153 | struct sock *sk; |
| 1154 | int ret = 0; | ||
| 1120 | 1155 | ||
| 1121 | info.exclude_sk = ssk; | 1156 | info.exclude_sk = ssk; |
| 1122 | info.pid = pid; | 1157 | info.pid = pid; |
| @@ -1127,9 +1162,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | |||
| 1127 | read_lock(&nl_table_lock); | 1162 | read_lock(&nl_table_lock); |
| 1128 | 1163 | ||
| 1129 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) | 1164 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) |
| 1130 | do_one_set_err(sk, &info); | 1165 | ret += do_one_set_err(sk, &info); |
| 1131 | 1166 | ||
| 1132 | read_unlock(&nl_table_lock); | 1167 | read_unlock(&nl_table_lock); |
| 1168 | return ret; | ||
| 1133 | } | 1169 | } |
| 1134 | EXPORT_SYMBOL(netlink_set_err); | 1170 | EXPORT_SYMBOL(netlink_set_err); |
| 1135 | 1171 | ||
| @@ -1973,12 +2009,12 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
| 1973 | if (v == SEQ_START_TOKEN) | 2009 | if (v == SEQ_START_TOKEN) |
| 1974 | seq_puts(seq, | 2010 | seq_puts(seq, |
| 1975 | "sk Eth Pid Groups " | 2011 | "sk Eth Pid Groups " |
| 1976 | "Rmem Wmem Dump Locks Drops\n"); | 2012 | "Rmem Wmem Dump Locks Drops Inode\n"); |
| 1977 | else { | 2013 | else { |
| 1978 | struct sock *s = v; | 2014 | struct sock *s = v; |
| 1979 | struct netlink_sock *nlk = nlk_sk(s); | 2015 | struct netlink_sock *nlk = nlk_sk(s); |
| 1980 | 2016 | ||
| 1981 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d\n", | 2017 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d %-8lu\n", |
| 1982 | s, | 2018 | s, |
| 1983 | s->sk_protocol, | 2019 | s->sk_protocol, |
| 1984 | nlk->pid, | 2020 | nlk->pid, |
| @@ -1987,7 +2023,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
| 1987 | sk_wmem_alloc_get(s), | 2023 | sk_wmem_alloc_get(s), |
| 1988 | nlk->cb, | 2024 | nlk->cb, |
| 1989 | atomic_read(&s->sk_refcnt), | 2025 | atomic_read(&s->sk_refcnt), |
| 1990 | atomic_read(&s->sk_drops) | 2026 | atomic_read(&s->sk_drops), |
| 2027 | sock_i_ino(s) | ||
| 1991 | ); | 2028 | ); |
| 1992 | 2029 | ||
| 1993 | } | 2030 | } |
