| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * inet_diag.c Module for monitoring INET transport protocols sockets. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 27 | 23 | #include <net/inet_hashtables.h> |
|---|
| 28 | 24 | #include <net/inet_timewait_sock.h> |
|---|
| 29 | 25 | #include <net/inet6_hashtables.h> |
|---|
| 26 | +#include <net/bpf_sk_storage.h> |
|---|
| 30 | 27 | #include <net/netlink.h> |
|---|
| 31 | 28 | |
|---|
| 32 | 29 | #include <linux/inet.h> |
|---|
| .. | .. |
|---|
| 46 | 43 | u16 userlocks; |
|---|
| 47 | 44 | u32 ifindex; |
|---|
| 48 | 45 | u32 mark; |
|---|
| 46 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
|---|
| 47 | + u64 cgroup_id; |
|---|
| 48 | +#endif |
|---|
| 49 | 49 | }; |
|---|
| 50 | 50 | |
|---|
| 51 | 51 | static DEFINE_MUTEX(inet_diag_table_mutex); |
|---|
| 52 | 52 | |
|---|
| 53 | 53 | static const struct inet_diag_handler *inet_diag_lock_handler(int proto) |
|---|
| 54 | 54 | { |
|---|
| 55 | + if (proto < 0 || proto >= IPPROTO_MAX) { |
|---|
| 56 | + mutex_lock(&inet_diag_table_mutex); |
|---|
| 57 | + return ERR_PTR(-ENOENT); |
|---|
| 58 | + } |
|---|
| 59 | + |
|---|
| 55 | 60 | if (!inet_diag_table[proto]) |
|---|
| 56 | 61 | sock_load_diag_module(AF_INET, proto); |
|---|
| 57 | 62 | |
|---|
| .. | .. |
|---|
| 120 | 125 | bool net_admin) |
|---|
| 121 | 126 | { |
|---|
| 122 | 127 | const struct inet_sock *inet = inet_sk(sk); |
|---|
| 128 | + struct inet_diag_sockopt inet_sockopt; |
|---|
| 123 | 129 | |
|---|
| 124 | 130 | if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown)) |
|---|
| 125 | 131 | goto errout; |
|---|
| .. | .. |
|---|
| 165 | 171 | goto errout; |
|---|
| 166 | 172 | } |
|---|
| 167 | 173 | |
|---|
| 174 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
|---|
| 175 | + if (nla_put_u64_64bit(skb, INET_DIAG_CGROUP_ID, |
|---|
| 176 | + cgroup_id(sock_cgroup_ptr(&sk->sk_cgrp_data)), |
|---|
| 177 | + INET_DIAG_PAD)) |
|---|
| 178 | + goto errout; |
|---|
| 179 | +#endif |
|---|
| 180 | + |
|---|
| 168 | 181 | r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); |
|---|
| 169 | 182 | r->idiag_inode = sock_i_ino(sk); |
|---|
| 183 | + |
|---|
| 184 | + memset(&inet_sockopt, 0, sizeof(inet_sockopt)); |
|---|
| 185 | + inet_sockopt.recverr = inet->recverr; |
|---|
| 186 | + inet_sockopt.is_icsk = inet->is_icsk; |
|---|
| 187 | + inet_sockopt.freebind = inet->freebind; |
|---|
| 188 | + inet_sockopt.hdrincl = inet->hdrincl; |
|---|
| 189 | + inet_sockopt.mc_loop = inet->mc_loop; |
|---|
| 190 | + inet_sockopt.transparent = inet->transparent; |
|---|
| 191 | + inet_sockopt.mc_all = inet->mc_all; |
|---|
| 192 | + inet_sockopt.nodefrag = inet->nodefrag; |
|---|
| 193 | + inet_sockopt.bind_address_no_port = inet->bind_address_no_port; |
|---|
| 194 | + inet_sockopt.recverr_rfc4884 = inet->recverr_rfc4884; |
|---|
| 195 | + inet_sockopt.defer_connect = inet->defer_connect; |
|---|
| 196 | + if (nla_put(skb, INET_DIAG_SOCKOPT, sizeof(inet_sockopt), |
|---|
| 197 | + &inet_sockopt)) |
|---|
| 198 | + goto errout; |
|---|
| 170 | 199 | |
|---|
| 171 | 200 | return 0; |
|---|
| 172 | 201 | errout: |
|---|
| .. | .. |
|---|
| 174 | 203 | } |
|---|
| 175 | 204 | EXPORT_SYMBOL_GPL(inet_diag_msg_attrs_fill); |
|---|
| 176 | 205 | |
|---|
| 206 | +static int inet_diag_parse_attrs(const struct nlmsghdr *nlh, int hdrlen, |
|---|
| 207 | + struct nlattr **req_nlas) |
|---|
| 208 | +{ |
|---|
| 209 | + struct nlattr *nla; |
|---|
| 210 | + int remaining; |
|---|
| 211 | + |
|---|
| 212 | + nlmsg_for_each_attr(nla, nlh, hdrlen, remaining) { |
|---|
| 213 | + int type = nla_type(nla); |
|---|
| 214 | + |
|---|
| 215 | + if (type == INET_DIAG_REQ_PROTOCOL && nla_len(nla) != sizeof(u32)) |
|---|
| 216 | + return -EINVAL; |
|---|
| 217 | + |
|---|
| 218 | + if (type < __INET_DIAG_REQ_MAX) |
|---|
| 219 | + req_nlas[type] = nla; |
|---|
| 220 | + } |
|---|
| 221 | + return 0; |
|---|
| 222 | +} |
|---|
| 223 | + |
|---|
| 224 | +static int inet_diag_get_protocol(const struct inet_diag_req_v2 *req, |
|---|
| 225 | + const struct inet_diag_dump_data *data) |
|---|
| 226 | +{ |
|---|
| 227 | + if (data->req_nlas[INET_DIAG_REQ_PROTOCOL]) |
|---|
| 228 | + return nla_get_u32(data->req_nlas[INET_DIAG_REQ_PROTOCOL]); |
|---|
| 229 | + return req->sdiag_protocol; |
|---|
| 230 | +} |
|---|
| 231 | + |
|---|
| 232 | +#define MAX_DUMP_ALLOC_SIZE (KMALLOC_MAX_SIZE - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
|---|
| 233 | + |
|---|
| 177 | 234 | int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, |
|---|
| 178 | | - struct sk_buff *skb, const struct inet_diag_req_v2 *req, |
|---|
| 179 | | - struct user_namespace *user_ns, |
|---|
| 180 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
|---|
| 181 | | - const struct nlmsghdr *unlh, |
|---|
| 182 | | - bool net_admin) |
|---|
| 235 | + struct sk_buff *skb, struct netlink_callback *cb, |
|---|
| 236 | + const struct inet_diag_req_v2 *req, |
|---|
| 237 | + u16 nlmsg_flags, bool net_admin) |
|---|
| 183 | 238 | { |
|---|
| 184 | 239 | const struct tcp_congestion_ops *ca_ops; |
|---|
| 185 | 240 | const struct inet_diag_handler *handler; |
|---|
| 241 | + struct inet_diag_dump_data *cb_data; |
|---|
| 186 | 242 | int ext = req->idiag_ext; |
|---|
| 187 | 243 | struct inet_diag_msg *r; |
|---|
| 188 | 244 | struct nlmsghdr *nlh; |
|---|
| 189 | 245 | struct nlattr *attr; |
|---|
| 190 | 246 | void *info = NULL; |
|---|
| 191 | 247 | |
|---|
| 192 | | - handler = inet_diag_table[req->sdiag_protocol]; |
|---|
| 248 | + cb_data = cb->data; |
|---|
| 249 | + handler = inet_diag_table[inet_diag_get_protocol(req, cb_data)]; |
|---|
| 193 | 250 | BUG_ON(!handler); |
|---|
| 194 | 251 | |
|---|
| 195 | | - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), |
|---|
| 196 | | - nlmsg_flags); |
|---|
| 252 | + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, |
|---|
| 253 | + cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
|---|
| 197 | 254 | if (!nlh) |
|---|
| 198 | 255 | return -EMSGSIZE; |
|---|
| 199 | 256 | |
|---|
| .. | .. |
|---|
| 204 | 261 | r->idiag_state = sk->sk_state; |
|---|
| 205 | 262 | r->idiag_timer = 0; |
|---|
| 206 | 263 | r->idiag_retrans = 0; |
|---|
| 264 | + r->idiag_expires = 0; |
|---|
| 207 | 265 | |
|---|
| 208 | | - if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin)) |
|---|
| 266 | + if (inet_diag_msg_attrs_fill(sk, skb, r, ext, |
|---|
| 267 | + sk_user_ns(NETLINK_CB(cb->skb).sk), |
|---|
| 268 | + net_admin)) |
|---|
| 209 | 269 | goto errout; |
|---|
| 210 | 270 | |
|---|
| 211 | 271 | if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { |
|---|
| 212 | 272 | struct inet_diag_meminfo minfo = { |
|---|
| 213 | 273 | .idiag_rmem = sk_rmem_alloc_get(sk), |
|---|
| 214 | | - .idiag_wmem = sk->sk_wmem_queued, |
|---|
| 274 | + .idiag_wmem = READ_ONCE(sk->sk_wmem_queued), |
|---|
| 215 | 275 | .idiag_fmem = sk->sk_forward_alloc, |
|---|
| 216 | 276 | .idiag_tmem = sk_wmem_alloc_get(sk), |
|---|
| 217 | 277 | }; |
|---|
| .. | .. |
|---|
| 244 | 304 | r->idiag_timer = 1; |
|---|
| 245 | 305 | r->idiag_retrans = icsk->icsk_retransmits; |
|---|
| 246 | 306 | r->idiag_expires = |
|---|
| 247 | | - jiffies_to_msecs(icsk->icsk_timeout - jiffies); |
|---|
| 307 | + jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); |
|---|
| 248 | 308 | } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { |
|---|
| 249 | 309 | r->idiag_timer = 4; |
|---|
| 250 | 310 | r->idiag_retrans = icsk->icsk_probes_out; |
|---|
| 251 | 311 | r->idiag_expires = |
|---|
| 252 | | - jiffies_to_msecs(icsk->icsk_timeout - jiffies); |
|---|
| 312 | + jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); |
|---|
| 253 | 313 | } else if (timer_pending(&sk->sk_timer)) { |
|---|
| 254 | 314 | r->idiag_timer = 2; |
|---|
| 255 | 315 | r->idiag_retrans = icsk->icsk_probes_out; |
|---|
| 256 | 316 | r->idiag_expires = |
|---|
| 257 | | - jiffies_to_msecs(sk->sk_timer.expires - jiffies); |
|---|
| 258 | | - } else { |
|---|
| 259 | | - r->idiag_timer = 0; |
|---|
| 260 | | - r->idiag_expires = 0; |
|---|
| 317 | + jiffies_delta_to_msecs(sk->sk_timer.expires - jiffies); |
|---|
| 261 | 318 | } |
|---|
| 262 | 319 | |
|---|
| 263 | 320 | if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) { |
|---|
| .. | .. |
|---|
| 302 | 359 | goto errout; |
|---|
| 303 | 360 | } |
|---|
| 304 | 361 | |
|---|
| 362 | + /* Keep it at the end for potential retry with a larger skb, |
|---|
| 363 | + * or else do best-effort fitting, which is only done for the |
|---|
| 364 | + * first_nlmsg. |
|---|
| 365 | + */ |
|---|
| 366 | + if (cb_data->bpf_stg_diag) { |
|---|
| 367 | + bool first_nlmsg = ((unsigned char *)nlh == skb->data); |
|---|
| 368 | + unsigned int prev_min_dump_alloc; |
|---|
| 369 | + unsigned int total_nla_size = 0; |
|---|
| 370 | + unsigned int msg_len; |
|---|
| 371 | + int err; |
|---|
| 372 | + |
|---|
| 373 | + msg_len = skb_tail_pointer(skb) - (unsigned char *)nlh; |
|---|
| 374 | + err = bpf_sk_storage_diag_put(cb_data->bpf_stg_diag, sk, skb, |
|---|
| 375 | + INET_DIAG_SK_BPF_STORAGES, |
|---|
| 376 | + &total_nla_size); |
|---|
| 377 | + |
|---|
| 378 | + if (!err) |
|---|
| 379 | + goto out; |
|---|
| 380 | + |
|---|
| 381 | + total_nla_size += msg_len; |
|---|
| 382 | + prev_min_dump_alloc = cb->min_dump_alloc; |
|---|
| 383 | + if (total_nla_size > prev_min_dump_alloc) |
|---|
| 384 | + cb->min_dump_alloc = min_t(u32, total_nla_size, |
|---|
| 385 | + MAX_DUMP_ALLOC_SIZE); |
|---|
| 386 | + |
|---|
| 387 | + if (!first_nlmsg) |
|---|
| 388 | + goto errout; |
|---|
| 389 | + |
|---|
| 390 | + if (cb->min_dump_alloc > prev_min_dump_alloc) |
|---|
| 391 | + /* Retry with pskb_expand_head() with |
|---|
| 392 | + * __GFP_DIRECT_RECLAIM |
|---|
| 393 | + */ |
|---|
| 394 | + goto errout; |
|---|
| 395 | + |
|---|
| 396 | + WARN_ON_ONCE(total_nla_size <= prev_min_dump_alloc); |
|---|
| 397 | + |
|---|
| 398 | + /* Send what we have for this sk |
|---|
| 399 | + * and move on to the next sk in the following |
|---|
| 400 | + * dump() |
|---|
| 401 | + */ |
|---|
| 402 | + } |
|---|
| 403 | + |
|---|
| 305 | 404 | out: |
|---|
| 306 | 405 | nlmsg_end(skb, nlh); |
|---|
| 307 | 406 | return 0; |
|---|
| .. | .. |
|---|
| 312 | 411 | } |
|---|
| 313 | 412 | EXPORT_SYMBOL_GPL(inet_sk_diag_fill); |
|---|
| 314 | 413 | |
|---|
| 315 | | -static int inet_csk_diag_fill(struct sock *sk, |
|---|
| 316 | | - struct sk_buff *skb, |
|---|
| 317 | | - const struct inet_diag_req_v2 *req, |
|---|
| 318 | | - struct user_namespace *user_ns, |
|---|
| 319 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
|---|
| 320 | | - const struct nlmsghdr *unlh, |
|---|
| 321 | | - bool net_admin) |
|---|
| 322 | | -{ |
|---|
| 323 | | - return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, user_ns, |
|---|
| 324 | | - portid, seq, nlmsg_flags, unlh, net_admin); |
|---|
| 325 | | -} |
|---|
| 326 | | - |
|---|
| 327 | 414 | static int inet_twsk_diag_fill(struct sock *sk, |
|---|
| 328 | 415 | struct sk_buff *skb, |
|---|
| 329 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
|---|
| 330 | | - const struct nlmsghdr *unlh) |
|---|
| 416 | + struct netlink_callback *cb, |
|---|
| 417 | + u16 nlmsg_flags) |
|---|
| 331 | 418 | { |
|---|
| 332 | 419 | struct inet_timewait_sock *tw = inet_twsk(sk); |
|---|
| 333 | 420 | struct inet_diag_msg *r; |
|---|
| 334 | 421 | struct nlmsghdr *nlh; |
|---|
| 335 | 422 | long tmo; |
|---|
| 336 | 423 | |
|---|
| 337 | | - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), |
|---|
| 338 | | - nlmsg_flags); |
|---|
| 424 | + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, |
|---|
| 425 | + cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, |
|---|
| 426 | + sizeof(*r), nlmsg_flags); |
|---|
| 339 | 427 | if (!nlh) |
|---|
| 340 | 428 | return -EMSGSIZE; |
|---|
| 341 | 429 | |
|---|
| 342 | 430 | r = nlmsg_data(nlh); |
|---|
| 343 | 431 | BUG_ON(tw->tw_state != TCP_TIME_WAIT); |
|---|
| 344 | 432 | |
|---|
| 345 | | - tmo = tw->tw_timer.expires - jiffies; |
|---|
| 346 | | - if (tmo < 0) |
|---|
| 347 | | - tmo = 0; |
|---|
| 348 | | - |
|---|
| 349 | 433 | inet_diag_msg_common_fill(r, sk); |
|---|
| 350 | 434 | r->idiag_retrans = 0; |
|---|
| 351 | 435 | |
|---|
| 352 | 436 | r->idiag_state = tw->tw_substate; |
|---|
| 353 | 437 | r->idiag_timer = 3; |
|---|
| 354 | | - r->idiag_expires = jiffies_to_msecs(tmo); |
|---|
| 438 | + tmo = tw->tw_timer.expires - jiffies; |
|---|
| 439 | + r->idiag_expires = jiffies_delta_to_msecs(tmo); |
|---|
| 355 | 440 | r->idiag_rqueue = 0; |
|---|
| 356 | 441 | r->idiag_wqueue = 0; |
|---|
| 357 | 442 | r->idiag_uid = 0; |
|---|
| .. | .. |
|---|
| 362 | 447 | } |
|---|
| 363 | 448 | |
|---|
| 364 | 449 | static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, |
|---|
| 365 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
|---|
| 366 | | - const struct nlmsghdr *unlh, bool net_admin) |
|---|
| 450 | + struct netlink_callback *cb, |
|---|
| 451 | + u16 nlmsg_flags, bool net_admin) |
|---|
| 367 | 452 | { |
|---|
| 368 | 453 | struct request_sock *reqsk = inet_reqsk(sk); |
|---|
| 369 | 454 | struct inet_diag_msg *r; |
|---|
| 370 | 455 | struct nlmsghdr *nlh; |
|---|
| 371 | 456 | long tmo; |
|---|
| 372 | 457 | |
|---|
| 373 | | - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), |
|---|
| 374 | | - nlmsg_flags); |
|---|
| 458 | + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, |
|---|
| 459 | + cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
|---|
| 375 | 460 | if (!nlh) |
|---|
| 376 | 461 | return -EMSGSIZE; |
|---|
| 377 | 462 | |
|---|
| .. | .. |
|---|
| 385 | 470 | offsetof(struct sock, sk_cookie)); |
|---|
| 386 | 471 | |
|---|
| 387 | 472 | tmo = inet_reqsk(sk)->rsk_timer.expires - jiffies; |
|---|
| 388 | | - r->idiag_expires = (tmo >= 0) ? jiffies_to_msecs(tmo) : 0; |
|---|
| 473 | + r->idiag_expires = jiffies_delta_to_msecs(tmo); |
|---|
| 389 | 474 | r->idiag_rqueue = 0; |
|---|
| 390 | 475 | r->idiag_wqueue = 0; |
|---|
| 391 | 476 | r->idiag_uid = 0; |
|---|
| .. | .. |
|---|
| 402 | 487 | } |
|---|
| 403 | 488 | |
|---|
| 404 | 489 | static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, |
|---|
| 490 | + struct netlink_callback *cb, |
|---|
| 405 | 491 | const struct inet_diag_req_v2 *r, |
|---|
| 406 | | - struct user_namespace *user_ns, |
|---|
| 407 | | - u32 portid, u32 seq, u16 nlmsg_flags, |
|---|
| 408 | | - const struct nlmsghdr *unlh, bool net_admin) |
|---|
| 492 | + u16 nlmsg_flags, bool net_admin) |
|---|
| 409 | 493 | { |
|---|
| 410 | 494 | if (sk->sk_state == TCP_TIME_WAIT) |
|---|
| 411 | | - return inet_twsk_diag_fill(sk, skb, portid, seq, |
|---|
| 412 | | - nlmsg_flags, unlh); |
|---|
| 495 | + return inet_twsk_diag_fill(sk, skb, cb, nlmsg_flags); |
|---|
| 413 | 496 | |
|---|
| 414 | 497 | if (sk->sk_state == TCP_NEW_SYN_RECV) |
|---|
| 415 | | - return inet_req_diag_fill(sk, skb, portid, seq, |
|---|
| 416 | | - nlmsg_flags, unlh, net_admin); |
|---|
| 498 | + return inet_req_diag_fill(sk, skb, cb, nlmsg_flags, net_admin); |
|---|
| 417 | 499 | |
|---|
| 418 | | - return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, |
|---|
| 419 | | - nlmsg_flags, unlh, net_admin); |
|---|
| 500 | + return inet_sk_diag_fill(sk, inet_csk(sk), skb, cb, r, nlmsg_flags, |
|---|
| 501 | + net_admin); |
|---|
| 420 | 502 | } |
|---|
| 421 | 503 | |
|---|
| 422 | 504 | struct sock *inet_diag_find_one_icsk(struct net *net, |
|---|
| .. | .. |
|---|
| 464 | 546 | EXPORT_SYMBOL_GPL(inet_diag_find_one_icsk); |
|---|
| 465 | 547 | |
|---|
| 466 | 548 | int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, |
|---|
| 467 | | - struct sk_buff *in_skb, |
|---|
| 468 | | - const struct nlmsghdr *nlh, |
|---|
| 549 | + struct netlink_callback *cb, |
|---|
| 469 | 550 | const struct inet_diag_req_v2 *req) |
|---|
| 470 | 551 | { |
|---|
| 552 | + struct sk_buff *in_skb = cb->skb; |
|---|
| 471 | 553 | bool net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN); |
|---|
| 472 | 554 | struct net *net = sock_net(in_skb->sk); |
|---|
| 473 | 555 | struct sk_buff *rep; |
|---|
| .. | .. |
|---|
| 484 | 566 | goto out; |
|---|
| 485 | 567 | } |
|---|
| 486 | 568 | |
|---|
| 487 | | - err = sk_diag_fill(sk, rep, req, |
|---|
| 488 | | - sk_user_ns(NETLINK_CB(in_skb).sk), |
|---|
| 489 | | - NETLINK_CB(in_skb).portid, |
|---|
| 490 | | - nlh->nlmsg_seq, 0, nlh, net_admin); |
|---|
| 569 | + err = sk_diag_fill(sk, rep, cb, req, 0, net_admin); |
|---|
| 491 | 570 | if (err < 0) { |
|---|
| 492 | 571 | WARN_ON(err == -EMSGSIZE); |
|---|
| 493 | 572 | nlmsg_free(rep); |
|---|
| .. | .. |
|---|
| 508 | 587 | |
|---|
| 509 | 588 | static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb, |
|---|
| 510 | 589 | const struct nlmsghdr *nlh, |
|---|
| 590 | + int hdrlen, |
|---|
| 511 | 591 | const struct inet_diag_req_v2 *req) |
|---|
| 512 | 592 | { |
|---|
| 513 | 593 | const struct inet_diag_handler *handler; |
|---|
| 514 | | - int err; |
|---|
| 594 | + struct inet_diag_dump_data dump_data; |
|---|
| 595 | + int err, protocol; |
|---|
| 515 | 596 | |
|---|
| 516 | | - handler = inet_diag_lock_handler(req->sdiag_protocol); |
|---|
| 517 | | - if (IS_ERR(handler)) |
|---|
| 597 | + memset(&dump_data, 0, sizeof(dump_data)); |
|---|
| 598 | + err = inet_diag_parse_attrs(nlh, hdrlen, dump_data.req_nlas); |
|---|
| 599 | + if (err) |
|---|
| 600 | + return err; |
|---|
| 601 | + |
|---|
| 602 | + protocol = inet_diag_get_protocol(req, &dump_data); |
|---|
| 603 | + |
|---|
| 604 | + handler = inet_diag_lock_handler(protocol); |
|---|
| 605 | + if (IS_ERR(handler)) { |
|---|
| 518 | 606 | err = PTR_ERR(handler); |
|---|
| 519 | | - else if (cmd == SOCK_DIAG_BY_FAMILY) |
|---|
| 520 | | - err = handler->dump_one(in_skb, nlh, req); |
|---|
| 521 | | - else if (cmd == SOCK_DESTROY && handler->destroy) |
|---|
| 607 | + } else if (cmd == SOCK_DIAG_BY_FAMILY) { |
|---|
| 608 | + struct netlink_callback cb = { |
|---|
| 609 | + .nlh = nlh, |
|---|
| 610 | + .skb = in_skb, |
|---|
| 611 | + .data = &dump_data, |
|---|
| 612 | + }; |
|---|
| 613 | + err = handler->dump_one(&cb, req); |
|---|
| 614 | + } else if (cmd == SOCK_DESTROY && handler->destroy) { |
|---|
| 522 | 615 | err = handler->destroy(in_skb, req); |
|---|
| 523 | | - else |
|---|
| 616 | + } else { |
|---|
| 524 | 617 | err = -EOPNOTSUPP; |
|---|
| 618 | + } |
|---|
| 525 | 619 | inet_diag_unlock_handler(handler); |
|---|
| 526 | 620 | |
|---|
| 527 | 621 | return err; |
|---|
| .. | .. |
|---|
| 647 | 741 | yes = 0; |
|---|
| 648 | 742 | break; |
|---|
| 649 | 743 | } |
|---|
| 744 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
|---|
| 745 | + case INET_DIAG_BC_CGROUP_COND: { |
|---|
| 746 | + u64 cgroup_id; |
|---|
| 747 | + |
|---|
| 748 | + cgroup_id = get_unaligned((const u64 *)(op + 1)); |
|---|
| 749 | + if (cgroup_id != entry->cgroup_id) |
|---|
| 750 | + yes = 0; |
|---|
| 751 | + break; |
|---|
| 752 | + } |
|---|
| 753 | +#endif |
|---|
| 650 | 754 | } |
|---|
| 651 | 755 | |
|---|
| 652 | 756 | if (yes) { |
|---|
| .. | .. |
|---|
| 697 | 801 | entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark; |
|---|
| 698 | 802 | else |
|---|
| 699 | 803 | entry.mark = 0; |
|---|
| 804 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
|---|
| 805 | + entry.cgroup_id = sk_fullsock(sk) ? |
|---|
| 806 | + cgroup_id(sock_cgroup_ptr(&sk->sk_cgrp_data)) : 0; |
|---|
| 807 | +#endif |
|---|
| 700 | 808 | |
|---|
| 701 | 809 | return inet_diag_bc_run(bc, &entry); |
|---|
| 702 | 810 | } |
|---|
| .. | .. |
|---|
| 786 | 894 | return len >= *min_len; |
|---|
| 787 | 895 | } |
|---|
| 788 | 896 | |
|---|
| 897 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
|---|
| 898 | +static bool valid_cgroupcond(const struct inet_diag_bc_op *op, int len, |
|---|
| 899 | + int *min_len) |
|---|
| 900 | +{ |
|---|
| 901 | + *min_len += sizeof(u64); |
|---|
| 902 | + return len >= *min_len; |
|---|
| 903 | +} |
|---|
| 904 | +#endif |
|---|
| 905 | + |
|---|
| 789 | 906 | static int inet_diag_bc_audit(const struct nlattr *attr, |
|---|
| 790 | 907 | const struct sk_buff *skb) |
|---|
| 791 | 908 | { |
|---|
| .. | .. |
|---|
| 828 | 945 | if (!valid_markcond(bc, len, &min_len)) |
|---|
| 829 | 946 | return -EINVAL; |
|---|
| 830 | 947 | break; |
|---|
| 948 | +#ifdef CONFIG_SOCK_CGROUP_DATA |
|---|
| 949 | + case INET_DIAG_BC_CGROUP_COND: |
|---|
| 950 | + if (!valid_cgroupcond(bc, len, &min_len)) |
|---|
| 951 | + return -EINVAL; |
|---|
| 952 | + break; |
|---|
| 953 | +#endif |
|---|
| 831 | 954 | case INET_DIAG_BC_AUTO: |
|---|
| 832 | 955 | case INET_DIAG_BC_JMP: |
|---|
| 833 | 956 | case INET_DIAG_BC_NOP: |
|---|
| .. | .. |
|---|
| 850 | 973 | len -= op->yes; |
|---|
| 851 | 974 | } |
|---|
| 852 | 975 | return len == 0 ? 0 : -EINVAL; |
|---|
| 853 | | -} |
|---|
| 854 | | - |
|---|
| 855 | | -static int inet_csk_diag_dump(struct sock *sk, |
|---|
| 856 | | - struct sk_buff *skb, |
|---|
| 857 | | - struct netlink_callback *cb, |
|---|
| 858 | | - const struct inet_diag_req_v2 *r, |
|---|
| 859 | | - const struct nlattr *bc, |
|---|
| 860 | | - bool net_admin) |
|---|
| 861 | | -{ |
|---|
| 862 | | - if (!inet_diag_bc_sk(bc, sk)) |
|---|
| 863 | | - return 0; |
|---|
| 864 | | - |
|---|
| 865 | | - return inet_csk_diag_fill(sk, skb, r, |
|---|
| 866 | | - sk_user_ns(NETLINK_CB(cb->skb).sk), |
|---|
| 867 | | - NETLINK_CB(cb->skb).portid, |
|---|
| 868 | | - cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, |
|---|
| 869 | | - net_admin); |
|---|
| 870 | 976 | } |
|---|
| 871 | 977 | |
|---|
| 872 | 978 | static void twsk_build_assert(void) |
|---|
| .. | .. |
|---|
| 897 | 1003 | |
|---|
| 898 | 1004 | void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, |
|---|
| 899 | 1005 | struct netlink_callback *cb, |
|---|
| 900 | | - const struct inet_diag_req_v2 *r, struct nlattr *bc) |
|---|
| 1006 | + const struct inet_diag_req_v2 *r) |
|---|
| 901 | 1007 | { |
|---|
| 902 | 1008 | bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); |
|---|
| 1009 | + struct inet_diag_dump_data *cb_data = cb->data; |
|---|
| 903 | 1010 | struct net *net = sock_net(skb->sk); |
|---|
| 904 | 1011 | u32 idiag_states = r->idiag_states; |
|---|
| 905 | 1012 | int i, num, s_i, s_num; |
|---|
| 1013 | + struct nlattr *bc; |
|---|
| 906 | 1014 | struct sock *sk; |
|---|
| 907 | 1015 | |
|---|
| 1016 | + bc = cb_data->inet_diag_nla_bc; |
|---|
| 908 | 1017 | if (idiag_states & TCPF_SYN_RECV) |
|---|
| 909 | 1018 | idiag_states |= TCPF_NEW_SYN_RECV; |
|---|
| 910 | 1019 | s_i = cb->args[1]; |
|---|
| .. | .. |
|---|
| 940 | 1049 | r->id.idiag_sport) |
|---|
| 941 | 1050 | goto next_listen; |
|---|
| 942 | 1051 | |
|---|
| 943 | | - if (inet_csk_diag_dump(sk, skb, cb, r, |
|---|
| 944 | | - bc, net_admin) < 0) { |
|---|
| 1052 | + if (!inet_diag_bc_sk(bc, sk)) |
|---|
| 1053 | + goto next_listen; |
|---|
| 1054 | + |
|---|
| 1055 | + if (inet_sk_diag_fill(sk, inet_csk(sk), skb, |
|---|
| 1056 | + cb, r, NLM_F_MULTI, |
|---|
| 1057 | + net_admin) < 0) { |
|---|
| 945 | 1058 | spin_unlock(&ilb->lock); |
|---|
| 946 | 1059 | goto done; |
|---|
| 947 | 1060 | } |
|---|
| .. | .. |
|---|
| 1019 | 1132 | res = 0; |
|---|
| 1020 | 1133 | for (idx = 0; idx < accum; idx++) { |
|---|
| 1021 | 1134 | if (res >= 0) { |
|---|
| 1022 | | - res = sk_diag_fill(sk_arr[idx], skb, r, |
|---|
| 1023 | | - sk_user_ns(NETLINK_CB(cb->skb).sk), |
|---|
| 1024 | | - NETLINK_CB(cb->skb).portid, |
|---|
| 1025 | | - cb->nlh->nlmsg_seq, NLM_F_MULTI, |
|---|
| 1026 | | - cb->nlh, net_admin); |
|---|
| 1135 | + res = sk_diag_fill(sk_arr[idx], skb, cb, r, |
|---|
| 1136 | + NLM_F_MULTI, net_admin); |
|---|
| 1027 | 1137 | if (res < 0) |
|---|
| 1028 | 1138 | num = num_arr[idx]; |
|---|
| 1029 | 1139 | } |
|---|
| .. | .. |
|---|
| 1047 | 1157 | EXPORT_SYMBOL_GPL(inet_diag_dump_icsk); |
|---|
| 1048 | 1158 | |
|---|
| 1049 | 1159 | static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, |
|---|
| 1050 | | - const struct inet_diag_req_v2 *r, |
|---|
| 1051 | | - struct nlattr *bc) |
|---|
| 1160 | + const struct inet_diag_req_v2 *r) |
|---|
| 1052 | 1161 | { |
|---|
| 1162 | + struct inet_diag_dump_data *cb_data = cb->data; |
|---|
| 1053 | 1163 | const struct inet_diag_handler *handler; |
|---|
| 1054 | | - int err = 0; |
|---|
| 1164 | + u32 prev_min_dump_alloc; |
|---|
| 1165 | + int protocol, err = 0; |
|---|
| 1055 | 1166 | |
|---|
| 1056 | | - handler = inet_diag_lock_handler(r->sdiag_protocol); |
|---|
| 1167 | + protocol = inet_diag_get_protocol(r, cb_data); |
|---|
| 1168 | + |
|---|
| 1169 | +again: |
|---|
| 1170 | + prev_min_dump_alloc = cb->min_dump_alloc; |
|---|
| 1171 | + handler = inet_diag_lock_handler(protocol); |
|---|
| 1057 | 1172 | if (!IS_ERR(handler)) |
|---|
| 1058 | | - handler->dump(skb, cb, r, bc); |
|---|
| 1173 | + handler->dump(skb, cb, r); |
|---|
| 1059 | 1174 | else |
|---|
| 1060 | 1175 | err = PTR_ERR(handler); |
|---|
| 1061 | 1176 | inet_diag_unlock_handler(handler); |
|---|
| 1177 | + |
|---|
| 1178 | + /* The skb is not large enough to fit one sk info and |
|---|
| 1179 | + * inet_sk_diag_fill() has requested for a larger skb. |
|---|
| 1180 | + */ |
|---|
| 1181 | + if (!skb->len && cb->min_dump_alloc > prev_min_dump_alloc) { |
|---|
| 1182 | + err = pskb_expand_head(skb, 0, cb->min_dump_alloc, GFP_KERNEL); |
|---|
| 1183 | + if (!err) |
|---|
| 1184 | + goto again; |
|---|
| 1185 | + } |
|---|
| 1062 | 1186 | |
|---|
| 1063 | 1187 | return err ? : skb->len; |
|---|
| 1064 | 1188 | } |
|---|
| 1065 | 1189 | |
|---|
| 1066 | 1190 | static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) |
|---|
| 1067 | 1191 | { |
|---|
| 1068 | | - int hdrlen = sizeof(struct inet_diag_req_v2); |
|---|
| 1069 | | - struct nlattr *bc = NULL; |
|---|
| 1192 | + return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh)); |
|---|
| 1193 | +} |
|---|
| 1070 | 1194 | |
|---|
| 1071 | | - if (nlmsg_attrlen(cb->nlh, hdrlen)) |
|---|
| 1072 | | - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); |
|---|
| 1195 | +static int __inet_diag_dump_start(struct netlink_callback *cb, int hdrlen) |
|---|
| 1196 | +{ |
|---|
| 1197 | + const struct nlmsghdr *nlh = cb->nlh; |
|---|
| 1198 | + struct inet_diag_dump_data *cb_data; |
|---|
| 1199 | + struct sk_buff *skb = cb->skb; |
|---|
| 1200 | + struct nlattr *nla; |
|---|
| 1201 | + int err; |
|---|
| 1073 | 1202 | |
|---|
| 1074 | | - return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh), bc); |
|---|
| 1203 | + cb_data = kzalloc(sizeof(*cb_data), GFP_KERNEL); |
|---|
| 1204 | + if (!cb_data) |
|---|
| 1205 | + return -ENOMEM; |
|---|
| 1206 | + |
|---|
| 1207 | + err = inet_diag_parse_attrs(nlh, hdrlen, cb_data->req_nlas); |
|---|
| 1208 | + if (err) { |
|---|
| 1209 | + kfree(cb_data); |
|---|
| 1210 | + return err; |
|---|
| 1211 | + } |
|---|
| 1212 | + nla = cb_data->inet_diag_nla_bc; |
|---|
| 1213 | + if (nla) { |
|---|
| 1214 | + err = inet_diag_bc_audit(nla, skb); |
|---|
| 1215 | + if (err) { |
|---|
| 1216 | + kfree(cb_data); |
|---|
| 1217 | + return err; |
|---|
| 1218 | + } |
|---|
| 1219 | + } |
|---|
| 1220 | + |
|---|
| 1221 | + nla = cb_data->inet_diag_nla_bpf_stgs; |
|---|
| 1222 | + if (nla) { |
|---|
| 1223 | + struct bpf_sk_storage_diag *bpf_stg_diag; |
|---|
| 1224 | + |
|---|
| 1225 | + bpf_stg_diag = bpf_sk_storage_diag_alloc(nla); |
|---|
| 1226 | + if (IS_ERR(bpf_stg_diag)) { |
|---|
| 1227 | + kfree(cb_data); |
|---|
| 1228 | + return PTR_ERR(bpf_stg_diag); |
|---|
| 1229 | + } |
|---|
| 1230 | + cb_data->bpf_stg_diag = bpf_stg_diag; |
|---|
| 1231 | + } |
|---|
| 1232 | + |
|---|
| 1233 | + cb->data = cb_data; |
|---|
| 1234 | + return 0; |
|---|
| 1235 | +} |
|---|
| 1236 | + |
|---|
| 1237 | +static int inet_diag_dump_start(struct netlink_callback *cb) |
|---|
| 1238 | +{ |
|---|
| 1239 | + return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req_v2)); |
|---|
| 1240 | +} |
|---|
| 1241 | + |
|---|
| 1242 | +static int inet_diag_dump_start_compat(struct netlink_callback *cb) |
|---|
| 1243 | +{ |
|---|
| 1244 | + return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req)); |
|---|
| 1245 | +} |
|---|
| 1246 | + |
|---|
| 1247 | +static int inet_diag_dump_done(struct netlink_callback *cb) |
|---|
| 1248 | +{ |
|---|
| 1249 | + struct inet_diag_dump_data *cb_data = cb->data; |
|---|
| 1250 | + |
|---|
| 1251 | + bpf_sk_storage_diag_free(cb_data->bpf_stg_diag); |
|---|
| 1252 | + kfree(cb->data); |
|---|
| 1253 | + |
|---|
| 1254 | + return 0; |
|---|
| 1075 | 1255 | } |
|---|
| 1076 | 1256 | |
|---|
| 1077 | 1257 | static int inet_diag_type2proto(int type) |
|---|
| .. | .. |
|---|
| 1090 | 1270 | struct netlink_callback *cb) |
|---|
| 1091 | 1271 | { |
|---|
| 1092 | 1272 | struct inet_diag_req *rc = nlmsg_data(cb->nlh); |
|---|
| 1093 | | - int hdrlen = sizeof(struct inet_diag_req); |
|---|
| 1094 | 1273 | struct inet_diag_req_v2 req; |
|---|
| 1095 | | - struct nlattr *bc = NULL; |
|---|
| 1096 | 1274 | |
|---|
| 1097 | 1275 | req.sdiag_family = AF_UNSPEC; /* compatibility */ |
|---|
| 1098 | 1276 | req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type); |
|---|
| .. | .. |
|---|
| 1100 | 1278 | req.idiag_states = rc->idiag_states; |
|---|
| 1101 | 1279 | req.id = rc->id; |
|---|
| 1102 | 1280 | |
|---|
| 1103 | | - if (nlmsg_attrlen(cb->nlh, hdrlen)) |
|---|
| 1104 | | - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); |
|---|
| 1105 | | - |
|---|
| 1106 | | - return __inet_diag_dump(skb, cb, &req, bc); |
|---|
| 1281 | + return __inet_diag_dump(skb, cb, &req); |
|---|
| 1107 | 1282 | } |
|---|
| 1108 | 1283 | |
|---|
| 1109 | 1284 | static int inet_diag_get_exact_compat(struct sk_buff *in_skb, |
|---|
| .. | .. |
|---|
| 1118 | 1293 | req.idiag_states = rc->idiag_states; |
|---|
| 1119 | 1294 | req.id = rc->id; |
|---|
| 1120 | 1295 | |
|---|
| 1121 | | - return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, &req); |
|---|
| 1296 | + return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, |
|---|
| 1297 | + sizeof(struct inet_diag_req), &req); |
|---|
| 1122 | 1298 | } |
|---|
| 1123 | 1299 | |
|---|
| 1124 | 1300 | static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) |
|---|
| .. | .. |
|---|
| 1131 | 1307 | return -EINVAL; |
|---|
| 1132 | 1308 | |
|---|
| 1133 | 1309 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
|---|
| 1134 | | - if (nlmsg_attrlen(nlh, hdrlen)) { |
|---|
| 1135 | | - struct nlattr *attr; |
|---|
| 1136 | | - int err; |
|---|
| 1137 | | - |
|---|
| 1138 | | - attr = nlmsg_find_attr(nlh, hdrlen, |
|---|
| 1139 | | - INET_DIAG_REQ_BYTECODE); |
|---|
| 1140 | | - err = inet_diag_bc_audit(attr, skb); |
|---|
| 1141 | | - if (err) |
|---|
| 1142 | | - return err; |
|---|
| 1143 | | - } |
|---|
| 1144 | | - { |
|---|
| 1145 | | - struct netlink_dump_control c = { |
|---|
| 1146 | | - .dump = inet_diag_dump_compat, |
|---|
| 1147 | | - }; |
|---|
| 1148 | | - return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); |
|---|
| 1149 | | - } |
|---|
| 1310 | + struct netlink_dump_control c = { |
|---|
| 1311 | + .start = inet_diag_dump_start_compat, |
|---|
| 1312 | + .done = inet_diag_dump_done, |
|---|
| 1313 | + .dump = inet_diag_dump_compat, |
|---|
| 1314 | + }; |
|---|
| 1315 | + return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); |
|---|
| 1150 | 1316 | } |
|---|
| 1151 | 1317 | |
|---|
| 1152 | 1318 | return inet_diag_get_exact_compat(skb, nlh); |
|---|
| .. | .. |
|---|
| 1162 | 1328 | |
|---|
| 1163 | 1329 | if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY && |
|---|
| 1164 | 1330 | h->nlmsg_flags & NLM_F_DUMP) { |
|---|
| 1165 | | - if (nlmsg_attrlen(h, hdrlen)) { |
|---|
| 1166 | | - struct nlattr *attr; |
|---|
| 1167 | | - int err; |
|---|
| 1168 | | - |
|---|
| 1169 | | - attr = nlmsg_find_attr(h, hdrlen, |
|---|
| 1170 | | - INET_DIAG_REQ_BYTECODE); |
|---|
| 1171 | | - err = inet_diag_bc_audit(attr, skb); |
|---|
| 1172 | | - if (err) |
|---|
| 1173 | | - return err; |
|---|
| 1174 | | - } |
|---|
| 1175 | | - { |
|---|
| 1176 | | - struct netlink_dump_control c = { |
|---|
| 1177 | | - .dump = inet_diag_dump, |
|---|
| 1178 | | - }; |
|---|
| 1179 | | - return netlink_dump_start(net->diag_nlsk, skb, h, &c); |
|---|
| 1180 | | - } |
|---|
| 1331 | + struct netlink_dump_control c = { |
|---|
| 1332 | + .start = inet_diag_dump_start, |
|---|
| 1333 | + .done = inet_diag_dump_done, |
|---|
| 1334 | + .dump = inet_diag_dump, |
|---|
| 1335 | + }; |
|---|
| 1336 | + return netlink_dump_start(net->diag_nlsk, skb, h, &c); |
|---|
| 1181 | 1337 | } |
|---|
| 1182 | 1338 | |
|---|
| 1183 | | - return inet_diag_cmd_exact(h->nlmsg_type, skb, h, nlmsg_data(h)); |
|---|
| 1339 | + return inet_diag_cmd_exact(h->nlmsg_type, skb, h, hdrlen, |
|---|
| 1340 | + nlmsg_data(h)); |
|---|
| 1184 | 1341 | } |
|---|
| 1185 | 1342 | |
|---|
| 1186 | 1343 | static |
|---|
| .. | .. |
|---|
| 1315 | 1472 | kfree(inet_diag_table); |
|---|
| 1316 | 1473 | } |
|---|
| 1317 | 1474 | |
|---|
| 1318 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
|---|
| 1319 | | -rootfs_initcall(inet_diag_init); |
|---|
| 1320 | | -#else |
|---|
| 1321 | 1475 | module_init(inet_diag_init); |
|---|
| 1322 | | -#endif |
|---|
| 1323 | 1476 | module_exit(inet_diag_exit); |
|---|
| 1324 | 1477 | MODULE_LICENSE("GPL"); |
|---|
| 1325 | 1478 | MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */); |
|---|