📄 nfsroot.c
字号:
oldfs = get_fs(); set_fs(get_ds()); iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; result = sock->ops->sendmsg(sock, &msg, size, 0, 0); set_fs(oldfs); return (result != size);}/* * Try to receive UDP packet. */static inline int root_recv_udp(struct socket *sock, void *buf, int size){ u32 oldfs; int result; struct msghdr msg; struct iovec iov; oldfs = get_fs(); set_fs(get_ds()); iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_namelen = 0; result = sock->ops->recvmsg(sock, &msg, size, O_NONBLOCK, 0, &msg.msg_namelen); set_fs(oldfs); return result;}/* * Initialize BOOTP extension fields in the request. */static void root_bootp_init_ext(u8 *e){ *e++ = 99; /* RFC1048 Magic Cookie */ *e++ = 130; *e++ = 83; *e++ = 99; *e++ = 1; /* Subnet mask request */ *e++ = 4; e += 4; *e++ = 3; /* Default gateway request */ *e++ = 4; e += 4; *e++ = 12; /* Host name request */ *e++ = 32; e += 32; *e++ = 40; /* NIS Domain name request */ *e++ = 32; e += 32; *e++ = 17; /* Boot path */ *e++ = 32; e += 32; *e = 255; /* End of the list */}/* * Deinitialize the BOOTP mechanism. */static void root_bootp_close(void){ if (bootp_xmit_fd != -1) sys_close(bootp_xmit_fd); if (bootp_recv_fd != -1) sys_close(bootp_recv_fd); root_del_bootp_route(); root_free_bootp();}/* * Initialize the BOOTP mechanism. */static int root_bootp_open(void){ struct open_dev *openp; struct device *dev, *best_dev; /* * Select the best interface for BOOTP. We try to select a first * Ethernet-like interface. It's shame I know no simple way how to send * BOOTP's to all interfaces, but it doesn't apply to usual diskless * stations as they don't have multiple interfaces. */ best_dev = NULL; for (openp = open_base; openp != NULL; openp = openp->next) { dev = openp->dev; if (dev->flags & IFF_BROADCAST) { if (!best_dev || ((best_dev->flags & IFF_NOARP) && !(dev->flags & IFF_NOARP))) best_dev = dev; } } if (!best_dev) { printk(KERN_ERR "BOOTP: This cannot happen!\n"); return -1; } bootp_dev = best_dev; /* Allocate memory for BOOTP packets */ if (root_alloc_bootp()) return -1; /* Construct BOOTP request */ memset(xmit_bootp, 0, sizeof(struct bootp_pkt)); xmit_bootp->op = BOOTP_REQUEST; get_random_bytes(&xmit_bootp->xid, sizeof(xmit_bootp->xid)); xmit_bootp->htype = best_dev->type; xmit_bootp->hlen = best_dev->addr_len; memcpy(xmit_bootp->hw_addr, best_dev->dev_addr, best_dev->addr_len); root_bootp_init_ext(xmit_bootp->vendor_area);#ifdef NFSROOT_BOOTP_DEBUG { int x; printk(KERN_NOTICE "BOOTP: XID=%08x, DE=%s, HT=%02x, HL=%02x, HA=", xmit_bootp->xid, best_dev->name, xmit_bootp->htype, xmit_bootp->hlen); for(x=0; x<xmit_bootp->hlen; x++) printk("%02x", xmit_bootp->hw_addr[x]); printk("\n"); }#endif /* Create default route to that interface */ if (root_add_bootp_route()) return -1; /* Open the sockets */ if (root_open_udp_sock(&bootp_xmit_fd, &bootp_xmit_sock) || root_open_udp_sock(&bootp_recv_fd, &bootp_recv_sock)) return -1; /* Bind/connect the sockets */ ((struct sock *) bootp_xmit_sock->data) -> broadcast = 1; ((struct sock *) bootp_xmit_sock->data) -> reuse = 1; ((struct sock *) bootp_recv_sock->data) -> reuse = 1; if (root_bind_udp_sock(bootp_recv_sock, INADDR_ANY, 68) || root_bind_udp_sock(bootp_xmit_sock, INADDR_ANY, 68) || root_connect_udp_sock(bootp_xmit_sock, INADDR_BROADCAST, 67)) return -1; return 0;}/* * Send BOOTP request. */static int root_bootp_send(u32 jiffies){ xmit_bootp->secs = htons(jiffies / HZ); return root_send_udp(bootp_xmit_sock, xmit_bootp, sizeof(struct bootp_pkt));}/* * Copy BOOTP-supplied string if not already set. */static int root_bootp_string(char *dest, char *src, int len, int max){ if (*dest || !len) return 0; if (len > max-1) len = max-1; strncpy(dest, src, len); dest[len] = '\0'; return 1;}/* * Process BOOTP extension. */static void root_do_bootp_ext(u8 *ext){#ifdef NFSROOT_BOOTP_DEBUG u8 *c; printk("BOOTP: Got extension %02x",*ext); for(c=ext+2; c<ext+2+ext[1]; c++) printk(" %02x", *c); printk("\n");#endif switch (*ext++) { case 1: /* Subnet mask */ if (netmask.sin_addr.s_addr == INADDR_NONE) memcpy(&netmask.sin_addr.s_addr, ext+1, 4); break; case 3: /* Default gateway */ if (gateway.sin_addr.s_addr == INADDR_NONE) memcpy(&gateway.sin_addr.s_addr, ext+1, 4); break; case 12: /* Host name */ root_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN); break; case 40: /* NIS Domain name */ root_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN); break; case 17: /* Root path */ root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN); break; }}/* * Receive BOOTP request. */static void root_bootp_recv(void){ int len; u8 *ext, *end, *opt; len = root_recv_udp(bootp_recv_sock, recv_bootp, sizeof(struct bootp_pkt)); if (len < 0) return; /* Check consistency of incoming packet */ if (len < 300 || /* See RFC 1542:2.1 */ recv_bootp->op != BOOTP_REPLY || recv_bootp->htype != xmit_bootp->htype || recv_bootp->hlen != xmit_bootp->hlen || recv_bootp->xid != xmit_bootp->xid) {#ifdef NFSROOT_BOOTP_DEBUG printk("?");#endif return; } /* Record BOOTP packet arrival in the global variables */ cli(); if (pkt_arrived) { sti(); return; } pkt_arrived = ARRIVED_BOOTP; sti(); root_dev = bootp_dev; /* Extract basic fields */ myaddr.sin_addr.s_addr = recv_bootp->your_ip; if (server.sin_addr.s_addr==INADDR_NONE) server.sin_addr.s_addr = recv_bootp->server_ip; /* Parse extensions */ if (recv_bootp->vendor_area[0] == 99 && /* Check magic cookie */ recv_bootp->vendor_area[1] == 130 && recv_bootp->vendor_area[2] == 83 && recv_bootp->vendor_area[3] == 99) { ext = &recv_bootp->vendor_area[4]; end = (u8 *) recv_bootp + len; while (ext < end && *ext != 255) { if (*ext == 0) /* Padding */ ext++; else { opt = ext; ext += ext[1] + 2; if (ext <= end) root_do_bootp_ext(opt); } } }}#endif/*************************************************************************** Dynamic configuration of IP. ***************************************************************************/#ifdef CONFIG_RNFS_DYNAMIC/* * Determine client and server IP numbers and appropriate device by using * the RARP and BOOTP protocols. */static int root_auto_config(void){ int retries; unsigned long timeout, jiff; unsigned long start_jiffies; /* * If neither BOOTP nor RARP was selected, return with an error. This * routine gets only called when some pieces of information are mis- * sing, and without BOOTP and RARP we are not able to get that in- * formation. */ if (!bootp_flag && !rarp_flag) { printk(KERN_ERR "Root-NFS: Neither RARP nor BOOTP selected.\n"); return -1; }#ifdef CONFIG_RNFS_BOOTP if (bootp_flag && !bootp_dev_count) { printk(KERN_ERR "Root-NFS: No suitable device for BOOTP found.\n"); bootp_flag = 0; }#else bootp_flag = 0;#endif#ifdef CONFIG_RNFS_RARP if (rarp_flag && !rarp_dev_count) { printk(KERN_ERR "Root-NFS: No suitable device for RARP found.\n"); rarp_flag = 0; }#else rarp_flag = 0;#endif if (!bootp_flag && !rarp_flag) /* Error message already printed */ return -1; /* * Setup RARP and BOOTP protocols */#ifdef CONFIG_RNFS_RARP if (rarp_flag) root_rarp_open();#endif#ifdef CONFIG_RNFS_BOOTP if (bootp_flag && root_bootp_open() < 0) { root_bootp_close(); return -1; }#endif /* * Send requests and wait, until we get an answer. This loop * seems to be a terrible waste of CPU time, but actually there is * only one process running at all, so we don't need to use any * scheduler functions. * [Actually we could now, but the nothing else running note still * applies.. - AC] */ printk(KERN_NOTICE "Sending %s%s%s requests...", bootp_flag ? "BOOTP" : "", bootp_flag && rarp_flag ? " and " : "", rarp_flag ? "RARP" : ""); start_jiffies = jiffies; retries = CONF_RETRIES; get_random_bytes(&timeout, sizeof(timeout)); timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM); for(;;) {#ifdef CONFIG_RNFS_BOOTP if (bootp_flag && root_bootp_send(jiffies - start_jiffies) < 0) { printk(" BOOTP failed!\n"); root_bootp_close(); bootp_flag = 0; if (!rarp_flag) break; }#endif#ifdef CONFIG_RNFS_RARP if (rarp_flag) root_rarp_send();#endif printk("."); jiff = jiffies + timeout; while (jiffies < jiff && !pkt_arrived)#ifdef CONFIG_RNFS_BOOTP root_bootp_recv();#else ;#endif if (pkt_arrived) break; if (! --retries) { printk(" timed out!\n"); break; } timeout = timeout CONF_TIMEOUT_MULT; if (timeout > CONF_TIMEOUT_MAX) timeout = CONF_TIMEOUT_MAX; }#ifdef CONFIG_RNFS_RARP if (rarp_flag) root_rarp_close();#endif#ifdef CONFIG_RNFS_BOOTP if (bootp_flag) root_bootp_close();#endif if (!pkt_arrived) return -1; printk(" OK\n"); printk(KERN_NOTICE "Root-NFS: Got %s answer from %s, ", (pkt_arrived == ARRIVED_BOOTP) ? "BOOTP" : "RARP", in_ntoa(server.sin_addr.s_addr)); printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr)); return 0;}#endif/*************************************************************************** Parsing of options ***************************************************************************//* * The following integer options are recognized */static struct nfs_int_opts { char *name; int *val;} root_int_opts[] = { { "port", &nfs_port }, { "rsize", &nfs_data.rsize }, { "wsize", &nfs_data.wsize }, { "timeo", &nfs_data.timeo }, { "retrans", &nfs_data.retrans }, { "acregmin", &nfs_data.acregmin }, { "acregmax", &nfs_data.acregmax }, { "acdirmin", &nfs_data.acdirmin }, { "acdirmax", &nfs_data.acdirmax }, { NULL, NULL }};/* * And now the flag options */static struct nfs_bool_opts { char *name; int and_mask; int or_mask;} root_bool_opts[] = { { "soft", ~NFS_MOUNT_SOFT, NFS_MOUNT_SOFT }, { "hard", ~NFS_MOUNT_SOFT, 0 }, { "intr", ~NFS_MOUNT_INTR, NFS_MOUNT_INTR }, { "nointr", ~NFS_MOUNT_INTR, 0 }, { "posix", ~NFS_MOUNT_POSIX, NFS_MOUNT_POSIX }, { "noposix", ~NFS_MOUNT_POSIX, 0 }, { "cto", ~NFS_MOUNT_NOCTO, 0 }, { "nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO }, { "ac", ~NFS_MOUNT_NOAC, 0 }, { "noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC }, { NULL, 0, 0 }};/* * Prepare the NFS data structure and parse any options. This tries to * set as many values in the nfs_data structure as known right now. */static int root_nfs_name(char *name){ char buf[NFS_MAXPATHLEN]; char *cp, *cq, *options, *val; int octets = 0; /* It is possible to override the server IP number here */ cp = cq = name; while (octets < 4) { while (*cp >= '0' && *cp <= '9') cp++; if (cp == cq || cp - cq > 3) break; if (*cp == '.' || octets == 3) octets++; if (octets < 4) cp++; cq = cp; } if (octets == 4 && (*cp == ':' || *cp == '\0')) { if (*cp == ':') *cp++ = '\0'; server.sin_addr.s_addr = in_aton(name); name = cp; } /* Clear the nfs_data structure and setup the server hostname */ memset(&nfs_data, 0, sizeof(nfs_data)); strncpy(nfs_data.hostname, in_ntoa(server.sin_addr.s_addr), sizeof(nfs_data.hostname)-1); /* Set the name of the directory to mount */ if (nfs_path[0] == '\0' || strncmp(name, "default", 7)) strncpy(buf, name, NFS_MAXPATHLEN); else strncpy(buf, nfs_path, NFS_MAXPATHLEN); if ((options = strchr(buf, ','))) *options++ = '\0'; if (!strcmp(buf, "default")) strcpy(buf, NFS_ROOT); cp = in_ntoa(myaddr.sin_addr.s_addr); if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); return -1; } /* update nfs_path with path from nfsroot=... command line parameter */ if (*buf) sprintf(nfs_path, buf, cp); /* Set some default values */ nfs_port = -1; nfs_data.version = NFS_MOUNT_VERSION; nfs_data.flags = 0; nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.timeo = 7; nfs_data.retrans = 3; nfs_data.acregmin = 3; nfs_data.acregmax = 60; nfs_data.acdirmin = 30; nfs_data.acdirmax = 60; /* Process any options */ if (options) { cp = strtok(options, ","); while (cp) { if ((val = strchr(cp, '='))) { struct nfs_int_opts *opts = root_int_opts; *val++ = '\0'; while (opts->name && strcmp(opts->name, cp)) opts++; if (opts->name) *(opts->val) = (int) simple_strtoul(val, NULL, 10); } else { struct nfs_bool_opts *opts = root_bool_opts; while (opts->name && strcmp(opts->name, cp)) opts++; if (opts->name) { nfs_data.flags &= opts->and_mask; nfs_data.flags |= opts->or_mask; } } cp = strtok(NULL, ","); } } return 0;}/* * Tell the user what's going on. */#ifdef NFSROOT_DEBUGstatic void root_nfs_print(void){#define IN_NTOA(x) (((x) == INADDR_NONE) ? "none" : in_ntoa(x)) printk(KERN_NOTICE "Root-NFS: IP config: dev=%s, ", root_dev ? root_dev->name : "none");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -