linux-bk/net/ipv4/tcp_diag.c
<<
>>
Prefs
   1/*
   2 * tcp_diag.c   Module for monitoring TCP sockets.
   3 *
   4 * Version:     $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
   5 *
   6 * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   7 *
   8 *      This program is free software; you can redistribute it and/or
   9 *      modify it under the terms of the GNU General Public License
  10 *      as published by the Free Software Foundation; either version
  11 *      2 of the License, or (at your option) any later version.
  12 */
  13
  14#include <linux/config.h>
  15#include <linux/module.h>
  16#include <linux/types.h>
  17#include <linux/fcntl.h>
  18#include <linux/random.h>
  19#include <linux/cache.h>
  20#include <linux/init.h>
  21
  22#include <net/icmp.h>
  23#include <net/tcp.h>
  24#include <net/ipv6.h>
  25#include <net/inet_common.h>
  26
  27#include <linux/inet.h>
  28#include <linux/stddef.h>
  29
  30#include <linux/tcp_diag.h>
  31
  32static struct sock *tcpnl;
  33
  34
  35#define TCPDIAG_PUT(skb, attrtype, attrlen) \
  36({ int rtalen = RTA_LENGTH(attrlen);        \
  37   struct rtattr *rta;                      \
  38   if (skb_tailroom(skb) < RTA_ALIGN(rtalen)) goto nlmsg_failure; \
  39   rta = (void*)__skb_put(skb, RTA_ALIGN(rtalen)); \
  40   rta->rta_type = attrtype;                \
  41   rta->rta_len = rtalen;                   \
  42   RTA_DATA(rta); })
  43
  44static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
  45                        int ext, u32 pid, u32 seq)
  46{
  47        struct inet_opt *inet = inet_sk(sk);
  48        struct tcp_opt *tp = tcp_sk(sk);
  49        struct tcpdiagmsg *r;
  50        struct nlmsghdr  *nlh;
  51        struct tcp_info  *info = NULL;
  52        struct tcpdiag_meminfo  *minfo = NULL;
  53        unsigned char    *b = skb->tail;
  54
  55        nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
  56        r = NLMSG_DATA(nlh);
  57        if (sk->sk_state != TCP_TIME_WAIT) {
  58                if (ext & (1<<(TCPDIAG_MEMINFO-1)))
  59                        minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo));
  60                if (ext & (1<<(TCPDIAG_INFO-1)))
  61                        info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
  62        }
  63        r->tcpdiag_family = sk->sk_family;
  64        r->tcpdiag_state = sk->sk_state;
  65        r->tcpdiag_timer = 0;
  66        r->tcpdiag_retrans = 0;
  67
  68        r->id.tcpdiag_if = sk->sk_bound_dev_if;
  69        r->id.tcpdiag_cookie[0] = (u32)(unsigned long)sk;
  70        r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
  71
  72        if (r->tcpdiag_state == TCP_TIME_WAIT) {
  73                struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
  74                long tmo = tw->tw_ttd - jiffies;
  75                if (tmo < 0)
  76                        tmo = 0;
  77
  78                r->id.tcpdiag_sport = tw->tw_sport;
  79                r->id.tcpdiag_dport = tw->tw_dport;
  80                r->id.tcpdiag_src[0] = tw->tw_rcv_saddr;
  81                r->id.tcpdiag_dst[0] = tw->tw_daddr;
  82                r->tcpdiag_state = tw->tw_substate;
  83                r->tcpdiag_timer = 3;
  84                r->tcpdiag_expires = (tmo*1000+HZ-1)/HZ;
  85                r->tcpdiag_rqueue = 0;
  86                r->tcpdiag_wqueue = 0;
  87                r->tcpdiag_uid = 0;
  88                r->tcpdiag_inode = 0;
  89#ifdef CONFIG_IPV6
  90                if (r->tcpdiag_family == AF_INET6) {
  91                        ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
  92                                       &tw->tw_v6_rcv_saddr);
  93                        ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
  94                                       &tw->tw_v6_daddr);
  95                }
  96#endif
  97                nlh->nlmsg_len = skb->tail - b;
  98                return skb->len;
  99        }
 100
 101        r->id.tcpdiag_sport = inet->sport;
 102        r->id.tcpdiag_dport = inet->dport;
 103        r->id.tcpdiag_src[0] = inet->rcv_saddr;
 104        r->id.tcpdiag_dst[0] = inet->daddr;
 105
 106#ifdef CONFIG_IPV6
 107        if (r->tcpdiag_family == AF_INET6) {
 108                struct ipv6_pinfo *np = inet6_sk(sk);
 109
 110                ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
 111                               &np->rcv_saddr);
 112                ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
 113                               &np->daddr);
 114        }
 115#endif
 116
 117#define EXPIRES_IN_MS(tmo)  ((tmo-jiffies)*1000+HZ-1)/HZ
 118
 119        if (tp->pending == TCP_TIME_RETRANS) {
 120                r->tcpdiag_timer = 1;
 121                r->tcpdiag_retrans = tp->retransmits;
 122                r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
 123        } else if (tp->pending == TCP_TIME_PROBE0) {
 124                r->tcpdiag_timer = 4;
 125                r->tcpdiag_retrans = tp->probes_out;
 126                r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
 127        } else if (timer_pending(&sk->sk_timer)) {
 128                r->tcpdiag_timer = 2;
 129                r->tcpdiag_retrans = tp->probes_out;
 130                r->tcpdiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
 131        } else {
 132                r->tcpdiag_timer = 0;
 133                r->tcpdiag_expires = 0;
 134        }
 135#undef EXPIRES_IN_MS
 136
 137        r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq;
 138        r->tcpdiag_wqueue = tp->write_seq - tp->snd_una;
 139        r->tcpdiag_uid = sock_i_uid(sk);
 140        r->tcpdiag_inode = sock_i_ino(sk);
 141
 142        if (minfo) {
 143                minfo->tcpdiag_rmem = atomic_read(&sk->sk_rmem_alloc);
 144                minfo->tcpdiag_wmem = sk->sk_wmem_queued;
 145                minfo->tcpdiag_fmem = sk->sk_forward_alloc;
 146                minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc);
 147        }
 148
 149        if (info) {
 150                u32 now = tcp_time_stamp;
 151
 152                info->tcpi_state = sk->sk_state;
 153                info->tcpi_ca_state = tp->ca_state;
 154                info->tcpi_retransmits = tp->retransmits;
 155                info->tcpi_probes = tp->probes_out;
 156                info->tcpi_backoff = tp->backoff;
 157                info->tcpi_options = 0;
 158                if (tp->tstamp_ok)
 159                        info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
 160                if (tp->sack_ok)
 161                        info->tcpi_options |= TCPI_OPT_SACK;
 162                if (tp->wscale_ok) {
 163                        info->tcpi_options |= TCPI_OPT_WSCALE;
 164                        info->tcpi_snd_wscale = tp->snd_wscale;
 165                        info->tcpi_rcv_wscale = tp->rcv_wscale;
 166                } else {
 167                        info->tcpi_snd_wscale = 0;
 168                        info->tcpi_rcv_wscale = 0;
 169                }
 170#ifdef CONFIG_INET_ECN
 171                if (tp->ecn_flags&TCP_ECN_OK)
 172                        info->tcpi_options |= TCPI_OPT_ECN;
 173#endif
 174
 175                info->tcpi_rto = (1000000*tp->rto)/HZ;
 176                info->tcpi_ato = (1000000*tp->ack.ato)/HZ;
 177                info->tcpi_snd_mss = tp->mss_cache;
 178                info->tcpi_rcv_mss = tp->ack.rcv_mss;
 179
 180                info->tcpi_unacked = tp->packets_out;
 181                info->tcpi_sacked = tp->sacked_out;
 182                info->tcpi_lost = tp->lost_out;
 183                info->tcpi_retrans = tp->retrans_out;
 184                info->tcpi_fackets = tp->fackets_out;
 185
 186                info->tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ;
 187                info->tcpi_last_ack_sent = 0;
 188                info->tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ;
 189                info->tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ;
 190
 191                info->tcpi_pmtu = tp->pmtu_cookie;
 192                info->tcpi_rcv_ssthresh = tp->rcv_ssthresh;
 193                info->tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3;
 194                info->tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2;
 195                info->tcpi_snd_ssthresh = tp->snd_ssthresh;
 196                info->tcpi_snd_cwnd = tp->snd_cwnd;
 197                info->tcpi_advmss = tp->advmss;
 198                info->tcpi_reordering = tp->reordering;
 199        }
 200
 201        nlh->nlmsg_len = skb->tail - b;
 202        return skb->len;
 203
 204nlmsg_failure:
 205        skb_trim(skb, b - skb->data);
 206        return -1;
 207}
 208
 209extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
 210#ifdef CONFIG_IPV6
 211extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
 212                                  struct in6_addr *daddr, u16 dport,
 213                                  int dif);
 214#endif
 215
 216static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
 217{
 218        int err;
 219        struct sock *sk;
 220        struct tcpdiagreq *req = NLMSG_DATA(nlh);
 221        struct sk_buff *rep;
 222
 223        if (req->tcpdiag_family == AF_INET) {
 224                sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport,
 225                                   req->id.tcpdiag_src[0], req->id.tcpdiag_sport,
 226                                   req->id.tcpdiag_if);
 227        }
 228#ifdef CONFIG_IPV6
 229        else if (req->tcpdiag_family == AF_INET6) {
 230                sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport,
 231                                   (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport,
 232                                   req->id.tcpdiag_if);
 233        }
 234#endif
 235        else {
 236                return -EINVAL;
 237        }
 238
 239        if (sk == NULL)
 240                return -ENOENT;
 241
 242        err = -ESTALE;
 243        if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
 244             req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
 245            ((u32)(unsigned long)sk != req->id.tcpdiag_cookie[0] ||
 246             (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.tcpdiag_cookie[1]))
 247                goto out;
 248
 249        err = -ENOMEM;
 250        rep = alloc_skb(NLMSG_SPACE(sizeof(struct tcpdiagmsg)+
 251                                    sizeof(struct tcpdiag_meminfo)+
 252                                    sizeof(struct tcp_info)+64), GFP_KERNEL);
 253        if (!rep)
 254                goto out;
 255
 256        if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
 257                         NETLINK_CB(in_skb).pid,
 258                         nlh->nlmsg_seq) <= 0)
 259                BUG();
 260
 261        err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
 262        if (err > 0)
 263                err = 0;
 264
 265out:
 266        if (sk) {
 267                if (sk->sk_state == TCP_TIME_WAIT)
 268                        tcp_tw_put((struct tcp_tw_bucket*)sk);
 269                else
 270                        sock_put(sk);
 271        }
 272        return err;
 273}
 274
 275static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
 276{
 277        int words = bits >> 5;
 278
 279        bits &= 0x1f;
 280
 281        if (words) {
 282                if (memcmp(a1, a2, words << 2))
 283                        return 0;
 284        }
 285        if (bits) {
 286                __u32 w1, w2;
 287                __u32 mask;
 288
 289                w1 = a1[words];
 290                w2 = a2[words];
 291
 292                mask = htonl((0xffffffff) << (32 - bits));
 293
 294                if ((w1 ^ w2) & mask)
 295                        return 0;
 296        }
 297
 298        return 1;
 299}
 300
 301
 302static int tcpdiag_bc_run(const void *bc, int len, struct sock *sk)
 303{
 304        while (len > 0) {
 305                int yes = 1;
 306                struct inet_opt *inet = inet_sk(sk);
 307                const struct tcpdiag_bc_op *op = bc;
 308
 309                switch (op->code) {
 310                case TCPDIAG_BC_NOP:
 311                        break;
 312                case TCPDIAG_BC_JMP:
 313                        yes = 0;
 314                        break;
 315                case TCPDIAG_BC_S_GE:
 316                        yes = inet->num >= op[1].no;
 317                        break;
 318                case TCPDIAG_BC_S_LE:
 319                        yes = inet->num <= op[1].no;
 320                        break;
 321                case TCPDIAG_BC_D_GE:
 322                        yes = ntohs(inet->dport) >= op[1].no;
 323                        break;
 324                case TCPDIAG_BC_D_LE:
 325                        yes = ntohs(inet->dport) <= op[1].no;
 326                        break;
 327                case TCPDIAG_BC_AUTO:
 328                        yes = !(sk->sk_userlocks & SOCK_BINDPORT_LOCK);
 329                        break;
 330                case TCPDIAG_BC_S_COND:
 331                case TCPDIAG_BC_D_COND:
 332                {
 333                        struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1);
 334                        u32 *addr;
 335
 336                        if (cond->port != -1 &&
 337                            cond->port != (op->code == TCPDIAG_BC_S_COND ?
 338                                             inet->num : ntohs(inet->dport))) {
 339                                yes = 0;
 340                                break;
 341                        }
 342                        
 343                        if (cond->prefix_len == 0)
 344                                break;
 345
 346#ifdef CONFIG_IPV6
 347                        if (sk->sk_family == AF_INET6) {
 348                                struct ipv6_pinfo *np = inet6_sk(sk);
 349
 350                                if (op->code == TCPDIAG_BC_S_COND)
 351                                        addr = (u32*)&np->rcv_saddr;
 352                                else
 353                                        addr = (u32*)&np->daddr;
 354                        } else
 355#endif
 356                        {
 357                                if (op->code == TCPDIAG_BC_S_COND)
 358                                        addr = &inet->rcv_saddr;
 359                                else
 360                                        addr = &inet->daddr;
 361                        }
 362
 363                        if (bitstring_match(addr, cond->addr, cond->prefix_len))
 364                                break;
 365                        if (sk->sk_family == AF_INET6 &&
 366                            cond->family == AF_INET) {
 367                                if (addr[0] == 0 && addr[1] == 0 &&
 368                                    addr[2] == htonl(0xffff) &&
 369                                    bitstring_match(addr+3, cond->addr, cond->prefix_len))
 370                                        break;
 371                        }
 372                        yes = 0;
 373                        break;
 374                }
 375                }
 376
 377                if (yes) { 
 378                        len -= op->yes;
 379                        bc += op->yes;
 380                } else {
 381                        len -= op->no;
 382                        bc += op->no;
 383                }
 384        }
 385        return (len == 0);
 386}
 387
 388static int valid_cc(const void *bc, int len, int cc)
 389{
 390        while (len >= 0) {
 391                const struct tcpdiag_bc_op *op = bc;
 392
 393                if (cc > len)
 394                        return 0;
 395                if (cc == len)
 396                        return 1;
 397                if (op->yes < 4)
 398                        return 0;
 399                len -= op->yes;
 400                bc  += op->yes;
 401        }
 402        return 0;
 403}
 404
 405static int tcpdiag_bc_audit(const void *bytecode, int bytecode_len)
 406{
 407        const unsigned char *bc = bytecode;
 408        int  len = bytecode_len;
 409
 410        while (len > 0) {
 411                struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
 412
 413//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
 414                switch (op->code) {
 415                case TCPDIAG_BC_AUTO:
 416                case TCPDIAG_BC_S_COND:
 417                case TCPDIAG_BC_D_COND:
 418                case TCPDIAG_BC_S_GE:
 419                case TCPDIAG_BC_S_LE:
 420                case TCPDIAG_BC_D_GE:
 421                case TCPDIAG_BC_D_LE:
 422                        if (op->yes < 4 || op->yes > len+4)
 423                                return -EINVAL;
 424                case TCPDIAG_BC_JMP:
 425                        if (op->no < 4 || op->no > len+4)
 426                                return -EINVAL;
 427                        if (op->no < len &&
 428                            !valid_cc(bytecode, bytecode_len, len-op->no))
 429                                return -EINVAL;
 430                        break;
 431                case TCPDIAG_BC_NOP:
 432                        if (op->yes < 4 || op->yes > len+4)
 433                                return -EINVAL;
 434                        break;
 435                default:
 436                        return -EINVAL;
 437                }
 438                bc += op->yes;
 439                len -= op->yes;
 440        }
 441        return len == 0 ? 0 : -EINVAL;
 442}
 443
 444
 445static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 446{
 447        int i, num;
 448        int s_i, s_num;
 449        struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
 450        struct rtattr *bc = NULL;
 451
 452        if (cb->nlh->nlmsg_len > 4+NLMSG_SPACE(sizeof(struct tcpdiagreq)))
 453                bc = (struct rtattr*)(r+1);
 454
 455        s_i = cb->args[1];
 456        s_num = num = cb->args[2];
 457
 458        if (cb->args[0] == 0) {
 459                if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV)))
 460                        goto skip_listen_ht;
 461                tcp_listen_lock();
 462                for (i = s_i; i < TCP_LHTABLE_SIZE; i++) {
 463                        struct sock *sk;
 464                        struct hlist_node *node;
 465
 466                        if (i > s_i)
 467                                s_num = 0;
 468
 469                        num = 0;
 470                        sk_for_each(sk, node, &tcp_listening_hash[i]) {
 471                                struct inet_opt *inet = inet_sk(sk);
 472                                if (num < s_num)
 473                                        continue;
 474                                if (!(r->tcpdiag_states&TCPF_LISTEN) ||
 475                                    r->id.tcpdiag_dport)
 476                                        continue;
 477                                if (r->id.tcpdiag_sport != inet->sport &&
 478                                    r->id.tcpdiag_sport)
 479                                        continue;
 480                                if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
 481                                        continue;
 482                                if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
 483                                                 NETLINK_CB(cb->skb).pid,
 484                                                 cb->nlh->nlmsg_seq) <= 0) {
 485                                        tcp_listen_unlock();
 486                                        goto done;
 487                                }
 488                                ++num;
 489                        }
 490                }
 491                tcp_listen_unlock();
 492skip_listen_ht:
 493                cb->args[0] = 1;
 494                s_i = num = s_num = 0;
 495        }
 496
 497        if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV)))
 498                return skb->len;
 499
 500        for (i = s_i; i < tcp_ehash_size; i++) {
 501                struct tcp_ehash_bucket *head = &tcp_ehash[i];
 502                struct sock *sk;
 503                struct hlist_node *node;
 504
 505                if (i > s_i)
 506                        s_num = 0;
 507
 508                read_lock_bh(&head->lock);
 509
 510                num = 0;
 511                sk_for_each(sk, node, &head->chain) {
 512                        struct inet_opt *inet = inet_sk(sk);
 513
 514                        if (num < s_num)
 515                                continue;
 516                        if (!(r->tcpdiag_states & (1 << sk->sk_state)))
 517                                continue;
 518                        if (r->id.tcpdiag_sport != inet->sport &&
 519                            r->id.tcpdiag_sport)
 520                                continue;
 521                        if (r->id.tcpdiag_dport != inet->dport && r->id.tcpdiag_dport)
 522                                continue;
 523                        if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
 524                                continue;
 525                        if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
 526                                         NETLINK_CB(cb->skb).pid,
 527                                         cb->nlh->nlmsg_seq) <= 0) {
 528                                read_unlock_bh(&head->lock);
 529                                goto done;
 530                        }
 531                        ++num;
 532                }
 533
 534                if (r->tcpdiag_states&TCPF_TIME_WAIT) {
 535                        sk_for_each(sk, node,
 536                                    &tcp_ehash[i + tcp_ehash_size].chain) {
 537                                struct inet_opt *inet = inet_sk(sk);
 538
 539                                if (num < s_num)
 540                                        continue;
 541                                if (!(r->tcpdiag_states & (1 << sk->sk_zapped)))
 542                                        continue;
 543                                if (r->id.tcpdiag_sport != inet->sport &&
 544                                    r->id.tcpdiag_sport)
 545                                        continue;
 546                                if (r->id.tcpdiag_dport != inet->dport &&
 547                                    r->id.tcpdiag_dport)
 548                                        continue;
 549                                if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
 550                                        continue;
 551                                if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
 552                                                 NETLINK_CB(cb->skb).pid,
 553                                                 cb->nlh->nlmsg_seq) <= 0) {
 554                                        read_unlock_bh(&head->lock);
 555                                        goto done;
 556                                }
 557                                ++num;
 558                        }
 559                }
 560                read_unlock_bh(&head->lock);
 561        }
 562
 563done:
 564        cb->args[1] = i;
 565        cb->args[2] = num;
 566        return skb->len;
 567}
 568
 569static int tcpdiag_dump_done(struct netlink_callback *cb)
 570{
 571        return 0;
 572}
 573
 574
 575static __inline__ int
 576tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 577{
 578        if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
 579                return 0;
 580
 581        if (nlh->nlmsg_type != TCPDIAG_GETSOCK)
 582                goto err_inval;
 583
 584        if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len)
 585                goto err_inval;
 586
 587        if (nlh->nlmsg_flags&NLM_F_DUMP) {
 588                if (nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq))) {
 589                        struct rtattr *rta = (struct rtattr*)(NLMSG_DATA(nlh) + sizeof(struct tcpdiagreq));
 590                        if (rta->rta_type != TCPDIAG_REQ_BYTECODE ||
 591                            rta->rta_len < 8 ||
 592                            rta->rta_len > nlh->nlmsg_len - NLMSG_SPACE(sizeof(struct tcpdiagreq)))
 593                                goto err_inval;
 594                        if (tcpdiag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
 595                                goto err_inval;
 596                }
 597                return netlink_dump_start(tcpnl, skb, nlh,
 598                                          tcpdiag_dump,
 599                                          tcpdiag_dump_done);
 600        } else {
 601                return tcpdiag_get_exact(skb, nlh);
 602        }
 603
 604err_inval:
 605        return -EINVAL;
 606}
 607
 608
 609static inline void tcpdiag_rcv_skb(struct sk_buff *skb)
 610{
 611        int err;
 612        struct nlmsghdr * nlh;
 613
 614        if (skb->len >= NLMSG_SPACE(0)) {
 615                nlh = (struct nlmsghdr *)skb->data;
 616                if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
 617                        return;
 618                err = tcpdiag_rcv_msg(skb, nlh);
 619                if (err || nlh->nlmsg_flags & NLM_F_ACK) 
 620                        netlink_ack(skb, nlh, err);
 621        }
 622}
 623
 624static void tcpdiag_rcv(struct sock *sk, int len)
 625{
 626        struct sk_buff *skb;
 627
 628        while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 629                tcpdiag_rcv_skb(skb);
 630                kfree_skb(skb);
 631        }
 632}
 633
 634void __init tcpdiag_init(void)
 635{
 636        tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv);
 637        if (tcpnl == NULL)
 638                panic("tcpdiag_init: Cannot create netlink socket.");
 639}
 640
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.