⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iscsi_init.c

📁 iscsi-init LINUX boot
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * iSCSI boot initialization module for Linux * maintained by Igor Feoktistov <ifeoktistov@users.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. * */#define __KERNEL_SYSCALLS__#include <linux/config.h>#include <linux/init.h>#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ctype.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/file.h>#include <linux/jiffies.h>#include <linux/random.h>#include <linux/unistd.h>#include <linux/utsname.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/udp.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <net/ip.h>#include <asm/uaccess.h>#include <asm/checksum.h>#include "iscsi_init.h"static char __initdata *version = "4.0.2.1 (March 30, 2005)";static spinlock_t bootp_recv_lock = SPIN_LOCK_UNLOCKED;static struct iscsi_device *iscsi_device_list __initdata = NULL;static struct iscsi_target *iscsi_target_list __initdata = NULL;static struct iscsi_interface *iscsi_interface_list __initdata = NULL;static char *cmdline __initdata = NULL;static char *iscsi_initiator __initdata = NULL;static char *iscsi_timeout __initdata = NULL;static char *iscsi_config_page __initdata = NULL;static char pnp_domain[64];static u32 pnp_nameservers[CONF_NAMESERVERS_MAX];static char __initdata *iscsi_param_set[] ={    ISCSI_CFG_USERNAME,    ISCSI_CFG_PASSWORD,    ISCSI_CFG_INCOMINGUSERNAME,    ISCSI_CFG_INCOMINGPASSWORD,    ISCSI_CFG_OUTGOINGUSERNAME,    ISCSI_CFG_OUTGOINGPASSWORD,    ISCSI_CFG_HEADERDIGEST,    ISCSI_CFG_DATADIGEST,    ISCSI_CFG_LOGINTIMEOUT,    ISCSI_CFG_AUTHTIMEOUT,    ISCSI_CFG_IDLETIMEOUT,    ISCSI_CFG_CONNFAILTIMEOUT,    ISCSI_CFG_PINGTIMEOUT,    ISCSI_CFG_INITIALR2T,    ISCSI_CFG_IMMEDIATEDATA,    ISCSI_CFG_MAXRECVDATASEGLEN,    ISCSI_CFG_FIRSTBURSTLENGTH,    ISCSI_CFG_MAXFURSTLENGTH,    ISCSI_CFG_TCPWINSIZE,    NULL};static struct iscsi_param __initdata *iscsi_param_list = NULL;int errno __initdata = 0;static inline _syscall1(long, unlink, const char*, path);static inline _syscall3(long, ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg);static inline _syscall3(long, mknod, const char*, name, int, mode, dev_t, dev);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)static inline _syscall3(int, open, const char*, file, int, flag, int, mode);static inline _syscall1(int, close, int, fd);static inline _syscall3(int, read, int, fd, char*, buf, off_t, count);#endifstatic int __init iscsi_open_devs(struct iscsi_interface *iscsi_if){    struct iscsi_device *d, *d2;    struct net_device *dev;    unsigned short oflags;    rtnl_shlock();    for (dev = dev_base; dev; dev = dev->next) {	if (iscsi_if->if_name ? !strcmp(dev->name, iscsi_if->if_name) :	    (!(dev->flags & IFF_LOOPBACK) &&	    (dev->flags & (IFF_POINTOPOINT | IFF_BROADCAST)) &&	    strncmp(dev->name, "dummy", 5))) {	    if (dev->mtu < 364)		continue;	    oflags = dev->flags;	    if (dev_change_flags(dev, oflags | IFF_UP) < 0) {		printk(KERN_ERR "iSCSI-init(iscsi_open_devs): failed to open %s\n", dev->name);		continue;	    }	    if ((d = kmalloc(sizeof(struct iscsi_device), GFP_KERNEL))) {		d->next = NULL;		d->dev = dev;		d->flags = oflags;		get_random_bytes(&d->xid, sizeof(u32));		d->iscsi_if = iscsi_if;		if (iscsi_device_list) {		    for (d2 = iscsi_device_list; d2; d2 = d2->next) {			if (d2->next == NULL) {			    d2->next = d;			    break;			}		    }		}		else		    iscsi_device_list = d;	    }	    else		printk(KERN_ERR "iSCSI-init(iscsi_open_devs): memory allocation error\n");	}    }    rtnl_shunlock();    if (!iscsi_device_list) {        printk(KERN_ERR "iSCSI-init(iscsi_open_devs): no network devices available.\n");	return -1;    }    return 0;}static void __init iscsi_close_devs(struct iscsi_interface *iscsi_if){    struct iscsi_device *d, *next;    struct net_device *dev;    rtnl_shlock();    for (d = iscsi_device_list; d; d = next) {	dev = d->dev;	if (dev != d->iscsi_if->dev)	    dev_change_flags(dev, d->flags);	next = d->next;	kfree(d);    }    rtnl_shunlock();    iscsi_device_list = NULL;}/* *	Interface to various network functions. */static inline void set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port){    sin->sin_family = AF_INET;    sin->sin_addr.s_addr = addr;    sin->sin_port = port;}static int __init iscsi_dev_ioctl(unsigned int cmd, struct ifreq *arg){    int res;    mm_segment_t oldfs = get_fs();    set_fs(get_ds());    res = devinet_ioctl(cmd, arg);    set_fs(oldfs);    return res;}static int __init iscsi_route_ioctl(unsigned int cmd, struct rtentry *arg){    int res;    mm_segment_t oldfs = get_fs();    set_fs(get_ds());    res = ip_rt_ioctl(cmd, arg);    set_fs(oldfs);    return res;}/* *	Set up interface addresses and routes. */static int __init iscsi_setup_if(struct iscsi_interface *iscsi_if){    struct ifreq ir;    struct sockaddr_in *sin = (void*) &ir.ifr_ifru.ifru_addr;    int err;    memset(&ir, 0, sizeof(ir));    strcpy(ir.ifr_ifrn.ifrn_name, iscsi_if->dev->name);    set_sockaddr(sin, iscsi_if->if_addr, 0);    if ((err = iscsi_dev_ioctl(SIOCSIFADDR, &ir)) < 0) {	printk(KERN_ERR "iSCSI-init(iscsi_setup_if): unable to set interface address (%d).\n", err);	return -1;    }    if (iscsi_if->if_netmask == INADDR_NONE) {	if (IN_CLASSA(ntohl(iscsi_if->if_addr)))	    iscsi_if->if_netmask = htonl(IN_CLASSA_NET);	else	if (IN_CLASSB(ntohl(iscsi_if->if_addr)))	    iscsi_if->if_netmask = htonl(IN_CLASSB_NET);	else	if (IN_CLASSC(ntohl(iscsi_if->if_addr)))	    iscsi_if->if_netmask = htonl(IN_CLASSC_NET);	else	    printk(KERN_ERR "iSCSI-init(iscsi_setup_if): unable to guess netmask for address %u.%u.%u.%u\n", NIPQUAD(iscsi_if->if_addr));	if (iscsi_if->if_netmask != INADDR_NONE)	    printk("iSCSI-init: guessing netmask %u.%u.%u.%u\n", NIPQUAD(iscsi_if->if_netmask));    }    set_sockaddr(sin, iscsi_if->if_netmask, 0);    if ((err = iscsi_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) {	printk(KERN_ERR "iSCSI-init(iscsi_setup_if): unable to set interface netmask (%d).\n", err);	return -1;    }    set_sockaddr(sin, iscsi_if->if_addr | ~(iscsi_if->if_netmask), 0);    if ((err = iscsi_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) {	printk(KERN_ERR "iSCSI-init(iscsi_setup_if): unable to set interface broadcast address (%d).\n", err);	return -1;    }    return 0;}static int __init iscsi_setup_routes(struct iscsi_interface *iscsi_if, u32 dst){    /* No need to setup device routes, only the default route... */    struct rtentry rm;    int err;    memset(&rm, 0, sizeof(rm));    if ((iscsi_if->gateway ^ iscsi_if->if_addr) & iscsi_if->if_netmask) {	printk(KERN_ERR "iSCSI-init(iscsi_setup_routes): gateway not on directly connected network.\n");	iscsi_if->gateway = INADDR_NONE;	return -1;    }    set_sockaddr((struct sockaddr_in *) &rm.rt_dst, dst, 0);    set_sockaddr((struct sockaddr_in *) &rm.rt_genmask, 0, 0);    set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, iscsi_if->gateway, 0);    rm.rt_flags = RTF_UP | RTF_GATEWAY;    if (dst > 0) {	if (!((dst ^ iscsi_if->if_addr) & iscsi_if->if_netmask))	    return 0;	rm.rt_dev = iscsi_if->dev->name;	rm.rt_flags |= RTF_HOST;    }    if ((err = iscsi_route_ioctl(SIOCADDRT, &rm)) < 0) {	if (err != -EEXIST)	    printk(KERN_ERR "iSCSI-init(iscsi_setup_routes): cannot add default route (%d).\n", err);        return -1;    }    return 0;}/* *	DHCP/BOOTP support. */struct bootp_pkt {	/* BOOTP packet format */    struct iphdr iph;	/* IP header */    struct udphdr udph;	/* UDP header */    u8 op;		/* 1=request, 2=reply */    u8 htype;		/* HW address type */    u8 hlen;		/* HW address length */    u8 hops;		/* Used only by gateways */    u32 xid;		/* Transaction ID */    u16 secs;		/* Seconds since we started */    u16 flags;		/* Just what it says */    u32 client_ip;	/* Client's IP address if known */    u32 your_ip;	/* Assigned IP address */    u32 server_ip;	/* (Next, e.g. NFS) Server's IP address */    u32 relay_ip;	/* IP address of BOOTP relay */    u8 hw_addr[16];	/* Client's HW address */    u8 serv_name[64];	/* Server host name */    u8 boot_file[128];	/* Name of boot file */    u8 exten[312];	/* DHCP options / BOOTP vendor extensions */};/* packet ops */#define BOOTP_REQUEST	1#define BOOTP_REPLY	2/* DHCP message types */#define DHCPDISCOVER	1#define DHCPOFFER	2#define DHCPREQUEST	3#define DHCPDECLINE	4#define DHCPACK		5#define DHCPNAK		6#define DHCPRELEASE	7#define DHCPINFORM	8static int iscsi_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt);static struct packet_type bootp_packet_type = {    type:	__constant_htons(ETH_P_IP),    func:	iscsi_bootp_recv,};/* *  Initialize DHCP/BOOTP extension fields in the request. */static const u8 iscsi_bootp_cookie[4] = { 99, 130, 83, 99 };static void __init iscsi_dhcp_init_options(u8 *options, struct iscsi_interface *iscsi_if){    u8 mt = ((iscsi_if->servaddr == INADDR_NONE) ? DHCPDISCOVER : DHCPREQUEST);    u8 *e = options;    memcpy(e, iscsi_bootp_cookie, 4);	/* RFC1048 Magic Cookie */    e += 4;    *e++ = 53;				/* DHCP message type */    *e++ = 1;    *e++ = mt;    if (mt == DHCPREQUEST) {	*e++ = 54;			/* Server ID (IP address) */	*e++ = 4;	memcpy(e, &(iscsi_if->servaddr), 4);	e += 4;	*e++ = 50;			/* Requested IP address */	*e++ = 4;	memcpy(e, &(iscsi_if->if_addr), 4);	e += 4;    }    {	static const u8 iscsi_req_params[] = {	    1,	/* Subnet mask */    	    3,	/* Default gateway */	    6,	/* DNS server */	    12,	/* Host name */	    15,	/* Domain name */	    17,	/* Boot path */	    40,	/* NIS domain name */	};	*e++ = 55;	/* Parameter request list */	*e++ = sizeof(iscsi_req_params);	memcpy(e, iscsi_req_params, sizeof(iscsi_req_params));	e += sizeof(iscsi_req_params);    }    *e++ = 255;	/* End of the list */}/* *  Initialize the DHCP/BOOTP mechanism. */static inline void iscsi_bootp_init(void){    dev_add_pack(&bootp_packet_type);}/* *  DHCP/BOOTP cleanup. */static inline void iscsi_bootp_cleanup(void){    dev_remove_pack(&bootp_packet_type);}/* *  Send DHCP/BOOTP request to single interface. */static void __init iscsi_bootp_send_if(struct iscsi_device *d, unsigned long jiffies_diff){    struct net_device *dev = d->dev;    struct sk_buff *skb;    struct bootp_pkt *b;    int hh_len = LL_RESERVED_SPACE(dev);    struct iphdr *h;    /* Allocate packet */    skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);    if (!skb)	return;    skb_reserve(skb, hh_len);    b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));    memset(b, 0, sizeof(struct bootp_pkt));    /* Construct IP header */    skb->nh.iph = h = &b->iph;    h->version = 4;    h->ihl = 5;    h->tot_len = htons(sizeof(struct bootp_pkt));    h->frag_off = htons(IP_DF);    h->ttl = 64;    h->protocol = IPPROTO_UDP;    h->daddr = INADDR_BROADCAST;    h->check = ip_fast_csum((unsigned char *) h, h->ihl);    /* Construct UDP header */    b->udph.source = htons(68);    b->udph.dest = htons(67);    b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));    /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */    /* Construct DHCP/BOOTP header */    b->op = BOOTP_REQUEST;    if (dev->type < 256) /* check for false types */	b->htype = dev->type;    else if (dev->type == ARPHRD_IEEE802_TR) /* fix for token ring */	b->htype = ARPHRD_IEEE802;    else {	printk(KERN_ERR "iSCSI-init(iscsi_bootp_send_if): unknown ARP type 0x%04x for device %s\n", dev->type, dev->name);	b->htype = dev->type; /* can cause undefined behavior */    }    b->hlen = dev->addr_len;    b->your_ip = INADDR_NONE;    b->server_ip = INADDR_NONE;    memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);    b->secs = htons(jiffies_diff / HZ);    b->xid = d->xid;    /* add DHCP options or BOOTP extensions */    iscsi_dhcp_init_options(b->exten, d->iscsi_if);    /* Chain packet down the line... */    skb->dev = dev;    skb->protocol = htons(ETH_P_IP);    if ((dev->hard_header &&	dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||	dev_queue_xmit(skb) < 0)	printk("E");}/* *  Copy BOOTP-supplied string if not already set. */static int __init iscsi_bootp_string(char *dest, char *src, int len, int max){    if (!len)	return 0;    if (len > max - 1)	len = max - 1;    memcpy(dest, src, len);    dest[len] = '\0';    return 1;}/* *  Process BOOTP extensions. */static void __init iscsi_do_bootp_ext(u8 *ext, struct iscsi_interface *iscsi_if){    u8 servers;    int i;    switch (*ext++) {	case 1:		/* Subnet mask */	    if (iscsi_if->if_netmask == INADDR_NONE)		memcpy(&(iscsi_if->if_netmask), ext + 1, 4);		break;	case 3:		/* Default gateway */	    if (iscsi_if->gateway == INADDR_NONE)		memcpy(&(iscsi_if->gateway), ext + 1, 4);		break;	case 6:		/* DNS server */		servers = *ext/4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -