/*** decaps_gre ***************************************************************/ int decaps_gre (int fd, callback_t callback, int cl) { unsigned char buffer[PACKET_MAX + 64 /*ip header*/]; struct pptp_gre_header *header; int status, ip_len = 0; static int first = 1; unsigned int headersize; unsigned int payload_len; u_int32_t seq; if ((status = read (fd, buffer, sizeof(buffer))) <= 0) { warn("short read (%d): %s", status, strerror(errno)); stats.rx_errors++; return -1; } /* strip off IP header, if present */ if ((buffer[0] & 0xF0) == 0x40) ip_len = (buffer[0] & 0xF) * 4; header = (struct pptp_gre_header *)(buffer + ip_len); /* verify packet (else discard) */ if ( /* version should be 1 */ ((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) || /* PPTP-GRE protocol for PPTP */ (ntoh16(header->protocol) != PPTP_GRE_PROTO)|| /* flag C should be clear */ PPTP_GRE_IS_C(ntoh8(header->flags)) || /* flag R should be clear */ PPTP_GRE_IS_R(ntoh8(header->flags)) || /* flag K should be set */ (!PPTP_GRE_IS_K(ntoh8(header->flags))) || /* routing and recursion ctrl = 0 */ ((ntoh8(header->flags)&0xF) != 0)) { /* if invalid, discard this packet */ warn("Discarding GRE: %X %X %X %X %X %X", ntoh8(header->ver)&0x7F, ntoh16(header->protocol), PPTP_GRE_IS_C(ntoh8(header->flags)), PPTP_GRE_IS_R(ntoh8(header->flags)), PPTP_GRE_IS_K(ntoh8(header->flags)), ntoh8(header->flags) & 0xF); stats.rx_invalid++; return 0; } /* silently discard packets not for this call */ if (ntoh16(header->call_id) != pptp_gre_call_id) return 0; /* test if acknowledgement present */ if (PPTP_GRE_IS_A(ntoh8(header->ver))) { u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))? header->ack:header->seq; /* ack in different place if S = 0 */ ack = ntoh32( ack); if (ack > ack_recv) ack_recv = ack; /* also handle sequence number wrap-around */ if (WRAPPED(ack,ack_recv)) ack_recv = ack; if (ack_recv == stats.pt.seq) { int rtt = time_now_usecs() - stats.pt.time; stats.rtt = (stats.rtt + rtt) / 2; } } /* test if payload present */ if (!PPTP_GRE_IS_S(ntoh8(header->flags))) return 0; /* ack, but no payload */ headersize = sizeof(*header); payload_len = ntoh16(header->payload_len); seq = ntoh32(header->seq); /* no ack present? */ if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize -= sizeof(header->ack); /* check for incomplete packet (length smaller than expected) */ if (status - headersize < payload_len) { warn("discarding truncated packet (expected %d, got %d bytes)", payload_len, status - headersize); stats.rx_truncated++; return 0; } /* check for expected sequence number */ if ( first || (seq == seq_recv + 1)) { /* wrap-around safe */ if ( log_level >= 2 ) log("accepting packet %d", seq); stats.rx_accepted++; first = 0; seq_recv = seq; return callback(cl, buffer + ip_len + headersize, payload_len); /* out of order, check if the number is too low and discard the packet. * (handle sequence number wrap-around, and try to do it right) */ } else if ( seq < seq_recv + 1 || WRAPPED(seq_recv, seq) ) { if ( log_level >= 1 ) log("discarding duplicate or old packet %d (expecting %d)", seq, seq_recv + 1); stats.rx_underwin++; /* sequence number too high, is it reasonably close? */ } else if ( seq < seq_recv + MISSING_WINDOW || WRAPPED(seq, seq_recv + MISSING_WINDOW) ) { stats.rx_buffered++; if ( log_level >= 1 ) log("%s packet %d (expecting %d, lost or reordered)", disable_buffer ? "accepting" : "buffering", seq, seq_recv+1); if ( disable_buffer ) { seq_recv = seq; stats.rx_lost += seq - seq_recv - 1; return callback(cl, buffer + ip_len + headersize, payload_len); } else { pqueue_add(seq, buffer + ip_len + headersize, payload_len); } /* no, packet must be discarded */ } else { if ( log_level >= 1 ) warn("discarding bogus packet %d (expecting %d)", seq, seq_recv + 1); stats.rx_overwin++; } return 0; }
/*** encaps_gre ***************************************************************/ int encaps_gre (int fd, void *pack, unsigned int len) { union { struct pptp_gre_header header; unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)]; } u; static u_int32_t seq = 1; /* first sequence number sent must be 1 */ unsigned int header_len; int rc; /* package this up in a GRE shell. */ u.header.flags = hton8 (PPTP_GRE_FLAG_K); u.header.ver = hton8 (PPTP_GRE_VER); u.header.protocol = hton16(PPTP_GRE_PROTO); u.header.payload_len = hton16(len); u.header.call_id = hton16(pptp_gre_peer_call_id); /* special case ACK with no payload */ if (pack == NULL) { if (ack_sent != seq_recv) { u.header.ver |= hton8(PPTP_GRE_FLAG_A); u.header.payload_len = hton16(0); /* ack is in odd place because S == 0 */ u.header.seq = hton32(seq_recv); ack_sent = seq_recv; rc = (*my->write)(fd, &u.header, sizeof(u.header) - sizeof(u.header.seq)); if (rc < 0) { if (errno == ENOBUFS) rc = 0; /* Simply ignore it */ stats.tx_failed++; } else if (rc < sizeof(u.header) - sizeof(u.header.seq)) { stats.tx_short++; } else { stats.tx_acks++; } return rc; } else return 0; /* we don't need to send ACK */ } /* explicit brace to avoid ambiguous `else' warning */ /* send packet with payload */ u.header.flags |= hton8(PPTP_GRE_FLAG_S); u.header.seq = hton32(seq); if (ack_sent != seq_recv) { /* send ack with this message */ u.header.ver |= hton8(PPTP_GRE_FLAG_A); u.header.ack = hton32(seq_recv); ack_sent = seq_recv; header_len = sizeof(u.header); } else { /* don't send ack */ header_len = sizeof(u.header) - sizeof(u.header.ack); } if (header_len + len >= sizeof(u.buffer)) { stats.tx_oversize++; return 0; /* drop this, it's too big */ } /* copy payload into buffer */ memcpy(u.buffer + header_len, pack, len); /* record and increment sequence numbers */ seq_sent = seq; seq++; /* write this baby out to the net */ /* print_packet(2, u.buffer, header_len + len); */ rc = (*my->write)(fd, u.buffer, header_len + len); if (rc < 0) { if (errno == ENOBUFS) rc = 0; /* Simply ignore it */ stats.tx_failed++; } else if (rc < header_len + len) { stats.tx_short++; } else { stats.tx_sent++; stats.pt.seq = seq_sent; stats.pt.time = time_now_usecs(); } return rc; }
/*** encaps_gre ***************************************************************/ int encaps_gre (int fd, void *pack, unsigned int len) { union { struct pptp_gre_header header; unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)]; } u; //static u_int32_t seq = 1; /* first sequence number sent must be 1 */ unsigned int header_len; int rc; /* added start, Winster Chan, 06/26/2006 */ static u_int32_t kerseq; /* Sequence number got from kernel by ioctl() */ /* added end, Winster Chan, 06/26/2006 */ /* package this up in a GRE shell. */ u.header.flags = hton8 (PPTP_GRE_FLAG_K); u.header.ver = hton8 (PPTP_GRE_VER); u.header.protocol = hton16(PPTP_GRE_PROTO); u.header.payload_len = hton16(len); u.header.call_id = hton16(pptp_gre_peer_call_id); /* special case ACK with no payload */ if (pack == NULL) { if (ack_sent != seq_recv) { u.header.ver |= hton8(PPTP_GRE_FLAG_A); u.header.payload_len = hton16(0); /* ack is in odd place because S == 0 */ u.header.seq = hton32(seq_recv); ack_sent = seq_recv; rc = write(fd, &u.header, sizeof(u.header) - sizeof(u.header.seq)); if (rc < 0) { stats.tx_failed++; } else if (rc < sizeof(u.header) - sizeof(u.header.seq)) { stats.tx_short++; } else { stats.tx_acks++; } return rc; } else return 0; /* we don't need to send ACK */ } /* explicit brace to avoid ambiguous `else' warning */ /* send packet with payload */ u.header.flags |= hton8(PPTP_GRE_FLAG_S); /* modified start, Winster Chan, 06/26/2006 */ //u.header.seq = hton32(seq); if (pox_fd >= 0) { if (ioctl(pox_fd, PPTPIOCGGRESEQ, &kerseq) == -1) { warn("Couldn't get GRE sequence number"); } } else warn("Socket not opened"); u.header.seq = hton32(kerseq); /* modified end, Winster Chan, 06/26/2006 */ if (ack_sent != seq_recv) { /* send ack with this message */ u.header.ver |= hton8(PPTP_GRE_FLAG_A); u.header.ack = hton32(seq_recv); ack_sent = seq_recv; header_len = sizeof(u.header); } else { /* don't send ack */ header_len = sizeof(u.header) - sizeof(u.header.ack); } if (header_len + len >= sizeof(u.buffer)) { stats.tx_oversize++; return 0; /* drop this, it's too big */ } /* copy payload into buffer */ memcpy(u.buffer + header_len, pack, len); /* record and increment sequence numbers */ /* modified start, Winster Chan, 06/26/2006 */ //seq_sent = seq; seq++; /* * Note: the kerseq(kernel sequence number) is maintained by * pptp kernel driver */ seq_sent = kerseq; /* modified end, Winster Chan, 06/26/2006 */ /* write this baby out to the net */ /* print_packet(2, u.buffer, header_len + len); */ rc = write(fd, u.buffer, header_len + len); if (rc < 0) { stats.tx_failed++; } else if (rc < header_len + len) { stats.tx_short++; } else { stats.tx_sent++; stats.pt.seq = seq_sent; stats.pt.time = time_now_usecs(); } return rc; }