📄 iscsi-network-boot.c
字号:
/* * iSCSI driver for Linux * Copyright (C) 2002 Cisco Systems, Inc. * maintained by linux-iscsi-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * $Id: iscsi-network-boot.c,v 1.17 2005/02/14 09:14:02 smithan Exp $ * */#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <sys/stat.h>#include <net/route.h>#include "iscsi-sfnet.h"#include "iscsi-ioctl.h"#include "iscsid.h"#include "iscsi-login.h"#include "iscsi-network-boot.h"#define ISCSI_DEVICE "/dev/iscsictl"#define NETDEV_BOOT_SETUP_MAX 8static int control_fd = -1;static char inbp_interface_name[IFNAMSIZ];static intopen_control_device(void){ FILE *f = NULL; char devname[256], buf[256]; int devn, ctlfd; /* * Establish the control path to the driver */ f = fopen("/proc/devices", "r"); if (!f) { perror("Cannot open control path to the driver"); return -1; } devn = 0; while (!feof(f)) { if (!fgets(buf, sizeof (buf), f)) { break; } if (sscanf(buf, "%d %s", &devn, devname) != 2) { continue; } if (!strcmp(devname, "iscsictl")) { break; } devn = 0; } fclose(f); if (!devn) { printf ("cannot find iscsictl in /proc/devices - make " "sure the module is loaded"); return -1; } unlink(ISCSI_DEVICE); if (mknod(ISCSI_DEVICE, (S_IFCHR | 0600), (devn << 8))) { printf("cannot create %s ", ISCSI_DEVICE); return -1; } ctlfd = open(ISCSI_DEVICE, O_RDWR); if (ctlfd < 0) { printf("cannot open %s", ISCSI_DEVICE); return -1; } return ctlfd;}static char *get_initiatorname(char *pathname){ FILE *f = NULL; int c; char *line, buffer[1024], *name = NULL; if (!pathname) { printf("No pathname to load InitiatorName from"); return NULL; } /* get the InitiatorName */ if ((f = fopen(pathname, "r"))) { while ((line = fgets(buffer, sizeof (buffer), f))) { while (line && isspace(c = *line)) line++; if (strncmp(line, "InitiatorName=", 14) == 0) { char *end = line + 14; /* the name is everything up to the first bit * of whitespace */ while (*end && (!isspace(c = *end))) end++; if (isspace(c = *end)) *end = '\0'; if (end > line + 14) name = strdup(line + 14); } } fclose(f); if (!name) { printf ("an InitiatorName is required, but was not " "found in %s", pathname); return NULL; } else { printf("InitiatorName=%s\n", name); } return name; } else { printf("cannot open InitiatorName configuration file %s", pathname); return NULL; }}/* * Assumptions for network boot: * 1. Only one portal available which comes from nbp structure * 2. No authentication is used. * 3. Digest values are not configurable on initiator side, user can set it on * target if required. * 4. Tag is always 1, as there is no value in nbp specifying portal tag. * 5. Initiator name for boot and normal sessions will be different(FIXME). *//* Returns 0 on success, non zero on failure */static intioctl_establish_session(struct sapiNBP *nbp){ int rc, ret = 0; struct iscsi_session_ioctl *ioctld = NULL; struct sockaddr_in *addr; /* allocate an ioctl structure with enough space * for all of the portal info */ ioctld = calloc(1, sizeof (*ioctld) + sizeof (struct iscsi_portal_info)); if (ioctld == NULL) { printf("failed to allocate %d bytes for ioctl data structure", sizeof (*ioctld) + sizeof (struct iscsi_portal_info)); return 1; } ioctld->ioctl_version = ISCSI_SESSION_IOCTL_VERSION; ioctld->config_number = 1; ioctld->update = 0; ioctld->portal.login_timeout = 15; ioctld->portal.auth_timeout = 45; ioctld->portal.active_timeout = 5; ioctld->portal.idle_timeout = 60; ioctld->portal.ping_timeout = 5; ioctld->portal.replacement_timeout = 0; ioctld->portal.abort_timeout = 10; ioctld->portal.reset_timeout = 30; ioctld->portal.initial_r2t = 0; ioctld->portal.immediate_data = 0; ioctld->portal.max_recv_data_segment_len = 128 * 1024; ioctld->portal.first_burst_len = 256 * 1024; ioctld->portal.max_burst_len = (16 * 1024 * 1024) - 1024; ioctld->portal.def_time2wait = 0; ioctld->portal.def_time2retain = 0; ioctld->portal.data_digest = ISCSI_DIGEST_NONE_CRC32C; ioctld->portal.header_digest = ISCSI_DIGEST_NONE_CRC32C; ioctld->portal.tcp_window_size = 256 * 1024; addr = (struct sockaddr_in *)&ioctld->portal.addr; addr->sin_family = AF_INET; memcpy(&addr->sin_addr.s_addr, (char *)(&nbp->targetipaddr), sizeof(nbp->targetipaddr)); addr->sin_port = htons(nbp->tcpport); ioctld->portal.tag = PORTAL_GROUP_TAG_UNKNOWN; ioctld->password_length = 0; ioctld->password_length_in = 0; printf("authentication not configured for target"); strcpy(ioctld->initiator_name, get_initiatorname("/etc/initiatorname.iscsi")); strcpy(ioctld->target_name, nbp->targetstring); ioctld->isid[0] = DRIVER_ISID_0; ioctld->isid[1] = DRIVER_ISID_1; ioctld->isid[2] = DRIVER_ISID_2; ioctld->isid[3] = 0; ioctld->isid[4] = 0; ioctld->isid[5] = 1; /* * Tell the kernel to establish a session. */ do { rc = ioctl(control_fd, ISCSI_ESTABLISH_SESSION, (char *) ioctld); if (rc < 0) { printf("iSCSI session ioctl failed for %s, errno = %d", nbp->targetstring, errno); printf ("\nRetrying session establishment with " "the boot disk ...\n"); sleep(2); } else { printf ("iSCSI session ioctl for %s returned from " "kernel with rc %d", nbp->targetstring, rc); } } while (rc < 0); memset(&ioctld, 0, sizeof (ioctld)); return ret;}static intfind_pxe_sig(char *buf, int iter, struct sapiNBP *nbp){ int len, i = 0; char *p = buf, *sig = SIGNATURE; len = strlen(sig); while (INBP_BUF_SIZE - i >= len) { if (strncmp(p, sig, len) == 0) { printf("\nGot the signature at 0x%x\n", iter * INBP_BUF_SIZE + i); memcpy(nbp, p, sizeof (struct sapiNBP)); printf("targetname: %s\n\n", nbp->targetstring); return 1; } p++; i++; } return 0;}voidget_inbp_info(struct sapiNBP *nbp){ int fd, i = 0; char buf[1024]; if ((fd = open("/dev/mem", O_RDONLY)) < 0) { perror("open mem"); return; } while (i < SCANAREA) { if (read(fd, buf, INBP_BUF_SIZE) < 0) { printf("Read error at 0x%x\n", i * INBP_BUF_SIZE); perror("read"); return; } i++; /* printf("Reading %dk area..\n", i); */ if (find_pxe_sig(buf, i, nbp)) break; } if (i > SCANAREA) { printf("\n%s not found, iscsi boot will fail !!!\n", SIGNATURE); sleep(10); }}/* Returns 0 on success, non zero on error */static intiscsi_add_route(struct sapiNBP *nbp){ struct rtentry rt; struct sockaddr_in *dst = (struct sockaddr_in *) &rt.rt_dst; struct sockaddr_in *gw = (struct sockaddr_in *) &rt.rt_gateway; char dev[IFNAMSIZ], ip[16]; int ret, fd; memset((char *) &rt, 0, sizeof (struct rtentry)); memset(ip, 0, 16); memset(dev, 0, IFNAMSIZ); dst->sin_family = AF_INET; dst->sin_addr.s_addr = INADDR_ANY; strcpy(ip, (char *) (&nbp->ripaddr)); strcpy(dev, inbp_interface_name); gw->sin_family = AF_INET; memcpy(&gw->sin_addr.s_addr, ip, 4); rt.rt_flags = (RTF_UP | RTF_GATEWAY); rt.rt_dev = dev; fd = socket(AF_INET,SOCK_STREAM,0); if (fd == -1) { printf("\nFailed to create socket with errno %d\n", errno); return 1; } ret = ioctl(fd, SIOCADDRT, &rt); if(ret != 0) printf("iSCSI: error in setting the route, ioctl returned " "with value: %d\n", ret); return ret;}/* Returns 1 on success 0 on failure */static intiscsi_set_if_addr(struct sapiNBP *nbp){ struct ifreq ifr; struct sockaddr sa; struct sockaddr_in *sin = (struct sockaddr_in *) &sa; int dev_ret = 0, fd; memset(&ifr, 0, sizeof (struct ifreq)); memset(&sa, 0, sizeof (struct sockaddr)); if (nbp->myipaddr != 0) { memcpy(&sin->sin_addr, (char *)&nbp->myipaddr, 4); } else { printf("\nERROR !!! Not setting ip from inbp !!!\n"); return 0; } if (inbp_interface_name != NULL) { strcpy(ifr.ifr_name, inbp_interface_name); } else { printf("\nERROR !!! Not setting interface from inbp !!!\n"); return 0; } fd = socket(AF_INET,SOCK_STREAM,0); if (fd == -1) { printf("\nFailed to create socket with errno %d\n", errno); return 0; } /* Check if the interface is already up or not */ if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) { if ((ifr.ifr_flags & IFF_UP) != 0) { printf ("\nInterface %s has IFF_UP flag already set\n", ifr.ifr_name); return 1; } } else { printf ("\niSCSI: ERROR in getting interface FLAGS for " "interface %s\n", ifr.ifr_name); return 0; } memset(&ifr, 0, sizeof (struct ifreq)); strcpy(ifr.ifr_name, inbp_interface_name); sin->sin_family = AF_INET; sin->sin_port = 0; memcpy(&ifr.ifr_addr, &sa, sizeof (struct sockaddr)); if ((dev_ret = ioctl(fd, SIOCSIFADDR, (void *) &ifr)) != 0) { printf ("\niSCSI: ERROR in setting ip address for interface %s\n", ifr.ifr_name); return 0; } memset(&ifr, 0, sizeof (struct ifreq)); if (inbp_interface_name != NULL) { strcpy(ifr.ifr_name, inbp_interface_name); } else { printf("\nERROR !!! Not setting interface from inbp !!!\n"); return 0; } ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST; if ((dev_ret = ioctl(fd, SIOCSIFFLAGS, (void *) &ifr)) != 0) { printf("\niSCSI: ERROR in setting flags for interface %s\n", ifr.ifr_name); return 0; } memset(&ifr, 0, sizeof (struct ifreq)); strcpy(ifr.ifr_name, inbp_interface_name); memcpy(&sin->sin_addr, &nbp->myipmask, 4); memcpy(&ifr.ifr_netmask, &sa, sizeof (struct sockaddr)); if ((dev_ret = ioctl(fd, SIOCSIFNETMASK, (void *) &ifr)) != 0) { printf ("\niSCSI: ERROR in setting network mask " "for interface %s\n", ifr.ifr_name); return 0; } while (iscsi_add_route(nbp)) { printf("\niSCSI: iscsi_set_if_addr: iscsi_add_route failed\n"); sleep(2); } return 1;}/* Return 1 on sucess, 0 on error.*/intbring_up_network(struct sapiNBP *nbp){ int fd, tmp_index; struct ifreq req; fd = socket(AF_INET,SOCK_STREAM,0); if (fd == -1) { printf("/n failed to create socket with errno %d\n", errno); return 0; } for (tmp_index = 1; tmp_index < NETDEV_BOOT_SETUP_MAX; tmp_index++) { memset(&req,0,sizeof(req)); req.ifr_ifindex = tmp_index; if (ioctl(fd, SIOCGIFNAME, &req) < 0) { printf("iSCSI: error in getting interface name\n"); return 0; } req.ifr_ifindex = 0; if (ioctl(fd, SIOCGIFHWADDR, &req) < 0) { printf("iSCSI: error in getting hardware address\n"); return 0; } if (!memcmp(nbp->myethaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN)){ strcpy(inbp_interface_name, req.ifr_name); break; } } while(!iscsi_set_if_addr(nbp)) { printf("\niSCSI: iscsi_set_if_addr failed\n"); } return 1;}voidestablish_iscsi_network_boot_session(struct sapiNBP *nbp){ int rv = 0; /* ensure the control device exists, and open it for all of * the child processes to use */ for (;;) { control_fd = open_control_device(); if (control_fd >= 0) break; printf ("could not open control device %s. Make sure " "iscsi is loaded", ISCSI_DEVICE); sleep(5); } do { rv = ioctl_establish_session(nbp); if (rv != 0) { printf("ISCSI_ESTABLISH_SESSION ioctl for %s failed, " "returned from kernel with rv %d", nbp->targetstring, rv); } } while (rv != 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -