static int inet_diag_bc_run(const struct nlattr *_bc, const struct inet_diag_entry *entry) { const void *bc = nla_data(_bc); int len = nla_len(_bc); while (len > 0) { int yes = 1; const struct inet_diag_bc_op *op = bc; switch (op->code) { case INET_DIAG_BC_NOP: break; case INET_DIAG_BC_JMP: yes = 0; break; case INET_DIAG_BC_S_GE: yes = entry->sport >= op[1].no; break; case INET_DIAG_BC_S_LE: yes = entry->sport <= op[1].no; break; case INET_DIAG_BC_D_GE: yes = entry->dport >= op[1].no; break; case INET_DIAG_BC_D_LE: yes = entry->dport <= op[1].no; break; case INET_DIAG_BC_AUTO: yes = !(entry->userlocks & SOCK_BINDPORT_LOCK); break; case INET_DIAG_BC_S_COND: case INET_DIAG_BC_D_COND: { const struct inet_diag_hostcond *cond; const __be32 *addr; cond = (const struct inet_diag_hostcond *)(op + 1); if (cond->port != -1 && cond->port != (op->code == INET_DIAG_BC_S_COND ? entry->sport : entry->dport)) { yes = 0; break; } if (op->code == INET_DIAG_BC_S_COND) addr = entry->saddr; else addr = entry->daddr; if (cond->family != AF_UNSPEC && cond->family != entry->family) { if (entry->family == AF_INET6 && cond->family == AF_INET) { if (addr[0] == 0 && addr[1] == 0 && addr[2] == htonl(0xffff) && bitstring_match(addr + 3, cond->addr, cond->prefix_len)) break; } yes = 0; break; } if (cond->prefix_len == 0) break; if (bitstring_match(addr, cond->addr, cond->prefix_len)) break; yes = 0; break; } } if (yes) { len -= op->yes; bc += op->yes; } else { len -= op->no; bc += op->no; } } return len == 0; }
int tcpdiag_bc_run(char *bc, int len, struct sock *sk) { while (len > 0) { int yes = 1; struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc; switch (op->code) { case TCPDIAG_BC_NOP: break; case TCPDIAG_BC_JMP: yes = 0; break; case TCPDIAG_BC_S_GE: yes = (sk->num >= op[1].no); break; case TCPDIAG_BC_S_LE: yes = (sk->num <= op[1].no); break; case TCPDIAG_BC_D_GE: yes = (ntohs(sk->dport) >= op[1].no); break; case TCPDIAG_BC_D_LE: yes = (ntohs(sk->dport) <= op[1].no); break; case TCPDIAG_BC_AUTO: yes = !(sk->userlocks&SOCK_BINDPORT_LOCK); break; case TCPDIAG_BC_S_COND: case TCPDIAG_BC_D_COND: { struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1); u32 *addr; if (cond->port != -1 && cond->port != (op->code == TCPDIAG_BC_S_COND ? sk->num : ntohs(sk->dport))) { yes = 0; break; } if (cond->prefix_len == 0) break; #ifdef CONFIG_IPV6 if (sk->family == AF_INET6) { if (op->code == TCPDIAG_BC_S_COND) addr = (u32*)&sk->net_pinfo.af_inet6.rcv_saddr; else addr = (u32*)&sk->net_pinfo.af_inet6.daddr; } else #endif { if (op->code == TCPDIAG_BC_S_COND) addr = &sk->rcv_saddr; else addr = &sk->daddr; } if (bitstring_match(addr, cond->addr, cond->prefix_len)) break; if (sk->family == AF_INET6 && cond->family == AF_INET) { if (addr[0] == 0 && addr[1] == 0 && addr[2] == __constant_htonl(0xffff) && bitstring_match(addr+3, cond->addr, cond->prefix_len)) break; } yes = 0; break; } } if (yes) { len -= op->yes; bc += op->yes; } else { len -= op->no; bc += op->no; } } return (len == 0); }