+static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
+{
+ vpn_packet_t pkt1, pkt2;
+ vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
+ int nextpkt = 0;
+ vpn_packet_t *outpkt = pkt[0];
+ char *hmac = NULL;
+ int result;
+ int i;
+ static char iv[32] = {0};
+
+ cp();
+
+ /* Check packet length */
+
+ if(inpkt->len < sizeof(inpkt->seqno) + myself->maclength) {
+ ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
+ n->name, n->hostname);
+ return;
+ }
+
+ /* Check the message authentication code */
+
+ if(myself->digest && myself->maclength) {
+ inpkt->len -= myself->maclength;
+ gcry_md_reset(myself->digest_ctx);
+ gcry_md_write(myself->digest_ctx, (char *)&inpkt->seqno, inpkt->len);
+ hmac = gcry_md_read(myself->digest_ctx, 0);
+
+ if(!hmac || memcmp(hmac, (char *)&inpkt->seqno + inpkt->len, myself->maclength)) {
+ ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
+ n->name, n->hostname);
+ return;
+ }
+ }
+
+ /* Decrypt the packet */
+
+ if(myself->cipher) {
+ gcry_cipher_reset(myself->cipher_ctx);
+ //memcpy(iv, &inpkt->seqno, sizeof inpkt->seqno);
+ //gcry_cipher_setiv(myself->cipher_ctx, iv, myself->cipherblklen);
+ result = gcry_cipher_decrypt(myself->cipher_ctx, (char *)&inpkt->seqno, inpkt->len, NULL, 0);
+
+ if(result) {
+ ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s): %s"),
+ n->name, n->hostname, gpg_strerror(result));
+ logger(LOG_DEBUG, "%p %p %d", myself->cipher_ctx, (char *)&inpkt->seqno, inpkt->len);
+ return;
+ }
+ }
+
+ /* Remove padding */
+
+ if(myself->cipherblklen > 1) {
+ int padlen;
+
+ padlen = ((uint8_t *)&inpkt->seqno)[inpkt->len - 1];
+
+ if(padlen && padlen <= myself->cipherblklen)
+ inpkt->len -= padlen;
+ }
+
+ /* Check the sequence number */
+
+ inpkt->len -= sizeof(inpkt->seqno);
+ inpkt->seqno = ntohl(inpkt->seqno);
+
+ if(inpkt->seqno != n->received_seqno + 1) {
+ if(inpkt->seqno >= n->received_seqno + sizeof(n->late) * 8) {
+ logger(LOG_WARNING, _("Lost %u packets from %s (%s)"),
+ inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
+
+ memset(n->late, 0, sizeof(n->late));
+ } else if (inpkt->seqno <= n->received_seqno) {
+ if(inpkt->seqno <= n->received_seqno - sizeof(n->late) * 8 || !(n->late[(inpkt->seqno / 8) % sizeof(n->late)] & (1 << inpkt->seqno % 8))) {
+ logger(LOG_WARNING, _("Got late or replayed packet from %s (%s), seqno %u, last received %u"),
+ n->name, n->hostname, inpkt->seqno, n->received_seqno);
+ } else
+ for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
+ n->late[(inpkt->seqno / 8) % sizeof(n->late)] |= 1 << i % 8;
+ }
+ }
+
+ if(inpkt->seqno > n->received_seqno) {
+ n->received_seqno = inpkt->seqno;
+ n->late[(n->received_seqno / 8) % sizeof(n->late)] &= ~(1 << n->received_seqno % 8);
+ }
+
+ if(n->received_seqno > MAX_SEQNO)
+ keyexpires = 0;
+
+ /* Decompress the packet */
+
+ if(myself->compression) {
+ outpkt = pkt[nextpkt++];
+
+ if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, myself->compression)) < 0) {
+ ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while uncompressing packet from %s (%s)"),
+ n->name, n->hostname);
+ return;
+ }
+
+ inpkt = outpkt;
+ }
+
+ if(n->connection)
+ n->connection->last_ping_time = now;
+
+ if(!inpkt->data[12] && !inpkt->data[13])
+ mtu_probe_h(n, inpkt);
+ else
+ receive_packet(n, inpkt);