int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v) { if ((*length + 2) >= size) return 1; ((union gtpie_member*) (p + *length))->tv1.t = hton8(t); ((union gtpie_member*) (p + *length))->tv1.v = hton8(v); *length += 2; return 0; }
static void send_request (BArpProbe *o) { if (o->send_sending) { BLog(BLOG_ERROR, "cannot send packet while another packet is being sent!"); return; } // build packet struct arp_packet *arp = &o->send_packet; arp->hardware_type = hton16(ARP_HARDWARE_TYPE_ETHERNET); arp->protocol_type = hton16(ETHERTYPE_IPV4); arp->hardware_size = hton8(6); arp->protocol_size = hton8(4); arp->opcode = hton16(ARP_OPCODE_REQUEST); memcpy(arp->sender_mac, o->if_mac, 6); arp->sender_ip = hton32(0); memset(arp->target_mac, 0, sizeof(arp->target_mac)); arp->target_ip = o->addr; // send packet PacketPassInterface_Sender_Send(o->send_if, (uint8_t *)&o->send_packet, sizeof(o->send_packet)); // set sending o->send_sending = 1; }
int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v) { if ((*length + 9) >= size) return 1; ((union gtpie_member*) (p + *length))->tv8.t = hton8(t); ((union gtpie_member*) (p + *length))->tv8.v = hton64(v); *length += 9; return 0; }
int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v) { if ((*length + 5) >= size) return 1; ((union gtpie_member*) (p + *length))->tv4.t = hton8(t); ((union gtpie_member*) (p + *length))->tv4.v = hton32(v); *length += 5; return 0; }
int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v) { if ((*length + 3) >= size) return 1; ((union gtpie_member*) (p + *length))->tv2.t = hton8(t); ((union gtpie_member*) (p + *length))->tv2.v = hton16(v); *length += 3; return 0; }
int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, uint8_t *v) { if ((*length + 1 + l) >= size) return 1; ((union gtpie_member*) (p + *length))->tv0.t = hton8(t); memcpy((void*) (p + *length +1), v, l); *length += 1 + l; return 0; }
/*** this is a soft close *****************************************************/ void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason) { struct pptp_stop_ctrl_conn rqst = { PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), hton8(close_reason), 0, 0 }; int i; assert(conn && conn->call); /* avoid repeated close attempts */ if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY) return; /* close open calls, if any */ for (i = 0; i < vector_size(conn->call); i++) pptp_call_close(conn, vector_get_Nth(conn->call, i)); /* now close connection */ log("Closing PPTP connection"); pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst)); pptp_reset_timer(); /* wait 60 seconds for reply */ conn->conn_state = CONN_WAIT_STOP_REPLY; return; }
int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, void *v) { if ((*length + 3 + l) >= size) return 1; ((union gtpie_member*) (p + *length))->tlv.t = hton8(t); ((union gtpie_member*) (p + *length))->tlv.l = hton16(l); memcpy((void*) (p + *length +3), v, l); *length += 3 + l; return 0; }
void auth_finished (BSocksClient *o) { // allocate request buffer bsize_t size = bsize_fromsize(sizeof(struct socks_request_header)); switch (o->dest_addr.type) { case BADDR_TYPE_IPV4: size = bsize_add(size, bsize_fromsize(sizeof(struct socks_addr_ipv4))); break; case BADDR_TYPE_IPV6: size = bsize_add(size, bsize_fromsize(sizeof(struct socks_addr_ipv6))); break; } if (!reserve_buffer(o, size)) { report_error(o, BSOCKSCLIENT_EVENT_ERROR); return; } // write request struct socks_request_header header; header.ver = hton8(SOCKS_VERSION); header.cmd = hton8(SOCKS_CMD_CONNECT); header.rsv = hton8(0); switch (o->dest_addr.type) { case BADDR_TYPE_IPV4: { header.atyp = hton8(SOCKS_ATYP_IPV4); struct socks_addr_ipv4 addr; addr.addr = o->dest_addr.ipv4.ip; addr.port = o->dest_addr.ipv4.port; memcpy(o->buffer + sizeof(header), &addr, sizeof(addr)); } break; case BADDR_TYPE_IPV6: { header.atyp = hton8(SOCKS_ATYP_IPV6); struct socks_addr_ipv6 addr; memcpy(addr.addr, o->dest_addr.ipv6.ip, sizeof(o->dest_addr.ipv6.ip)); addr.port = o->dest_addr.ipv6.port; memcpy(o->buffer + sizeof(header), &addr, sizeof(addr)); } break; default: ASSERT(0); } memcpy(o->buffer, &header, sizeof(header)); // send request PacketPassInterface_Sender_Send(o->control.send_if, (uint8_t *)o->buffer, size.value); // set state o->state = STATE_SENDING_REQUEST; }
void connector_handler (BSocksClient* o, int is_error) { DebugObject_Access(&o->d_obj); ASSERT(o->state == STATE_CONNECTING) // check connection result if (is_error) { // PSIPHON // BLog(BLOG_ERROR, "connection failed"); BLog(BLOG_WARNING, "connection failed"); goto fail0; } // init connection if (!BConnection_Init(&o->con, BConnection_source_connector(&o->connector), o->reactor, o, (BConnection_handler)connection_handler)) { BLog(BLOG_ERROR, "BConnection_Init failed"); goto fail0; } BLog(BLOG_DEBUG, "connected"); // init control I/O init_control_io(o); // check number of methods if (o->num_auth_info == 0 || o->num_auth_info > 255) { BLog(BLOG_ERROR, "invalid number of authentication methods"); goto fail1; } // allocate buffer for sending hello bsize_t size = bsize_add( bsize_fromsize(sizeof(struct socks_client_hello_header)), bsize_mul( bsize_fromsize(o->num_auth_info), bsize_fromsize(sizeof(struct socks_client_hello_method)) ) ); if (!reserve_buffer(o, size)) { goto fail1; } // write hello header struct socks_client_hello_header header; header.ver = hton8(SOCKS_VERSION); header.nmethods = hton8(o->num_auth_info); memcpy(o->buffer, &header, sizeof(header)); // write hello methods for (size_t i = 0; i < o->num_auth_info; i++) { struct socks_client_hello_method method; method.method = hton8(o->auth_info[i].auth_type); memcpy(o->buffer + sizeof(header) + i * sizeof(method), &method, sizeof(method)); } // send PacketPassInterface_Sender_Send(o->control.send_if, (uint8_t *)o->buffer, size.value); // set state o->state = STATE_SENDING_HELLO; return; fail1: free_control_io(o); BConnection_Free(&o->con); fail0: report_error(o, BSOCKSCLIENT_EVENT_ERROR); return; }
/*** 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; }
int gtpie_encaps2(union gtpie_member ie[], unsigned int size, void *pack, unsigned *len) { unsigned int i, j; unsigned char *p; unsigned char *end; union gtpie_member *m; int iesize; p = pack; memset(pack, 0, GTPIE_MAX); end = p + GTPIE_MAX; for (j=0; j<GTPIE_SIZE; j++) for (i=0; i<size; i++) if (ie[i].t == j) { if (GTPIE_DEBUG) printf("gtpie_encaps. Number %d, Type %d\n", i, ie[i].t); m=(union gtpie_member *)p; switch (ie[i].t) { case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */ case GTPIE_REORDER: case GTPIE_MAP_CAUSE: case GTPIE_MS_VALIDATED: case GTPIE_RECOVERY: case GTPIE_SELECTION_MODE: case GTPIE_TEARDOWN: case GTPIE_NSAPI: case GTPIE_RANAP_CAUSE: case GTPIE_RP_SMS: case GTPIE_RP: case GTPIE_MS_NOT_REACH: iesize = 2; break; case GTPIE_PFI: /* TV GTPIE types with value length 2 */ case GTPIE_CHARGING_C: case GTPIE_TRACE_REF: case GTPIE_TRACE_TYPE: iesize = 3; break; case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */ case GTPIE_P_TMSI_S: iesize = 4; break; case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ case GTPIE_P_TMSI: case GTPIE_TEI_DI: case GTPIE_TEI_C: iesize = 5; break; case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */ iesize = 6; break; case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */ iesize = 8; break; case GTPIE_IMSI: /* TV GTPIE types with value length 8 */ case GTPIE_RAI: iesize = 9; break; case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */ iesize = 29; break; case GTPIE_EXT_HEADER_T: /* GTP extension header */ iesize = 2 + hton8(ie[i].ext.l); break; case GTPIE_CHARGING_ID: /* TLV GTPIE types with length length 2 */ case GTPIE_EUA: case GTPIE_MM_CONTEXT: case GTPIE_PDP_CONTEXT: case GTPIE_APN: case GTPIE_PCO: case GTPIE_GSN_ADDR: case GTPIE_MSISDN: case GTPIE_QOS_PROFILE: case GTPIE_AUTH_QUINTUP: case GTPIE_TFT: case GTPIE_TARGET_INF: case GTPIE_UTRAN_TRANS: case GTPIE_RAB_SETUP: case GTPIE_TRIGGER_ID: case GTPIE_OMC_ID: case GTPIE_CHARGING_ADDR: case GTPIE_PRIVATE: iesize = 3 + hton16(ie[i].tlv.l); break; default: return 2; /* We received something unknown */ } if (p+iesize < end) { memcpy(p, &ie[i], iesize); p += iesize; *len += iesize; } else return 2; /* Out of space */ } return 0; }
/*** pptp_dispatch_ctrl_packet ************************************************/ int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size) { struct pptp_header *header = (struct pptp_header *)buffer; u_int8_t close_reason = PPTP_STOP_NONE; assert(conn && conn->call); assert(buffer); assert(ntoh32(header->magic) == PPTP_MAGIC); assert(ntoh16(header->length) == size); assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL); if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) { log("Invalid packet received [type: %d; length: %d].", (int) ntoh16(header->ctrl_type), (int) size); return 0; } switch (ntoh16(header->ctrl_type)) { /* ----------- STANDARD Start-Session MESSAGES ------------ */ case PPTP_START_CTRL_CONN_RQST: { struct pptp_start_ctrl_conn *packet = (struct pptp_start_ctrl_conn *) buffer; struct pptp_start_ctrl_conn reply = { PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY), hton16(PPTP_VERSION), 0, 0, hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP), hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), PPTP_HOSTNAME, PPTP_VENDOR }; int idx, rc; log("Received Start Control Connection Request"); /* fix this packet, if necessary */ idx = get_quirk_index(); if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) { if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply))) warn("calling the start_ctrl_conn hook failed (%d)", rc); } if (conn->conn_state == CONN_IDLE) { if (ntoh16(packet->version) < PPTP_VERSION) { /* Can't support this (earlier) PPTP_VERSION */ reply.version = packet->version; /* protocol version not supported */ reply.result_code = hton8(5); pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); pptp_reset_timer(); /* give sender a chance for a retry */ } else { /* same or greater version */ if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { conn->conn_state = CONN_ESTABLISHED; log("server connection ESTABLISHED."); pptp_reset_timer(); } } } break; } case PPTP_START_CTRL_CONN_RPLY: { struct pptp_start_ctrl_conn *packet = (struct pptp_start_ctrl_conn *) buffer; log("Received Start Control Connection Reply"); if (conn->conn_state == CONN_WAIT_CTL_REPLY) { /* XXX handle collision XXX [see rfc] */ if (ntoh16(packet->version) != PPTP_VERSION) { if (conn->callback != NULL) conn->callback(conn, CONN_OPEN_FAIL); close_reason = PPTP_STOP_PROTOCOL; goto pptp_conn_close; } if (ntoh8(packet->result_code) != 1 && /* J'ai change le if () afin que la connection ne se ferme * pas pour un "rien" :p [email protected] - * * Don't close the connection if the result code is zero * (feature found in certain ADSL modems) */ ntoh8(packet->result_code) != 0) { log("Negative reply received to our Start Control " "Connection Request"); ctrlp_error(packet->result_code, packet->error_code, -1, pptp_start_ctrl_conn_rply, MAX_START_CTRL_CONN_REPLY); if (conn->callback != NULL) conn->callback(conn, CONN_OPEN_FAIL); close_reason = PPTP_STOP_PROTOCOL; goto pptp_conn_close; } conn->conn_state = CONN_ESTABLISHED; /* log session properties */ conn->version = ntoh16(packet->version); conn->firmware_rev = ntoh16(packet->firmware_rev); memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname)); memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor)); pptp_reset_timer(); /* 60 seconds until keep-alive */ log("Client connection established."); if (conn->callback != NULL) conn->callback(conn, CONN_OPEN_DONE); } /* else goto pptp_conn_close; */ break; } /* ----------- STANDARD Stop-Session MESSAGES ------------ */ case PPTP_STOP_CTRL_CONN_RQST: { /* conn_state should be CONN_ESTABLISHED, but it could be * something else */ struct pptp_stop_ctrl_conn reply = { PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0 }; log("Received Stop Control Connection Request."); if (conn->conn_state == CONN_IDLE) break; if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) { if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_RQST); conn->conn_state = CONN_IDLE; return -1; } break; } case PPTP_STOP_CTRL_CONN_RPLY: { log("Received Stop Control Connection Reply."); /* conn_state should be CONN_WAIT_STOP_REPLY, but it * could be something else */ if (conn->conn_state == CONN_IDLE) break; conn->conn_state = CONN_IDLE; return -1; } /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */ case PPTP_ECHO_RPLY: { struct pptp_echo_rply *packet = (struct pptp_echo_rply *) buffer; logecho( PPTP_ECHO_RPLY); if ((conn->ka_state == KA_OUTSTANDING) && (ntoh32(packet->identifier) == conn->ka_id)) { conn->ka_id++; conn->ka_state = KA_NONE; pptp_reset_timer(); } break; } case PPTP_ECHO_RQST: { struct pptp_echo_rqst *packet = (struct pptp_echo_rqst *) buffer; struct pptp_echo_rply reply = { PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), packet->identifier, /* skip hton32(ntoh32(id)) */ hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0 }; logecho( PPTP_ECHO_RQST); pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); pptp_reset_timer(); break; } /* ----------- OUTGOING CALL MESSAGES ------------ */ case PPTP_OUT_CALL_RQST: { struct pptp_out_call_rqst *packet = (struct pptp_out_call_rqst *)buffer; struct pptp_out_call_rply reply = { PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY), 0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0, hton32(PPTP_CONNECT_SPEED), hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0 }; log("Received Outgoing Call Request."); /* XXX PAC: eventually this should make an outgoing call. XXX */ reply.result_code = hton8(7); /* outgoing calls verboten */ pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); break; } case PPTP_OUT_CALL_RPLY: { struct pptp_out_call_rply *packet = (struct pptp_out_call_rply *)buffer; PPTP_CALL * call; u_int16_t callid = ntoh16(packet->call_id_peer); log("Received Outgoing Call Reply."); if (!vector_search(conn->call, (int) callid, &call)) { log("PPTP_OUT_CALL_RPLY received for non-existant call: " "peer call ID (us) %d call ID (them) %d.", callid, ntoh16(packet->call_id)); break; } if (call->call_type != PPTP_CALL_PNS) { log("Ack! How did this call_type get here?"); /* XXX? */ break; } if (call->state.pns != PNS_WAIT_REPLY) { warn("Unexpected(?) Outgoing Call Reply will be ignored."); break; } /* check for errors */ if (packet->result_code != 1) { /* An error. Log it verbosely. */ log("Our outgoing call request [callid %d] has not been " "accepted.", (int) callid); ctrlp_error(packet->result_code, packet->error_code, packet->cause_code, pptp_out_call_reply_result, MAX_OUT_CALL_REPLY_RESULT); call->state.pns = PNS_IDLE; if (call->callback != NULL) call->callback(conn, call, CALL_OPEN_FAIL); pptp_call_destroy(conn, call); } else { /* connection established */ call->state.pns = PNS_ESTABLISHED; call->peer_call_id = ntoh16(packet->call_id); call->speed = ntoh32(packet->speed); pptp_reset_timer(); /* call pptp_set_link. unless the user specified a quirk and this quirk has a set_link hook, this is a noop */ pptp_set_link(conn, call->peer_call_id); if (call->callback != NULL) call->callback(conn, call, CALL_OPEN_DONE); log("Outgoing call established (call ID %u, peer's " "call ID %u).\n", call->call_id, call->peer_call_id); } break; } /* ----------- INCOMING CALL MESSAGES ------------ */ /* XXX write me XXX */ /* ----------- CALL CONTROL MESSAGES ------------ */ case PPTP_CALL_CLEAR_RQST: { struct pptp_call_clear_rqst *packet = (struct pptp_call_clear_rqst *)buffer; struct pptp_call_clear_ntfy reply = { PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0} }; log("Received Call Clear Request."); if (vector_contains(conn->call, ntoh16(packet->call_id))) { PPTP_CALL * call; vector_search(conn->call, ntoh16(packet->call_id), &call); if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_RQST); pptp_send_ctrl_packet(conn, &reply, sizeof(reply)); pptp_call_destroy(conn, call); log("Call closed (RQST) (call id %d)", (int) call->call_id); } break; } case PPTP_CALL_CLEAR_NTFY: { struct pptp_call_clear_ntfy *packet = (struct pptp_call_clear_ntfy *)buffer; log("Call disconnect notification received (call id %d)", ntoh16(packet->call_id)); if (vector_contains(conn->call, ntoh16(packet->call_id))) { PPTP_CALL * call; ctrlp_error(packet->result_code, packet->error_code, packet->cause_code, pptp_call_disc_ntfy, MAX_CALL_DISC_NTFY); vector_search(conn->call, ntoh16(packet->call_id), &call); pptp_call_destroy(conn, call); } /* XXX we could log call stats here XXX */ /* XXX not all servers send this XXX */ break; } case PPTP_SET_LINK_INFO: { /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */ /* this is really dealt with in the HDLC deencapsulation, anyway. */ struct pptp_set_link_info *packet = (struct pptp_set_link_info *)buffer; /* log it. */ log("PPTP_SET_LINK_INFO received from peer_callid %u", (unsigned int) ntoh16(packet->call_id_peer)); log(" send_accm is %08lX, recv_accm is %08lX", (unsigned long) ntoh32(packet->send_accm), (unsigned long) ntoh32(packet->recv_accm)); if (!(ntoh32(packet->send_accm) == 0 && ntoh32(packet->recv_accm) == 0)) warn("Non-zero Async Control Character Maps are not supported!"); break; } default: log("Unrecognized Packet %d received.", (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type)); /* goto pptp_conn_close; */ break; } return 0; pptp_conn_close: warn("pptp_conn_close(%d)", (int) close_reason); pptp_conn_close(conn, close_reason); 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; /* 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; }