pkt.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /*
  2. * pkt.c
  3. * ptunnel is licensed under the BSD license:
  4. *
  5. * Copyright (c) 2004-2011, Daniel Stoedle <daniels@cs.uit.no>,
  6. * Yellow Lemon Software. All rights reserved.
  7. *
  8. * Copyright (c) 2017-2019, Toni Uhlig <matzeton@googlemail.com>
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. *
  16. * - Redistributions in binary form must reproduce the above copyright notice,
  17. * this list of conditions and the following disclaimer in the documentation
  18. * and/or other materials provided with the distribution.
  19. *
  20. * - Neither the name of the Yellow Lemon Software nor the names of its
  21. * contributors may be used to endorse or promote products derived from this
  22. * software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  28. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  31. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  32. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. * POSSIBILITY OF SUCH DAMAGE.
  35. *
  36. * Contacting the author:
  37. * You can get in touch with me, Daniel Stødle (that's the Norwegian letter oe,
  38. * in case your text editor didn't realize), here: <daniels@cs.uit.no>
  39. *
  40. * The official ptunnel website is here:
  41. * <http://www.cs.uit.no/~daniels/PingTunnel/>
  42. *
  43. * Note that the source code is best viewed with tabs set to 4 spaces.
  44. */
  45. #ifndef WIN32
  46. #include <netinet/in.h>
  47. #include <arpa/inet.h>
  48. #include <pthread.h>
  49. #endif
  50. #include <sys/time.h>
  51. #include "ptunnel.h"
  52. #include "pkt.h"
  53. #include "pdesc.h"
  54. #include "options.h"
  55. #include "utils.h"
  56. static proxy_desc_t *
  57. handle_incoming_tunnel_request(unsigned bytes, struct sockaddr_in *addr, int icmp_sock,
  58. icmp_echo_packet_t * const pkt, ping_tunnel_pkt_t * const pt_pkt)
  59. {
  60. struct timeval tt;
  61. struct in_addr in_addr;
  62. uint32_t init_state;
  63. proxy_desc_t *cur;
  64. pt_log(kLog_info, "Incoming tunnel request from %s.\n",
  65. inet_ntoa(*(struct in_addr *)&addr->sin_addr));
  66. gettimeofday(&tt, 0);
  67. if (tt.tv_sec < seq_expiry_tbl[pt_pkt->id_no]) {
  68. pt_log(kLog_verbose, "Dropping request: ID was recently in use.\n");
  69. return NULL;
  70. }
  71. in_addr.s_addr = pt_pkt->dst_ip;
  72. pt_log(kLog_info, "Starting new session to %s:%d with ID %d\n",
  73. inet_ntoa(in_addr), ntohl(pt_pkt->dst_port), pt_pkt->id_no);
  74. if ((opts.restrict_dst_ip && opts.given_dst_ip &&
  75. opts.given_dst_ip != pt_pkt->dst_ip) ||
  76. (opts.restrict_dst_port && (uint32_t)-1 != opts.given_dst_port &&
  77. opts.given_dst_port != ntohl(pt_pkt->dst_port)))
  78. {
  79. pt_log(kLog_info, "Destination administratively prohibited!\n");
  80. return NULL;
  81. }
  82. if (opts.password) {
  83. init_state = kProto_authenticate;
  84. } else {
  85. init_state = kProto_data;
  86. }
  87. cur = (proxy_desc_t *) create_and_insert_proxy_desc(pt_pkt->id_no, pkt->identifier, 0,
  88. addr, pt_pkt->dst_ip,
  89. ntohl(pt_pkt->dst_port),
  90. init_state, kProxy_flag);
  91. if (!cur) {
  92. /* if failed, abort. Logging is done in create_insert_proxy_desc */
  93. pt_log(kLog_error, "Failed to create proxy descriptor!\n");
  94. return NULL;
  95. }
  96. if (pt_pkt->data_len > 0) {
  97. handle_data(pkt, bytes, cur, 1);
  98. if (!opts.password) {
  99. handle_extended_options(cur);
  100. }
  101. }
  102. if (init_state == kProto_authenticate) {
  103. pt_log(kLog_debug, "Sending authentication challenge..\n");
  104. /* Send challenge */
  105. cur->challenge = generate_challenge();
  106. memcpy(cur->buf, cur->challenge, sizeof(challenge_t));
  107. queue_packet(icmp_sock, cur, cur->buf, sizeof(challenge_t), 0, 0,
  108. kProto_authenticate | cur->type_flag);
  109. }
  110. return cur;
  111. }
  112. static void handle_auth_request(unsigned bytes, int icmp_sock,
  113. icmp_echo_packet_t *const pkt,
  114. proxy_desc_t *const cur,
  115. challenge_t *const challenge)
  116. {
  117. if (!opts.password) {
  118. pt_log(kLog_error, "This proxy requires a password! "
  119. "Please supply one usin g the -x switch.\n");
  120. send_termination_msg(cur, icmp_sock);
  121. cur->should_remove = 1;
  122. return;
  123. }
  124. #ifdef ENABLE_SHA512
  125. if (opts.force_sha512) {
  126. pt_log(kLog_debug,
  127. "Got authentication challenge - sending SHA512 response\n");
  128. generate_response_sha512(&challenge->plain, &challenge->digest);
  129. } else
  130. #endif
  131. {
  132. pt_log(kLog_debug, "Got authentication challenge - sending MD5 response\n");
  133. generate_response_md5(&challenge->plain, &challenge->digest);
  134. }
  135. memcpy(cur->buf, challenge, sizeof(challenge_t));
  136. queue_packet(icmp_sock, cur, cur->buf, sizeof(challenge_t), 0, 0,
  137. kProto_authenticate | cur->type_flag);
  138. /* We have authenticated locally.
  139. * It's up to the proxy now if it accepts our response or not..
  140. */
  141. cur->authenticated = 1;
  142. handle_data(pkt, bytes, cur, 0);
  143. }
  144. static void handle_auth_response(unsigned bytes, int icmp_sock,
  145. icmp_echo_packet_t *const pkt,
  146. proxy_desc_t *const cur,
  147. challenge_t *const challenge)
  148. {
  149. pt_log(kLog_debug, "Received remote %s challenge response.\n",
  150. (challenge->digest.hash_type == HT_SHA512 ? "SHA512" : "MD5"));
  151. if ((!opts.force_sha512 && challenge->digest.hash_type == HT_MD5 &&
  152. validate_challenge_md5(cur->challenge, &challenge->digest)) ||
  153. #ifdef ENABLE_SHA512
  154. (challenge->digest.hash_type == HT_SHA512 &&
  155. validate_challenge_sha512(cur->challenge, &challenge->digest)) ||
  156. #endif
  157. cur->authenticated)
  158. {
  159. pt_log(kLog_verbose, "Remote end authenticated successfully.\n");
  160. handle_extended_options(cur);
  161. /* Authentication has succeeded, so now we can proceed
  162. * to handle incoming TCP data.
  163. */
  164. cur->authenticated = 1;
  165. cur->state = kProto_data;
  166. /* Insert the packet into the receive ring, to avoid
  167. * confusing the reliab ility mechanism.
  168. */
  169. handle_data(pkt, bytes, cur, 0);
  170. } else {
  171. pt_log(kLog_info, "Remote end failed authentication.\n");
  172. send_termination_msg(cur, icmp_sock);
  173. cur->should_remove = 1;
  174. }
  175. }
  176. static void header_byteorder_ntoh(icmp_echo_packet_t * const icmp_pkt,
  177. ping_tunnel_pkt_t * const pt_pkt)
  178. {
  179. pt_pkt->state = ntohl(pt_pkt->state);
  180. icmp_pkt->identifier = ntohs(icmp_pkt->identifier);
  181. icmp_pkt->seq = ntohs(icmp_pkt->seq);
  182. pt_pkt->id_no = ntohs(pt_pkt->id_no);
  183. pt_pkt->seq_no = ntohs(pt_pkt->seq_no);
  184. }
  185. static proxy_desc_t * get_proxy_descriptor(uint16_t id_no)
  186. {
  187. proxy_desc_t * cur;
  188. /* Find the relevant connection, if it exists */
  189. pthread_mutex_lock(&chain_lock);
  190. for (cur = chain; cur; cur = cur->next) {
  191. if (cur->id_no == id_no) {
  192. break;
  193. }
  194. }
  195. pthread_mutex_unlock(&chain_lock);
  196. return cur;
  197. }
  198. /* handle_proxy_packet:
  199. * Processes incoming ICMP packets for the proxy. The packet can come either from the
  200. * packet capture lib, or from the actual socket or both.
  201. * Input: A buffer pointing at the start of an IP header, the buffer length and the proxy
  202. * descriptor chain.
  203. */
  204. void handle_packet(char * buf, unsigned bytes, int is_pcap, struct sockaddr_in * addr, int icmp_sock)
  205. {
  206. ip_packet_t * ip_pkt;
  207. icmp_echo_packet_t * pkt;
  208. ping_tunnel_pkt_t * pt_pkt;
  209. proxy_desc_t * cur;
  210. uint32_t type_flag, pkt_flag, proxy_flag;
  211. challenge_t * challenge;
  212. proxy_flag = kProxy_flag;
  213. if (bytes < sizeof(icmp_echo_packet_t) + sizeof(ping_tunnel_pkt_t))
  214. pt_log(kLog_verbose,
  215. "Skipping this packet - too short. "
  216. "Expect: %lu+%lu = %lu ; Got: %u\n",
  217. sizeof(icmp_echo_packet_t),
  218. sizeof(ping_tunnel_pkt_t),
  219. sizeof(icmp_echo_packet_t) + sizeof(ping_tunnel_pkt_t),
  220. bytes);
  221. else {
  222. if (opts.udp || opts.unprivileged) {
  223. ip_pkt = 0;
  224. pkt = (icmp_echo_packet_t *)buf;
  225. pt_pkt = (ping_tunnel_pkt_t *)pkt->data;
  226. } else {
  227. ip_pkt = (ip_packet_t *)buf;
  228. pkt = (icmp_echo_packet_t *)ip_pkt->data;
  229. pt_pkt = (ping_tunnel_pkt_t *)pkt->data;
  230. }
  231. if (ntohl(pt_pkt->magic) == opts.magic) {
  232. header_byteorder_ntoh(pkt, pt_pkt);
  233. cur = get_proxy_descriptor(pt_pkt->id_no);
  234. /* Handle the packet if it comes from "the other end." This is a bit tricky
  235. * to get right, since we receive both our own and the other end's packets.
  236. * Basically, a proxy will accept any packet from a user, regardless if it
  237. * has a valid connection or not. A user will only accept the packet if there
  238. * exists a connection to handle it.
  239. */
  240. if (cur) {
  241. type_flag = cur->type_flag;
  242. if (type_flag == (uint32_t)kProxy_flag) {
  243. cur->icmp_id = pkt->identifier;
  244. cur->ping_seq = pkt->seq;
  245. }
  246. if (!is_pcap)
  247. cur->xfer.icmp_in++;
  248. } else {
  249. type_flag = kProxy_flag;
  250. }
  251. pkt_flag = pt_pkt->state & kFlag_mask;
  252. pt_pkt->state &= ~kFlag_mask;
  253. if (pt_pkt->state > (kNum_proto_types - 1)) {
  254. pt_log(kLog_error, "Dropping packet with invalid state.\n");
  255. return;
  256. }
  257. pt_log(kLog_sendrecv,
  258. "Recv: %4d [%4d] bytes "
  259. "[id = 0x%04X] [seq = %d] "
  260. "[seq_no = %d] [type = %s] "
  261. "[ack = %d] [icmp = %d] "
  262. "[user = %s] [pcap = %d]\n",
  263. bytes,
  264. ntohl(pt_pkt->data_len),
  265. pkt->identifier,
  266. ntohs(pkt->seq),
  267. pt_pkt->seq_no,
  268. state_name[pt_pkt->state & (~kFlag_mask)],
  269. ntohl(pt_pkt->ack),
  270. pkt->type,
  271. (pkt_flag == kUser_flag ? "yes" : "no"),
  272. is_pcap);
  273. /* This test essentially verifies that the packet comes from someone who isn't us. */
  274. if ((pkt_flag == kUser_flag && type_flag == proxy_flag) ||
  275. (pkt_flag == proxy_flag && type_flag == kUser_flag)) {
  276. pt_pkt->data_len = ntohl(pt_pkt->data_len);
  277. pt_pkt->ack = ntohl(pt_pkt->ack);
  278. if (pt_pkt->state == kProxy_start) {
  279. if (!cur && type_flag == proxy_flag) {
  280. cur = handle_incoming_tunnel_request(bytes, addr, icmp_sock, pkt, pt_pkt);
  281. if (!cur) {
  282. return;
  283. }
  284. } else if (type_flag == kUser_flag) {
  285. pt_log(kLog_error, "Dropping proxy session request - we are not a proxy!\n");
  286. return;
  287. } else {
  288. pt_log(kLog_error,
  289. "Dropping duplicate proxy session request "
  290. "with ID %d and seq %d.\n",
  291. pt_pkt->id_no,
  292. pt_pkt->seq_no);
  293. }
  294. } else if (cur && pt_pkt->state == kProto_authenticate) {
  295. /* Sanity check packet length, and make sure it matches what we expect */
  296. if (pt_pkt->data_len != sizeof(challenge_t)) {
  297. pt_log(kLog_error,
  298. "Received challenge packet, but data length "
  299. "is not as expected.\n");
  300. pt_log(kLog_debug, "Data length: %u Expected: %lu\n", pt_pkt->data_len, sizeof(challenge_t));
  301. cur->should_remove = 1;
  302. return;
  303. }
  304. /* Prevent packet data from being forwarded over TCP! */
  305. pt_pkt->data_len = 0;
  306. challenge = (challenge_t *)pt_pkt->data;
  307. /* If client: Compute response to challenge */
  308. if (type_flag == kUser_flag) {
  309. handle_auth_request(bytes, icmp_sock, pkt, cur, challenge);
  310. return;
  311. }
  312. /* If proxy: Handle client's response to challenge */
  313. else if (type_flag == proxy_flag) {
  314. handle_auth_response(bytes, icmp_sock, pkt, cur, challenge);
  315. return;
  316. }
  317. }
  318. /* Handle close-messages for connections we know about */
  319. if (cur && pt_pkt->state == kProto_close) {
  320. pt_log(kLog_info, "Received session close from remote peer.\n");
  321. cur->should_remove = 1;
  322. return;
  323. }
  324. /* The proxy will ignore any other packets from the client
  325. * until it has been authenticated. The packet resend mechanism
  326. * insures that this isn't problematic.
  327. */
  328. if (type_flag == proxy_flag && opts.password && cur && !cur->authenticated) {
  329. pt_log(kLog_debug,
  330. "Ignoring packet with seq-no %d "
  331. "- not authenticated yet.\n",
  332. pt_pkt->seq_no);
  333. return;
  334. }
  335. if (cur && cur->sock) {
  336. double now = time_as_double();
  337. if (pt_pkt->state != kProto_ack) {
  338. cur->last_data_activity = now;
  339. }
  340. if (pt_pkt->state == kProto_data || pt_pkt->state == kProxy_start || pt_pkt->state == kProto_ack) {
  341. if (pt_pkt->state == kProxy_start) {
  342. pt_pkt->data_len = 0;
  343. }
  344. handle_data(pkt, bytes, cur, 0);
  345. }
  346. handle_ack(pt_pkt->ack, cur);
  347. cur->last_activity = now;
  348. }
  349. }
  350. } else {
  351. pt_log(kLog_verbose, "Ignored incoming packet.\n");
  352. }
  353. }
  354. }
  355. /* handle_data:
  356. * Utility function for handling kProto_data packets, and place the data it contains
  357. * onto the passed-in receive ring.
  358. */
  359. void handle_data(icmp_echo_packet_t * pkt, int total_len, proxy_desc_t * cur, int handle_extended_options)
  360. {
  361. ping_tunnel_pkt_t * pt_pkt = (ping_tunnel_pkt_t *)pkt->data;
  362. int expected_len = sizeof(ip_packet_t) + sizeof(icmp_echo_packet_t) + sizeof(ping_tunnel_pkt_t); /* 20+8+28 */
  363. /* Place packet in the receive ring, in its proper place.
  364. * This works as follows:
  365. * -1. Packet == ack packet? Perform ack, and continue.
  366. * 0. seq_no < next_remote_seq, and absolute difference is bigger than w size => discard
  367. * 1. If seq_no == next_remote_seq, we have no problems; just put it in the ring.
  368. * 2. If seq_no > next_remote_seq + remaining window size, discard packet.
  369. * Send resend request for missing packets.
  370. * 3. Else, put packet in the proper place in the ring
  371. * (don't overwrite if one is already there), but don't increment next_remote_seq_no
  372. * 4. If packed was not discarded, process ack info in packet.
  373. */
  374. expected_len += pt_pkt->data_len;
  375. expected_len += expected_len % 2;
  376. if (opts.udp || opts.unprivileged)
  377. expected_len -= sizeof(ip_packet_t);
  378. if (total_len < expected_len) {
  379. pt_log(kLog_error,
  380. "Packet not completely received: %d Should be: %d.\n",
  381. total_len,
  382. expected_len);
  383. pt_log(kLog_debug, "Data length: %d Total length: %d\n", pt_pkt->data_len, total_len);
  384. /* just ignore that packet */
  385. return;
  386. }
  387. if (handle_extended_options) {
  388. uint16_t * extended_options = (uint16_t *)pt_pkt->data;
  389. if (pt_pkt->data_len >= 2) {
  390. cur->extended_options[0] = ntohs(extended_options[0]);
  391. }
  392. if (pt_pkt->data_len >= 4) {
  393. cur->extended_options[1] = ntohs(extended_options[1]);
  394. }
  395. if (pt_pkt->data_len >= 6) {
  396. cur->extended_options[2] = ntohs(extended_options[2]);
  397. }
  398. if (pt_pkt->data_len >= 8) {
  399. cur->extended_options[3] = ntohs(extended_options[3]);
  400. }
  401. return;
  402. }
  403. if (pt_pkt->seq_no == cur->next_remote_seq) {
  404. /* hmm, what happens if this test is true? */
  405. if (!cur->recv_ring[cur->recv_idx] && pt_pkt->state == kProto_data) {
  406. pt_log(kLog_debug, "Queing data packet: %d\n", pt_pkt->seq_no);
  407. cur->recv_ring[cur->recv_idx] = create_fwd_desc(pt_pkt->seq_no, pt_pkt->data_len, pt_pkt->data);
  408. cur->recv_wait_send++;
  409. cur->recv_idx++;
  410. } else {
  411. pt_log(kLog_debug, "Dup packet for %d ?\n", pt_pkt->seq_no);
  412. }
  413. cur->next_remote_seq++;
  414. if (cur->recv_idx >= cur->window_size)
  415. cur->recv_idx = 0;
  416. /* Check if we have already received some of the next packets */
  417. while (cur->recv_ring[cur->recv_idx]) {
  418. if (cur->recv_ring[cur->recv_idx]->seq_no == cur->next_remote_seq) {
  419. cur->next_remote_seq++;
  420. cur->recv_idx++;
  421. if (cur->recv_idx >= cur->window_size)
  422. cur->recv_idx = 0;
  423. } else {
  424. break;
  425. }
  426. }
  427. } else {
  428. int r, s, d, pos;
  429. pos = -1; /* If pos ends up staying -1, packet is discarded. */
  430. r = cur->next_remote_seq;
  431. s = pt_pkt->seq_no;
  432. d = s - r;
  433. if (d < 0) { /* This packet _may_ be old, or seq_no may have wrapped around */
  434. d = (s + 0xFFFF) - r;
  435. if (cur->window_size && d < cur->window_size) {
  436. /* Counter has wrapped, so we should add this packet to the recv ring */
  437. pos = (cur->recv_idx + d) % cur->window_size;
  438. }
  439. } else if (cur->window_size && d < cur->window_size) {
  440. pos = (cur->recv_idx + d) % cur->window_size;
  441. }
  442. if (pos != -1) {
  443. if (!cur->recv_ring[pos]) {
  444. pt_log(kLog_verbose,
  445. "Out of order. Expected: %d Got: %d Inserted: %d "
  446. "(cur = %d)\n",
  447. cur->next_remote_seq,
  448. pt_pkt->seq_no,
  449. pos,
  450. cur->recv_idx);
  451. cur->recv_ring[pos] = create_fwd_desc(pt_pkt->seq_no, pt_pkt->data_len, pt_pkt->data);
  452. cur->recv_wait_send++;
  453. }
  454. } else {
  455. pt_log(kLog_info, "Packet discarded - outside receive window.\n");
  456. }
  457. }
  458. }
  459. void handle_extended_options(proxy_desc_t * cur)
  460. {
  461. if (cur->extended_options[0] > 0) {
  462. if (cur->extended_options[0] > cur->window_size) {
  463. size_t extend = cur->extended_options[0] - cur->window_size;
  464. cur->send_ring = (icmp_desc_t *)realloc(cur->send_ring, cur->extended_options[0] * sizeof(icmp_desc_t));
  465. cur->recv_ring =
  466. (forward_desc_t **)realloc(cur->recv_ring, cur->extended_options[0] * sizeof(forward_desc_t *));
  467. memset(cur->send_ring + cur->window_size, 0, extend * sizeof(icmp_desc_t));
  468. memset(cur->recv_ring + cur->window_size, 0, extend * sizeof(forward_desc_t *));
  469. }
  470. cur->window_size = cur->extended_options[0];
  471. pt_log(kLog_verbose, "Received extended option for window size %d \n", cur->window_size);
  472. }
  473. if (cur->extended_options[1] > 0) {
  474. cur->ack_interval = cur->extended_options[1] / 1000.0;
  475. pt_log(kLog_verbose, "Received extended option for ack interval %f \n", cur->ack_interval);
  476. }
  477. if (cur->extended_options[2] > 0) {
  478. cur->resend_interval = cur->extended_options[2] / 1000.0;
  479. pt_log(kLog_verbose, "Received extended option for resend interval %f \n", cur->resend_interval);
  480. }
  481. if (cur->extended_options[3] > 0) {
  482. cur->payload_size = cur->extended_options[3];
  483. pt_log(kLog_verbose, "Received extended option for payload size %d \n", cur->payload_size);
  484. }
  485. }
  486. void handle_ack(uint32_t seq_no, proxy_desc_t * cur)
  487. {
  488. if (cur->send_wait_ack > 0) {
  489. int i, can_ack = 0, count = 0;
  490. i = cur->send_idx - 1;
  491. if (i < 0)
  492. i = cur->window_size - 1;
  493. pt_log(kLog_debug, "Received ack-series starting at seq %d\n", seq_no);
  494. while (count < cur->window_size) {
  495. if (!cur->send_ring[i].pkt)
  496. break;
  497. if (cur->send_ring[i].seq_no == seq_no)
  498. can_ack = 1;
  499. else if (!can_ack)
  500. cur->send_first_ack = i;
  501. if (can_ack) {
  502. free(cur->send_ring[i].pkt);
  503. cur->send_ring[i].pkt = 0;
  504. cur->send_ring[i].pkt_len = 0;
  505. cur->send_wait_ack--;
  506. }
  507. i--;
  508. if (i < 0)
  509. i = cur->window_size - 1;
  510. count++;
  511. }
  512. } else {
  513. pt_log(kLog_verbose,
  514. "Dropping superfluous acknowledgement for seq %d "
  515. "(no outstanding packets needing ack.)\n",
  516. seq_no);
  517. }
  518. }