++ /* save original call ID in nat_info */
++ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
++
++ /* don't use tcph->source since we are at a DSTmanip
++ * hook (e.g. PREROUTING) and pkt is not mangled yet */
++ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
++
++ /* save new call ID in ct info */
++ ct_pptp_info->pns_call_id = ntohs(new_callid);
++ break;
++ case PPTP_IN_CALL_REPLY:
++ cid = &pptpReq.icreq->callID;
++ break;
++ case PPTP_CALL_CLEAR_REQUEST:
++ cid = &pptpReq.clrreq->callID;
++ break;
++ default:
++ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
++ /* fall through */
++
++ case PPTP_SET_LINK_INFO:
++ /* only need to NAT in case PAC is behind NAT box */
++ case PPTP_START_SESSION_REQUEST:
++ case PPTP_START_SESSION_REPLY:
++ case PPTP_STOP_SESSION_REQUEST:
++ case PPTP_STOP_SESSION_REPLY:
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* no need to alter packet */
++ return NF_ACCEPT;
++ }
++
++ IP_NF_ASSERT(cid);
++
++ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
++ ntohs(*cid), ntohs(new_callid));
++
++ /* mangle packet */
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
++ sizeof(new_callid), (char *)&new_callid,
++ sizeof(new_callid));
++
++ return NF_ACCEPT;
++}
++
++/* inbound packets == from PAC to PNS */
++static inline unsigned int
++pptp_inbound_pkt(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *oldexp)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
++ ((void *)tcph + tcph->doff*4);
++
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
++
++ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
++ u_int32_t old_dst_ip;
++
++ struct ip_conntrack_tuple t, inv_t;
++ struct ip_conntrack_tuple *orig_t, *reply_t;
++
++ /* FIXME: size checks !!! */
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ new_pcid = htons(nat_pptp_info->pns_call_id);
++
++ switch (msg = ntohs(ctlh->messageType)) {
++ case PPTP_OUT_CALL_REPLY:
++ pcid = &pptpReq.ocack->peersCallID;
++ cid = &pptpReq.ocack->callID;
++ if (!oldexp) {
++ DEBUGP("outcall but no expectation\n");
++ break;
++ }
++ old_dst_ip = oldexp->tuple.dst.ip;
++ t = oldexp->tuple;
++ invert_tuplepr(&inv_t, &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;
++ if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
++ /* expectation for PNS->PAC direction */
++ t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
++ t.dst.u.gre.key = htonl(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 = htonl(nat_pptp_info->pac_call_id);
++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
++ } else {
++ /* expectation for PAC->PNS direction */
++ t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
++ t.dst.u.gre.key = htonl(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 = htonl(nat_pptp_info->pns_call_id);
++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);