1*4882a593SmuzhiyunFrom b6c4a1b204740fe52b32e7f530831a59f4038e20 Mon Sep 17 00:00:00 2001 2*4882a593SmuzhiyunFrom: Alexey Makhalov <amakhalov@vmware.com> 3*4882a593SmuzhiyunDate: Thu, 9 Jul 2020 08:10:40 +0000 4*4882a593SmuzhiyunSubject: [PATCH] tftp: Do not use priority queue 5*4882a593SmuzhiyunMIME-Version: 1.0 6*4882a593SmuzhiyunContent-Type: text/plain; charset=UTF-8 7*4882a593SmuzhiyunContent-Transfer-Encoding: 8bit 8*4882a593Smuzhiyun 9*4882a593SmuzhiyunThere is not need to reassemble the order of blocks. Per RFC 1350, 10*4882a593Smuzhiyunserver must wait for the ACK, before sending next block. Data packets 11*4882a593Smuzhiyuncan be served immediately without putting them to priority queue. 12*4882a593Smuzhiyun 13*4882a593SmuzhiyunLogic to handle incoming packet is this: 14*4882a593Smuzhiyun - if packet block id equal to expected block id, then 15*4882a593Smuzhiyun process the packet, 16*4882a593Smuzhiyun - if packet block id is less than expected - this is retransmit 17*4882a593Smuzhiyun of old packet, then ACK it and drop the packet, 18*4882a593Smuzhiyun - if packet block id is more than expected - that shouldn't 19*4882a593Smuzhiyun happen, just drop the packet. 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunIt makes the tftp receive path code simpler, smaller and faster. 22*4882a593SmuzhiyunAs a benefit, this change fixes CID# 73624 and CID# 96690, caused 23*4882a593Smuzhiyunby following while loop: 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun while (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) == 0) 26*4882a593Smuzhiyun 27*4882a593Smuzhiyunwhere tftph pointer is not moving from one iteration to another, causing 28*4882a593Smuzhiyunto serve same packet again. Luckily, double serving didn't happen due to 29*4882a593Smuzhiyundata->block++ during the first iteration. 30*4882a593Smuzhiyun 31*4882a593SmuzhiyunFixes: CID 73624, CID 96690 32*4882a593Smuzhiyun 33*4882a593SmuzhiyunSigned-off-by: Alexey Makhalov <amakhalov@vmware.com> 34*4882a593SmuzhiyunReviewed-by: Daniel Kiper <daniel.kiper@oracle.com> 35*4882a593SmuzhiyunSigned-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com> 36*4882a593Smuzhiyun--- 37*4882a593Smuzhiyun grub-core/net/tftp.c | 168 ++++++++++++++----------------------------- 38*4882a593Smuzhiyun 1 file changed, 53 insertions(+), 115 deletions(-) 39*4882a593Smuzhiyun 40*4882a593Smuzhiyundiff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c 41*4882a593Smuzhiyunindex 7d90bf66e..b4297bc8d 100644 42*4882a593Smuzhiyun--- a/grub-core/net/tftp.c 43*4882a593Smuzhiyun+++ b/grub-core/net/tftp.c 44*4882a593Smuzhiyun@@ -25,7 +25,6 @@ 45*4882a593Smuzhiyun #include <grub/mm.h> 46*4882a593Smuzhiyun #include <grub/dl.h> 47*4882a593Smuzhiyun #include <grub/file.h> 48*4882a593Smuzhiyun-#include <grub/priority_queue.h> 49*4882a593Smuzhiyun #include <grub/i18n.h> 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun GRUB_MOD_LICENSE ("GPLv3+"); 52*4882a593Smuzhiyun@@ -106,31 +105,8 @@ typedef struct tftp_data 53*4882a593Smuzhiyun int have_oack; 54*4882a593Smuzhiyun struct grub_error_saved save_err; 55*4882a593Smuzhiyun grub_net_udp_socket_t sock; 56*4882a593Smuzhiyun- grub_priority_queue_t pq; 57*4882a593Smuzhiyun } *tftp_data_t; 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun-static int 60*4882a593Smuzhiyun-cmp_block (grub_uint16_t a, grub_uint16_t b) 61*4882a593Smuzhiyun-{ 62*4882a593Smuzhiyun- grub_int16_t i = (grub_int16_t) (a - b); 63*4882a593Smuzhiyun- if (i > 0) 64*4882a593Smuzhiyun- return +1; 65*4882a593Smuzhiyun- if (i < 0) 66*4882a593Smuzhiyun- return -1; 67*4882a593Smuzhiyun- return 0; 68*4882a593Smuzhiyun-} 69*4882a593Smuzhiyun- 70*4882a593Smuzhiyun-static int 71*4882a593Smuzhiyun-cmp (const void *a__, const void *b__) 72*4882a593Smuzhiyun-{ 73*4882a593Smuzhiyun- struct grub_net_buff *a_ = *(struct grub_net_buff **) a__; 74*4882a593Smuzhiyun- struct grub_net_buff *b_ = *(struct grub_net_buff **) b__; 75*4882a593Smuzhiyun- struct tftphdr *a = (struct tftphdr *) a_->data; 76*4882a593Smuzhiyun- struct tftphdr *b = (struct tftphdr *) b_->data; 77*4882a593Smuzhiyun- /* We want the first elements to be on top. */ 78*4882a593Smuzhiyun- return -cmp_block (grub_be_to_cpu16 (a->u.data.block), grub_be_to_cpu16 (b->u.data.block)); 79*4882a593Smuzhiyun-} 80*4882a593Smuzhiyun- 81*4882a593Smuzhiyun static grub_err_t 82*4882a593Smuzhiyun ack (tftp_data_t data, grub_uint64_t block) 83*4882a593Smuzhiyun { 84*4882a593Smuzhiyun@@ -207,73 +183,60 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), 85*4882a593Smuzhiyun return GRUB_ERR_NONE; 86*4882a593Smuzhiyun } 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun- err = grub_priority_queue_push (data->pq, &nb); 89*4882a593Smuzhiyun- if (err) 90*4882a593Smuzhiyun- return err; 91*4882a593Smuzhiyun- 92*4882a593Smuzhiyun- { 93*4882a593Smuzhiyun- struct grub_net_buff **nb_top_p, *nb_top; 94*4882a593Smuzhiyun- while (1) 95*4882a593Smuzhiyun- { 96*4882a593Smuzhiyun- nb_top_p = grub_priority_queue_top (data->pq); 97*4882a593Smuzhiyun- if (!nb_top_p) 98*4882a593Smuzhiyun- return GRUB_ERR_NONE; 99*4882a593Smuzhiyun- nb_top = *nb_top_p; 100*4882a593Smuzhiyun- tftph = (struct tftphdr *) nb_top->data; 101*4882a593Smuzhiyun- if (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) >= 0) 102*4882a593Smuzhiyun- break; 103*4882a593Smuzhiyun- ack (data, grub_be_to_cpu16 (tftph->u.data.block)); 104*4882a593Smuzhiyun- grub_netbuff_free (nb_top); 105*4882a593Smuzhiyun- grub_priority_queue_pop (data->pq); 106*4882a593Smuzhiyun- } 107*4882a593Smuzhiyun- while (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) == 0) 108*4882a593Smuzhiyun- { 109*4882a593Smuzhiyun- unsigned size; 110*4882a593Smuzhiyun- 111*4882a593Smuzhiyun- grub_priority_queue_pop (data->pq); 112*4882a593Smuzhiyun- 113*4882a593Smuzhiyun- if (file->device->net->packs.count < 50) 114*4882a593Smuzhiyun+ /* Ack old/retransmitted block. */ 115*4882a593Smuzhiyun+ if (grub_be_to_cpu16 (tftph->u.data.block) < data->block + 1) 116*4882a593Smuzhiyun+ ack (data, grub_be_to_cpu16 (tftph->u.data.block)); 117*4882a593Smuzhiyun+ /* Ignore unexpected block. */ 118*4882a593Smuzhiyun+ else if (grub_be_to_cpu16 (tftph->u.data.block) > data->block + 1) 119*4882a593Smuzhiyun+ grub_dprintf ("tftp", "TFTP unexpected block # %d\n", tftph->u.data.block); 120*4882a593Smuzhiyun+ else 121*4882a593Smuzhiyun+ { 122*4882a593Smuzhiyun+ unsigned size; 123*4882a593Smuzhiyun+ 124*4882a593Smuzhiyun+ if (file->device->net->packs.count < 50) 125*4882a593Smuzhiyun+ { 126*4882a593Smuzhiyun err = ack (data, data->block + 1); 127*4882a593Smuzhiyun- else 128*4882a593Smuzhiyun- { 129*4882a593Smuzhiyun- file->device->net->stall = 1; 130*4882a593Smuzhiyun- err = 0; 131*4882a593Smuzhiyun- } 132*4882a593Smuzhiyun- if (err) 133*4882a593Smuzhiyun- return err; 134*4882a593Smuzhiyun- 135*4882a593Smuzhiyun- err = grub_netbuff_pull (nb_top, sizeof (tftph->opcode) + 136*4882a593Smuzhiyun- sizeof (tftph->u.data.block)); 137*4882a593Smuzhiyun- if (err) 138*4882a593Smuzhiyun- return err; 139*4882a593Smuzhiyun- size = nb_top->tail - nb_top->data; 140*4882a593Smuzhiyun- 141*4882a593Smuzhiyun- data->block++; 142*4882a593Smuzhiyun- if (size < data->block_size) 143*4882a593Smuzhiyun- { 144*4882a593Smuzhiyun- if (data->ack_sent < data->block) 145*4882a593Smuzhiyun- ack (data, data->block); 146*4882a593Smuzhiyun- file->device->net->eof = 1; 147*4882a593Smuzhiyun- file->device->net->stall = 1; 148*4882a593Smuzhiyun- grub_net_udp_close (data->sock); 149*4882a593Smuzhiyun- data->sock = NULL; 150*4882a593Smuzhiyun- } 151*4882a593Smuzhiyun- /* Prevent garbage in broken cards. Is it still necessary 152*4882a593Smuzhiyun- given that IP implementation has been fixed? 153*4882a593Smuzhiyun- */ 154*4882a593Smuzhiyun- if (size > data->block_size) 155*4882a593Smuzhiyun- { 156*4882a593Smuzhiyun- err = grub_netbuff_unput (nb_top, size - data->block_size); 157*4882a593Smuzhiyun- if (err) 158*4882a593Smuzhiyun- return err; 159*4882a593Smuzhiyun- } 160*4882a593Smuzhiyun- /* If there is data, puts packet in socket list. */ 161*4882a593Smuzhiyun- if ((nb_top->tail - nb_top->data) > 0) 162*4882a593Smuzhiyun- grub_net_put_packet (&file->device->net->packs, nb_top); 163*4882a593Smuzhiyun- else 164*4882a593Smuzhiyun- grub_netbuff_free (nb_top); 165*4882a593Smuzhiyun- } 166*4882a593Smuzhiyun- } 167*4882a593Smuzhiyun+ if (err) 168*4882a593Smuzhiyun+ return err; 169*4882a593Smuzhiyun+ } 170*4882a593Smuzhiyun+ else 171*4882a593Smuzhiyun+ file->device->net->stall = 1; 172*4882a593Smuzhiyun+ 173*4882a593Smuzhiyun+ err = grub_netbuff_pull (nb, sizeof (tftph->opcode) + 174*4882a593Smuzhiyun+ sizeof (tftph->u.data.block)); 175*4882a593Smuzhiyun+ if (err) 176*4882a593Smuzhiyun+ return err; 177*4882a593Smuzhiyun+ size = nb->tail - nb->data; 178*4882a593Smuzhiyun+ 179*4882a593Smuzhiyun+ data->block++; 180*4882a593Smuzhiyun+ if (size < data->block_size) 181*4882a593Smuzhiyun+ { 182*4882a593Smuzhiyun+ if (data->ack_sent < data->block) 183*4882a593Smuzhiyun+ ack (data, data->block); 184*4882a593Smuzhiyun+ file->device->net->eof = 1; 185*4882a593Smuzhiyun+ file->device->net->stall = 1; 186*4882a593Smuzhiyun+ grub_net_udp_close (data->sock); 187*4882a593Smuzhiyun+ data->sock = NULL; 188*4882a593Smuzhiyun+ } 189*4882a593Smuzhiyun+ /* 190*4882a593Smuzhiyun+ * Prevent garbage in broken cards. Is it still necessary 191*4882a593Smuzhiyun+ * given that IP implementation has been fixed? 192*4882a593Smuzhiyun+ */ 193*4882a593Smuzhiyun+ if (size > data->block_size) 194*4882a593Smuzhiyun+ { 195*4882a593Smuzhiyun+ err = grub_netbuff_unput (nb, size - data->block_size); 196*4882a593Smuzhiyun+ if (err) 197*4882a593Smuzhiyun+ return err; 198*4882a593Smuzhiyun+ } 199*4882a593Smuzhiyun+ /* If there is data, puts packet in socket list. */ 200*4882a593Smuzhiyun+ if ((nb->tail - nb->data) > 0) 201*4882a593Smuzhiyun+ { 202*4882a593Smuzhiyun+ grub_net_put_packet (&file->device->net->packs, nb); 203*4882a593Smuzhiyun+ /* Do not free nb. */ 204*4882a593Smuzhiyun+ return GRUB_ERR_NONE; 205*4882a593Smuzhiyun+ } 206*4882a593Smuzhiyun+ } 207*4882a593Smuzhiyun+ grub_netbuff_free (nb); 208*4882a593Smuzhiyun return GRUB_ERR_NONE; 209*4882a593Smuzhiyun case TFTP_ERROR: 210*4882a593Smuzhiyun data->have_oack = 1; 211*4882a593Smuzhiyun@@ -287,19 +250,6 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), 212*4882a593Smuzhiyun } 213*4882a593Smuzhiyun } 214*4882a593Smuzhiyun 215*4882a593Smuzhiyun-static void 216*4882a593Smuzhiyun-destroy_pq (tftp_data_t data) 217*4882a593Smuzhiyun-{ 218*4882a593Smuzhiyun- struct grub_net_buff **nb_p; 219*4882a593Smuzhiyun- while ((nb_p = grub_priority_queue_top (data->pq))) 220*4882a593Smuzhiyun- { 221*4882a593Smuzhiyun- grub_netbuff_free (*nb_p); 222*4882a593Smuzhiyun- grub_priority_queue_pop (data->pq); 223*4882a593Smuzhiyun- } 224*4882a593Smuzhiyun- 225*4882a593Smuzhiyun- grub_priority_queue_destroy (data->pq); 226*4882a593Smuzhiyun-} 227*4882a593Smuzhiyun- 228*4882a593Smuzhiyun static grub_err_t 229*4882a593Smuzhiyun tftp_open (struct grub_file *file, const char *filename) 230*4882a593Smuzhiyun { 231*4882a593Smuzhiyun@@ -372,17 +322,9 @@ tftp_open (struct grub_file *file, const char *filename) 232*4882a593Smuzhiyun file->not_easily_seekable = 1; 233*4882a593Smuzhiyun file->data = data; 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun- data->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp); 236*4882a593Smuzhiyun- if (!data->pq) 237*4882a593Smuzhiyun- { 238*4882a593Smuzhiyun- grub_free (data); 239*4882a593Smuzhiyun- return grub_errno; 240*4882a593Smuzhiyun- } 241*4882a593Smuzhiyun- 242*4882a593Smuzhiyun err = grub_net_resolve_address (file->device->net->server, &addr); 243*4882a593Smuzhiyun if (err) 244*4882a593Smuzhiyun { 245*4882a593Smuzhiyun- destroy_pq (data); 246*4882a593Smuzhiyun grub_free (data); 247*4882a593Smuzhiyun return err; 248*4882a593Smuzhiyun } 249*4882a593Smuzhiyun@@ -392,7 +334,6 @@ tftp_open (struct grub_file *file, const char *filename) 250*4882a593Smuzhiyun file); 251*4882a593Smuzhiyun if (!data->sock) 252*4882a593Smuzhiyun { 253*4882a593Smuzhiyun- destroy_pq (data); 254*4882a593Smuzhiyun grub_free (data); 255*4882a593Smuzhiyun return grub_errno; 256*4882a593Smuzhiyun } 257*4882a593Smuzhiyun@@ -406,7 +347,6 @@ tftp_open (struct grub_file *file, const char *filename) 258*4882a593Smuzhiyun if (err) 259*4882a593Smuzhiyun { 260*4882a593Smuzhiyun grub_net_udp_close (data->sock); 261*4882a593Smuzhiyun- destroy_pq (data); 262*4882a593Smuzhiyun grub_free (data); 263*4882a593Smuzhiyun return err; 264*4882a593Smuzhiyun } 265*4882a593Smuzhiyun@@ -423,7 +363,6 @@ tftp_open (struct grub_file *file, const char *filename) 266*4882a593Smuzhiyun if (grub_errno) 267*4882a593Smuzhiyun { 268*4882a593Smuzhiyun grub_net_udp_close (data->sock); 269*4882a593Smuzhiyun- destroy_pq (data); 270*4882a593Smuzhiyun grub_free (data); 271*4882a593Smuzhiyun return grub_errno; 272*4882a593Smuzhiyun } 273*4882a593Smuzhiyun@@ -466,7 +405,6 @@ tftp_close (struct grub_file *file) 274*4882a593Smuzhiyun grub_print_error (); 275*4882a593Smuzhiyun grub_net_udp_close (data->sock); 276*4882a593Smuzhiyun } 277*4882a593Smuzhiyun- destroy_pq (data); 278*4882a593Smuzhiyun grub_free (data); 279*4882a593Smuzhiyun return GRUB_ERR_NONE; 280*4882a593Smuzhiyun } 281*4882a593Smuzhiyun-- 282*4882a593Smuzhiyun2.26.2 283*4882a593Smuzhiyun 284