/* timeout GRE data connections */ static int pptp_timeout_related(struct ip_conntrack *ct) { struct list_head *cur_item, *next; struct ip_conntrack_expect *exp; /* FIXME: do we have to lock something ? */ for (cur_item = ct->sibling_list.next; cur_item != &ct->sibling_list; cur_item = next) { next = cur_item->next; exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); ip_ct_gre_keymap_destroy(exp); if (!exp->sibling) { ip_conntrack_unexpect_related(exp); continue; } DEBUGP("setting timeout of conntrack %p to 0\n", exp->sibling); exp->sibling->proto.gre.timeout = 0; exp->sibling->proto.gre.stream_timeout = 0; ip_ct_refresh(exp->sibling, 0); } return 0; }
static void pptp_expectfn(struct ip_conntrack *ct, struct ip_conntrack_expect *exp) { DEBUGP("increasing timeouts\n"); /* increase timeout of GRE data channel conntrack entry */ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; /* Can you see how rusty this code is, compared with the pre-2.6.11 * one? That's what happened to my shiny newnat of 2002 ;( -HW */ if (!ip_nat_pptp_hook_expectfn) { struct ip_conntrack_tuple inv_t; struct ip_conntrack_expect *exp_other; /* obviously this tuple inversion only works until you do NAT */ invert_tuplepr(&inv_t, &exp->tuple); DEBUGP("trying to unexpect other dir: "); DUMP_TUPLE(&inv_t); exp_other = __ip_conntrack_exp_find(&inv_t); if (exp_other) { /* delete other expectation. */ DEBUGP("found\n"); ip_conntrack_unexpect_related(exp_other); } else { DEBUGP("not found\n"); } } else { /* we need more than simple inversion */ ip_nat_pptp_hook_expectfn(ct, exp); } }
static int timeout_ct_or_exp(const struct ip_conntrack_tuple *t) { struct ip_conntrack_tuple_hash *h; struct ip_conntrack_expect *exp; DEBUGP("trying to timeout ct or exp for tuple "); DUMP_TUPLE(t); h = __ip_conntrack_find(t, NULL); if (h) { struct ip_conntrack *sibling = tuplehash_to_ctrack(h); DEBUGP("setting timeout of conntrack %p to 0\n", sibling); sibling->proto.gre.timeout = 0; sibling->proto.gre.stream_timeout = 0; /* refresh_acct will not modify counters if skb == NULL */ ip_ct_refresh_acct(sibling, 0, NULL, 0); return 1; } else { exp = __ip_conntrack_exp_find(t); if (exp) { DEBUGP("unexpect_related of expect %p\n", exp); ip_conntrack_unexpect_related(exp); return 1; } } return 0; }
static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) { struct ip_conntrack_tuple_hash *h; struct ip_conntrack_expect *exp; DEBUGP("trying to timeout ct or exp for tuple "); DUMP_TUPLE(t); h = ip_conntrack_find_get(t, NULL); if (h) { struct ip_conntrack *sibling = tuplehash_to_ctrack(h); DEBUGP("setting timeout of conntrack %p to 0\n", sibling); sibling->proto.gre.timeout = 0; sibling->proto.gre.stream_timeout = 0; if (del_timer(&sibling->timeout)) sibling->timeout.function((unsigned long)sibling); ip_conntrack_put(sibling); return 1; } else { exp = ip_conntrack_expect_find(t); if (exp) { DEBUGP("unexpect_related of expect %p\n", exp); ip_conntrack_unexpect_related(exp); ip_conntrack_expect_put(exp); return 1; } } return 0; }
/* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_ftp(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, enum ip_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack_expect *exp, u32 *seq) { u_int32_t newip; u_int16_t port; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack *ct = exp->master; DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); /* Connection will come from wherever this packet goes, hence !dir */ newip = ct->tuplehash[!dir].tuple.dst.ip; exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->dir = !dir; /* When you see the packet, we need to NAT it the same as the * this one. */ exp->expectfn = ip_nat_follow_master; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { exp->tuple.dst.u.tcp.port = htons(port); if (ip_conntrack_expect_related(exp) == 0) break; } if (port == 0) { ip_conntrack_expect_free(exp); return NF_DROP; } if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, seq)) { ip_conntrack_unexpect_related(exp); return NF_DROP; } return NF_ACCEPT; }
static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, H245_TransportAddress * addr, u_int16_t port, struct ip_conntrack_expect *exp) { int dir = CTINFO2DIR(ctinfo); u_int16_t nated_port = port; /* Set expectations for NAT */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->expectfn = ip_nat_follow_master; exp->dir = !dir; /* Try to get same port: if not, try to change it. */ for (; nated_port != 0; nated_port++) { exp->tuple.dst.u.tcp.port = htons(nated_port); if (ip_conntrack_expect_related(exp) == 0) break; } if (nated_port == 0) { /* No port available */ if (net_ratelimit()) printk("ip_nat_h323: out of TCP ports\n"); return 0; } /* Modify signal */ if (set_h245_addr(pskb, data, dataoff, addr, ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) { ip_conntrack_unexpect_related(exp); return -1; } DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); return 0; }
/* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack_expect *exp, const char *dptr) { struct ip_conntrack *ct = exp->master; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); u_int32_t newip; u_int16_t port; DEBUGP("ip_nat_sdp():\n"); /* Connection will come from reply */ newip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.ip = newip; exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; exp->dir = !dir; /* When you see the packet, we need to NAT it the same as the this one. */ exp->expectfn = ip_nat_follow_master; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { exp->tuple.dst.u.udp.port = htons(port); if (ip_conntrack_expect_related(exp) == 0) break; } if (port == 0) return NF_DROP; if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { ip_conntrack_unexpect_related(exp); return NF_DROP; } return NF_ACCEPT; }
static unsigned int help(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack_expect *exp) { char buffer[sizeof("65535")]; u_int16_t port; unsigned int ret; /* Connection comes from client. */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->dir = IP_CT_DIR_ORIGINAL; /* When you see the packet, we need to NAT it the same as the * this one (ie. same IP: it will be TCP and master is UDP). */ exp->expectfn = ip_nat_follow_master; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { exp->tuple.dst.u.tcp.port = htons(port); if (ip_conntrack_expect_related(exp) == 0) break; } if (port == 0) { ip_conntrack_expect_free(exp); return NF_DROP; } sprintf(buffer, "%u", port); ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); if (ret != NF_ACCEPT) ip_conntrack_unexpect_related(exp); return ret; }
static int pptp_expectfn(struct ip_conntrack *ct) { struct ip_conntrack *master; struct ip_conntrack_expect *exp; #ifdef CONFIG_IFX_ALG_QOS // chandrav IFX_ALG_QOS_DBG("\nPPTP_ALG: Master conntracker ifx_alg_qos_mark is : %x \n",ct->ifx_alg_qos_mark ); /* * Mark the connection tracker with PPTP ALG Application Family type * (IFX_ALG_PROTO_DATA) and PPTP ALG Protocol Family type * (IFX_ALG_PROTO_DATA) */ ct->ifx_alg_qos_mark = IFX_ALG_APP_PPTP | IFX_ALG_PROTO_DATA; IFX_ALG_QOS_DBG("\nPPTP ALG:Marked the Child conntracker with:%x \n", ct->ifx_alg_qos_mark ); #endif /* CONFIG_IFX_ALG_QOS */ DEBUGP("increasing timeouts\n"); /* increase timeout of GRE data channel conntrack entry */ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; master = master_ct(ct); if (!master) { DEBUGP(" no master!!!\n"); return 0; } exp = ct->master; if (!exp) { DEBUGP("no expectation!!\n"); return 0; } DEBUGP("completing tuples with ct info\n"); /* we can do this, since we're unconfirmed */ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == htonl(master->help.ct_pptp_info.pac_call_id)) { /* assume PNS->PAC */ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(master->help.ct_pptp_info.pns_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(master->help.ct_pptp_info.pns_call_id); } else { /* assume PAC->PNS */ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(master->help.ct_pptp_info.pac_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(master->help.ct_pptp_info.pac_call_id); } /* delete other expectation */ if (exp->expected_list.next != &exp->expected_list) { struct ip_conntrack_expect *other_exp; struct list_head *cur_item, *next; for (cur_item = master->sibling_list.next; cur_item != &master->sibling_list; cur_item = next) { next = cur_item->next; other_exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); /* remove only if occurred at same sequence number */ if (other_exp != exp && other_exp->seq == exp->seq) { DEBUGP("unexpecting other direction\n"); ip_ct_gre_keymap_destroy(other_exp); ip_conntrack_unexpect_related(other_exp); } } } return 0; }
static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, H245_TransportAddress * addr, u_int16_t port, u_int16_t rtp_port, struct ip_conntrack_expect *rtp_exp, struct ip_conntrack_expect *rtcp_exp) { struct ip_ct_h323_master *info = &ct->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int i; u_int16_t nated_port; /* Set expectations for NAT */ rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; rtp_exp->expectfn = ip_nat_follow_master; rtp_exp->dir = !dir; rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; rtcp_exp->expectfn = ip_nat_follow_master; rtcp_exp->dir = !dir; /* Lookup existing expects */ for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { if (info->rtp_port[i][dir] == rtp_port) { /* Expected */ /* Use allocated ports first. This will refresh * the expects */ rtp_exp->tuple.dst.u.udp.port = htons(info->rtp_port[i][dir]); rtcp_exp->tuple.dst.u.udp.port = htons(info->rtp_port[i][dir] + 1); break; } else if (info->rtp_port[i][dir] == 0) { /* Not expected */ break; } } /* Run out of expectations */ if (i >= H323_RTP_CHANNEL_MAX) { if (net_ratelimit()) printk("ip_nat_h323: out of expectations\n"); return 0; } /* Try to get a pair of ports. */ for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); nated_port != 0; nated_port += 2) { rtp_exp->tuple.dst.u.udp.port = htons(nated_port); if (ip_conntrack_expect_related(rtp_exp) == 0) { rtcp_exp->tuple.dst.u.udp.port = htons(nated_port + 1); if (ip_conntrack_expect_related(rtcp_exp) == 0) break; ip_conntrack_unexpect_related(rtp_exp); } } if (nated_port == 0) { /* No port available */ if (net_ratelimit()) printk("ip_nat_h323: out of RTP ports\n"); return 0; } /* Modify signal */ if (set_h245_addr(pskb, data, dataoff, addr, ct->tuplehash[!dir].tuple.dst.ip, (port & 1) ? nated_port + 1 : nated_port) == 0) { /* Save ports */ info->rtp_port[i][dir] = rtp_port; info->rtp_port[i][!dir] = nated_port; } else { ip_conntrack_unexpect_related(rtp_exp); ip_conntrack_unexpect_related(rtcp_exp); return -1; } /* Success */ DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(rtp_exp->tuple.src.ip), ntohs(rtp_exp->tuple.src.u.udp.port), NIPQUAD(rtp_exp->tuple.dst.ip), ntohs(rtp_exp->tuple.dst.u.udp.port)); DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(rtcp_exp->tuple.src.ip), ntohs(rtcp_exp->tuple.src.u.udp.port), NIPQUAD(rtcp_exp->tuple.dst.ip), ntohs(rtcp_exp->tuple.dst.u.udp.port)); return 0; }
static void pptp_nat_expected(struct ip_conntrack *ct, struct ip_conntrack_expect *exp) { struct ip_conntrack *master = ct->master; struct ip_conntrack_expect *other_exp; struct ip_conntrack_tuple t; struct ip_ct_pptp_master *ct_pptp_info; struct ip_nat_pptp *nat_pptp_info; struct ip_nat_range range; ct_pptp_info = &master->help.ct_pptp_info; nat_pptp_info = &master->nat.help.nat_pptp_info; /* And here goes the grand finale of corrosion... */ if (exp->dir == IP_CT_DIR_ORIGINAL) { DEBUGP("we are PNS->PAC\n"); /* therefore, build tuple for PAC->PNS */ t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id); t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id); t.dst.protonum = IPPROTO_GRE; } else { DEBUGP("we are PAC->PNS\n"); /* build tuple for PNS->PAC */ t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; t.src.u.gre.key = htons(master->nat.help.nat_pptp_info.pns_call_id); t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; t.dst.u.gre.key = htons(master->nat.help.nat_pptp_info.pac_call_id); t.dst.protonum = IPPROTO_GRE; } DEBUGP("trying to unexpect other dir: \n"); DUMP_TUPLE(&t); other_exp = __ip_conntrack_exp_find(&t); if (other_exp) { ip_conntrack_unexpect_related(other_exp); DEBUGP("success\n"); } else { DEBUGP("not found!\n"); } /* This must be a fresh one. */ BUG_ON(ct->status & IPS_NAT_DONE_MASK); /* Change src to where master sends to */ range.flags = IP_NAT_RANGE_MAP_IPS; range.min_ip = range.max_ip = ct->master->tuplehash[!exp->dir].tuple.dst.ip; if (exp->dir == IP_CT_DIR_ORIGINAL) { range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; range.min = range.max = exp->saved_proto; } /* hook doesn't matter, but it has to do source manip */ ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); /* For DST manip, map port here to where it's expected. */ range.flags = IP_NAT_RANGE_MAP_IPS; range.min_ip = range.max_ip = ct->master->tuplehash[!exp->dir].tuple.src.ip; //sam add +++ 2008.10.03 for pptp passthrough can not work. ct->tuplehash[!exp->dir].tuple.dst.u.gre.key = t.dst.u.gre.key; //sam add --- if (exp->dir == IP_CT_DIR_REPLY) { range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; range.min = range.max = exp->saved_proto; } /* hook doesn't matter, but it has to do destination manip */ ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); }
static int pptp_exp_gre(struct ip_conntrack_expect *expect_orig, struct ip_conntrack_expect *expect_reply) { struct ip_ct_pptp_master *ct_pptp_info = &expect_orig->master->help.ct_pptp_info; struct ip_nat_pptp *nat_pptp_info = &expect_orig->master->nat.help.nat_pptp_info; struct ip_conntrack *ct = expect_orig->master; struct ip_conntrack_tuple inv_t; struct ip_conntrack_tuple *orig_t, *reply_t; /* save original PAC call ID in nat_info */ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; /* alter expectation */ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; /* alter expectation for PNS->PAC direction */ invert_tuplepr(&inv_t, &expect_orig->tuple); expect_orig->saved_proto.gre.key = htons(ct_pptp_info->pns_call_id); expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id); expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); inv_t.src.ip = reply_t->src.ip; inv_t.dst.ip = reply_t->dst.ip; inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id); inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); if (!ip_conntrack_expect_related(expect_orig)) { DEBUGP("successfully registered expect\n"); } else { DEBUGP("can't expect_related(expect_orig)\n"); ip_conntrack_expect_free(expect_orig); return 1; } /* alter expectation for PAC->PNS direction */ invert_tuplepr(&inv_t, &expect_reply->tuple); expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id); expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id); expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); inv_t.src.ip = orig_t->src.ip; inv_t.dst.ip = orig_t->dst.ip; inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id); inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); if (!ip_conntrack_expect_related(expect_reply)) { DEBUGP("successfully registered expect\n"); } else { DEBUGP("can't expect_related(expect_reply)\n"); ip_conntrack_unexpect_related(expect_orig); ip_conntrack_expect_free(expect_reply); return 1; } if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) { DEBUGP("can't register original keymap\n"); ip_conntrack_unexpect_related(expect_orig); ip_conntrack_unexpect_related(expect_reply); return 1; } if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) { DEBUGP("can't register reply keymap\n"); ip_conntrack_unexpect_related(expect_orig); ip_conntrack_unexpect_related(expect_reply); ip_ct_gre_keymap_destroy(ct); return 1; } return 0; }
static unsigned int help(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack_expect *exp) { u_int16_t port; unsigned int ret; /* "4294967296 65635 " */ char buffer[18]; DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", expect->seq, exp_irc_info->len, ntohl(tcph->seq)); /* Reply comes from server. */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->dir = IP_CT_DIR_REPLY; /* When you see the packet, we need to NAT it the same as the * this one. */ exp->expectfn = ip_nat_follow_master; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { exp->tuple.dst.u.tcp.port = htons(port); if (ip_conntrack_expect_related(exp) == 0) break; } if (port == 0) return NF_DROP; /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26 * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26 * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27 * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits, * 255.255.255.255==4294967296, 10 digits) * P: bound port (min 1 d, max 5d (65635)) * F: filename (min 1 d ) * S: size (min 1 d ) * 0x01, \n: terminators */ /* AAA = "us", ie. where server normally talks to. */ sprintf(buffer, "%u %u", ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), port); DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n", buffer, NIPQUAD(exp->tuple.src.ip), port); ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); if (ret != NF_ACCEPT) ip_conntrack_unexpect_related(exp); return ret; }
static int pptp_expectfn(struct ip_conntrack *ct) { struct ip_conntrack *master; struct ip_conntrack_expect *exp; DEBUGP("increasing timeouts\n"); /* increase timeout of GRE data channel conntrack entry */ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; master = master_ct(ct); if (!master) { DEBUGP(" no master!!!\n"); return 0; } exp = ct->master; if (!exp) { DEBUGP("no expectation!!\n"); return 0; } DEBUGP("completing tuples with ct info\n"); /* we can do this, since we're unconfirmed */ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == htonl(master->help.ct_pptp_info.pac_call_id)) { /* assume PNS->PAC */ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(master->help.ct_pptp_info.pns_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(master->help.ct_pptp_info.pns_call_id); } else { /* assume PAC->PNS */ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(master->help.ct_pptp_info.pac_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(master->help.ct_pptp_info.pac_call_id); } /* delete other expectation */ if (exp->expected_list.next != &exp->expected_list) { struct ip_conntrack_expect *other_exp; struct list_head *cur_item, *next; for (cur_item = master->sibling_list.next; cur_item != &master->sibling_list; cur_item = next) { next = cur_item->next; other_exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); /* remove only if occurred at same sequence number */ if (other_exp != exp && other_exp->seq == exp->seq) { DEBUGP("unexpecting other direction\n"); ip_ct_gre_keymap_destroy(other_exp); ip_conntrack_unexpect_related(other_exp); } } } return 0; }