pxe: Add methods to abstract out the connection type.
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 8 Apr 2011 09:13:15 +0000 (02:13 -0700)
committerEric W. Biederman <ebiederm@xmission.com>
Tue, 12 Apr 2011 21:40:44 +0000 (14:40 -0700)
The gpxe handling has already found the places where
we need to have different code to handle different
connection types.  So add function pointers into
struct pxe_pvt_inode for each of those places and
cleanup the code to call those new functions.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
core/fs/pxe/pxe.c
core/fs/pxe/pxe.h

index 262b38e..9c40fa1 100644 (file)
@@ -93,20 +93,21 @@ static void gpxe_close_file(struct inode *inode)
 }
 #endif
 
+static void tftp_close_file(struct inode *inode)
+{
+    struct pxe_pvt_inode *socket = PVT(inode);
+    if (socket->tftp_localport != 0) {
+       tftp_error(inode, 0, "No error, file close");
+    }
+}
+
 static void pxe_close_file(struct file *file)
 {
     struct inode *inode = file->inode;
     struct pxe_pvt_inode *socket = PVT(inode);
 
     if (!socket->tftp_goteof) {
-#if GPXE
-       if (socket->tftp_localport == 0xffff) {
-           gpxe_close_file(inode);
-       } else
-#endif
-       if (socket->tftp_localport != 0) {
-           tftp_error(inode, 0, "No error, file close");
-       }
+       socket->close(inode);
     }
 
     free_socket(inode);
@@ -421,7 +422,7 @@ static enum pxe_path_type pxe_path_type(const char *str)
  * @param: inode -> Inode pointer
  *
  */
-static void get_packet_gpxe(struct inode *inode)
+static void gpxe_get_packet(struct inode *inode)
 {
     struct pxe_pvt_inode *socket = PVT(inode);
     static __lowmem struct s_PXENV_FILE_READ file_read;
@@ -478,7 +479,7 @@ static void pxe_mangle_name(char *dst, const char *src)
  * Get a fresh packet if the buffer is drained, and we haven't hit
  * EOF yet.  The buffer should be filled immediately after draining!
  */
-static void fill_buffer(struct inode *inode)
+static void tftp_get_packet(struct inode *inode)
 {
     int err;
     int last_pkt;
@@ -490,16 +491,6 @@ static void fill_buffer(struct inode *inode)
     static __lowmem struct s_PXENV_UDP_READ udp_read;
     struct pxe_pvt_inode *socket = PVT(inode);
 
-    if (socket->tftp_bytesleft || socket->tftp_goteof)
-        return;
-
-#if GPXE
-    if (socket->tftp_localport == 0xffff) {
-        get_packet_gpxe(inode);
-        return;
-    }
-#endif
-
     /*
      * Start by ACKing the previous packet; this should cause
      * the next packet to be sent.
@@ -580,6 +571,19 @@ static void fill_buffer(struct inode *inode)
     }
 }
 
+/*
+ * Get a fresh packet if the buffer is drained, and we haven't hit
+ * EOF yet.  The buffer should be filled immediately after draining!
+ */
+static void fill_buffer(struct inode *inode)
+{
+    struct pxe_pvt_inode *socket = PVT(inode);
+    if (socket->tftp_bytesleft || socket->tftp_goteof)
+        return;
+
+    return socket->fill_buffer(inode);
+}
+
 
 /**
  * getfssec: Get multiple clusters from a file, given the starting cluster.
@@ -634,42 +638,58 @@ static uint32_t pxe_getfssec(struct file *file, char *buf,
     return bytes_read;
 }
 
+#if GPXE
 /**
- * Open a TFTP connection to the server
+ * Open a url using gpxe
  *
- * @param:filename, the file we wanna open
+ * @param:inode, the inode to store our state in
+ * @param:url, the url we want to open
  *
  * @out: open_file_t structure, stores in file->open_file
  * @out: the lenght of this file, stores in file->file_len
  *
  */
-static void __pxe_searchdir(const char *filename, struct file *file);
-extern uint16_t PXERetry;
-
-static void pxe_searchdir(const char *filename, struct file *file)
+static void gpxe_open(struct inode *inode, const char *url)
 {
-    int i = PXERetry;
+    static __lowmem struct s_PXENV_FILE_OPEN file_open;
+    static char lowurl[2*FILENAME_MAX];
+    struct pxe_pvt_inode *socket = PVT(inode);
+    int err;
 
-    do {
-       dprintf("PXE: file = %p, retries left = %d: ", file, i);
-       __pxe_searchdir(filename, file);
-       dprintf("%s\n", file->inode ? "ok" : "failed");
-    } while (!file->inode && i--);
+    snprintf(lowurl, sizeof lowurl, "%s", url);
+    file_open.Status        = PXENV_STATUS_BAD_FUNC;
+    file_open.FileName      = FAR_PTR(lowurl);
+    err = pxe_call(PXENV_FILE_OPEN, &file_open);
+    if (err)
+       return; 
+
+    socket->fill_buffer = gpxe_get_packet;
+    socket->close = gpxe_close_file;
+    socket->tftp_remoteport = file_open.FileHandle;
+    inode->size = -1; /* This is not an error */
 }
+#endif
 
-static void __pxe_searchdir(const char *filename, struct file *file)
+/**
+ * Open a TFTP connection to the server
+ *
+ * @param:inode, the inode to store our state in
+ * @param:ip, the ip to contact to get the file
+ * @param:filename, the file we wanna open
+ *
+ * @out: open_file_t structure, stores in file->open_file
+ * @out: the lenght of this file, stores in file->file_len
+ *
+ */
+static void tftp_open(struct inode *inode, uint32_t ip, uint16_t server_port, const char *filename)
 {
-    struct fs_info *fs = file->fs;
-    struct inode *inode;
-    struct pxe_pvt_inode *socket;
+    struct pxe_pvt_inode *socket = PVT(inode);
     char *buf;
-    const char *np;
     char *p;
     char *options;
     char *data;
     static __lowmem struct s_PXENV_UDP_WRITE udp_write;
     static __lowmem struct s_PXENV_UDP_READ  udp_read;
-    static __lowmem struct s_PXENV_FILE_OPEN file_open;
     static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
     static __lowmem char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
     const struct tftp_options *tftp_opt;
@@ -683,76 +703,16 @@ static void __pxe_searchdir(const char *filename, struct file *file)
     uint16_t tid;
     uint16_t opcode;
     uint16_t blk_num;
-    uint32_t ip = 0;
     uint32_t opdata, *opdata_ptr;
-    enum pxe_path_type path_type;
-    char fullpath[2*FILENAME_MAX];
-    uint16_t server_port = TFTP_PORT;  /* TFTP server port */
 
-    inode = file->inode = NULL;
-       
+    socket->fill_buffer = tftp_get_packet;
+    socket->close = tftp_close_file;
+
     buf = rrq_packet_buf;
     *(uint16_t *)buf = TFTP_RRQ;  /* TFTP opcode */
     buf += 2;
 
-    path_type = pxe_path_type(filename);
-    if (path_type == PXE_RELATIVE) {
-       snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
-       path_type = pxe_path_type(filename = fullpath);
-    }
-
-    switch (path_type) {
-    case PXE_RELATIVE:         /* Really shouldn't happen... */
-    case PXE_URL:
-       buf = stpcpy(buf, filename);
-       ip = IPInfo.serverip;   /* Default server */
-       break;
-
-    case PXE_HOMESERVER:
-       buf = stpcpy(buf, filename+2);
-       ip = IPInfo.serverip;
-       break;
-
-    case PXE_TFTP:
-       np = strchr(filename, ':');
-       buf = stpcpy(buf, np+2);
-       if (parse_dotquad(filename, &ip) != np)
-           ip = dns_resolv(filename);
-       break;
-
-    case PXE_URL_TFTP:
-       np = filename + 7;
-       while (*np && *np != '/' && *np != ':')
-           np++;
-       if (np > filename + 7) {
-           if (parse_dotquad(filename + 7, &ip) != np)
-               ip = dns_resolv(filename + 7);
-       }
-       if (*np == ':') {
-           np++;
-           server_port = 0;
-           while (*np >= '0' && *np <= '9')
-               server_port = server_port * 10 + *np++ - '0';
-           server_port = server_port ? htons(server_port) : TFTP_PORT;
-       }
-       if (*np == '/')
-           np++;               /* Do *NOT* eat more than one slash here... */
-       /*
-        * The ; is because of a quirk in the TFTP URI spec (RFC
-        * 3617); it is to be followed by TFTP modes, which we just ignore.
-        */
-       while (*np && *np != ';') {
-           int v;
-           if (*np == '%' && (v = hexbyte(np+1)) > 0) {
-               *buf++ = v;
-               np += 3;
-           } else {
-               *buf++ = *np++;
-           }
-       }
-       *buf = '\0';
-       break;
-    }
+    buf = stpcpy(buf, filename);
 
     buf++;                     /* Point *past* the final NULL */
     memcpy(buf, rrq_tail, sizeof rrq_tail);
@@ -760,38 +720,6 @@ static void __pxe_searchdir(const char *filename, struct file *file)
 
     rrq_len = buf - rrq_packet_buf;
 
-    inode = allocate_socket(fs);
-    if (!inode)
-       return;                 /* Allocation failure */
-    socket = PVT(inode);
-
-#if GPXE
-    if (path_type == PXE_URL) {
-       if (has_gpxe) {
-           file_open.Status        = PXENV_STATUS_BAD_FUNC;
-           file_open.FileName      = FAR_PTR(rrq_packet_buf + 2);
-           err = pxe_call(PXENV_FILE_OPEN, &file_open);
-           if (err)
-               goto done;
-           
-           socket->tftp_localport = -1;
-           socket->tftp_remoteport = file_open.FileHandle;
-           inode->size = -1;
-           goto done;
-       } else {
-           static bool already = false;
-           if (!already) {
-               printf("URL syntax, but gPXE extensions not detected, "
-                      "trying plain TFTP...\n");
-               already = true;
-           }
-       }
-    }
-#endif /* GPXE */
-
-    if (!ip)
-           goto done;          /* No server */
-
     timeout_ptr = TimeoutTable;   /* Reset timeout */
     
 sendreq:
@@ -964,13 +892,7 @@ wait_pkt:
        printf("TFTP unknown opcode %d\n", ntohs(opcode));
        goto err_reply;
     }
-
 done:
-    if (!inode->size) {
-        free_socket(inode);
-       return;
-    }
-    file->inode = inode;
     return;
 
 err_reply:
@@ -980,6 +902,133 @@ err_reply:
     kaboom();
 }
 
+/**
+ * Open the specified connection
+ *
+ * @param:filename, the file we wanna open
+ *
+ * @out: open_file_t structure, stores in file->open_file
+ * @out: the lenght of this file, stores in file->file_len
+ *
+ */
+static void __pxe_searchdir(const char *filename, struct file *file);
+extern uint16_t PXERetry;
+
+static void pxe_searchdir(const char *filename, struct file *file)
+{
+    int i = PXERetry;
+
+    do {
+       dprintf("PXE: file = %p, retries left = %d: ", file, i);
+       __pxe_searchdir(filename, file);
+       dprintf("%s\n", file->inode ? "ok" : "failed");
+    } while (!file->inode && i--);
+}
+static void __pxe_searchdir(const char *filename, struct file *file)
+{
+    struct fs_info *fs = file->fs;
+    struct inode *inode;
+    const char *np;
+    char *buf;
+    uint32_t ip = 0;
+    enum pxe_path_type path_type;
+    char fullpath[2*FILENAME_MAX];
+    uint16_t server_port = TFTP_PORT;  /* TFTP server port */
+
+    inode = file->inode = NULL;
+
+    path_type = pxe_path_type(filename);
+    if (path_type == PXE_RELATIVE) {
+       snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
+       path_type = pxe_path_type(filename = fullpath);
+    }
+
+    switch (path_type) {
+    case PXE_RELATIVE:         /* Really shouldn't happen... */
+    case PXE_URL:
+       ip = IPInfo.serverip;   /* Default server */
+       break;
+
+    case PXE_HOMESERVER:
+       filename = filename+2;
+       ip = IPInfo.serverip;
+       break;
+
+    case PXE_TFTP:
+       np = strchr(filename, ':');
+       if (parse_dotquad(filename, &ip) != np)
+           ip = dns_resolv(filename);
+       filename = np+2;
+       break;
+
+    case PXE_URL_TFTP:
+       np = filename + 7;
+       while (*np && *np != '/' && *np != ':')
+           np++;
+       if (np > filename + 7) {
+           if (parse_dotquad(filename + 7, &ip) != np)
+               ip = dns_resolv(filename + 7);
+       }
+       if (*np == ':') {
+           np++;
+           server_port = 0;
+           while (*np >= '0' && *np <= '9')
+               server_port = server_port * 10 + *np++ - '0';
+           server_port = server_port ? htons(server_port) : TFTP_PORT;
+       }
+       if (*np == '/')
+           np++;               /* Do *NOT* eat more than one slash here... */
+       /*
+        * The ; is because of a quirk in the TFTP URI spec (RFC
+        * 3617); it is to be followed by TFTP modes, which we just ignore.
+        */
+       filename = buf = fullpath;
+       while (*np && *np != ';') {
+           int v;
+           if (*np == '%' && (v = hexbyte(np+1)) > 0) {
+               *buf++ = v;
+               np += 3;
+           } else {
+               *buf++ = *np++;
+           }
+       }
+       *buf = '\0';
+       break;
+    }
+
+    inode = allocate_socket(fs);
+    if (!inode)
+       return;                 /* Allocation failure */
+
+#if GPXE
+    if (path_type == PXE_URL) {
+       if (has_gpxe) {
+           gpxe_open(inode, filename);
+           goto done;
+       } else {
+           static bool already = false;
+           if (!already) {
+               printf("URL syntax, but gPXE extensions not detected, "
+                      "trying plain TFTP...\n");
+               already = true;
+           }
+       }
+    }
+#endif /* GPXE */
+
+    if (!ip)
+           goto done;          /* No server */
+
+    tftp_open(inode, ip, server_port, filename);
+done:
+    if (!inode->size) {
+        free_socket(inode);
+       return;
+    }
+    file->inode = inode;
+    return;
+}
+
 
 /*
  * Store standard filename prefix
index 1e6fa76..b199ea1 100644 (file)
@@ -163,6 +163,8 @@ struct pxe_pvt_inode {
     char    *tftp_dataptr;     /* Pointer to available data */
     uint8_t  tftp_goteof;      /* 1 if the EOF packet received */
     uint8_t  tftp_unused[3];   /* Currently unused */
+    void (*fill_buffer)(struct inode *inode);
+    void (*close)(struct inode *inode);
     char     tftp_pktbuf[PKTBUF_SIZE];
 } __attribute__ ((packed));