📄 netiucv.c
字号:
l = strlen(sbuf); p = sbuf; if (file->f_pos < l) { p += file->f_pos; l = strlen(p); ret = (count > l) ? l : count; if (copy_to_user(buf, p, ret)) return -EFAULT; } file->f_pos += ret; return ret;}static struct file_operations netiucv_stat_fops = { read: netiucv_stat_read, write: netiucv_stat_write, open: netiucv_stat_open, release: netiucv_stat_close,};static struct file_operations netiucv_buffer_fops = { read: netiucv_buffer_read, write: netiucv_buffer_write, open: netiucv_buffer_open, release: netiucv_buffer_close,};static struct file_operations netiucv_user_fops = { read: netiucv_user_read, write: netiucv_user_write, open: netiucv_user_open, release: netiucv_user_close,};static struct inode_operations netiucv_stat_iops = {#if LINUX_VERSION_CODE < 0x020363 default_file_ops: &netiucv_stat_fops#endif};static struct inode_operations netiucv_buffer_iops = {#if LINUX_VERSION_CODE < 0x020363 default_file_ops: &netiucv_buffer_fops#endif};static struct inode_operations netiucv_user_iops = {#if LINUX_VERSION_CODE < 0x020363 default_file_ops: &netiucv_user_fops#endif};static struct proc_dir_entry stat_entry = { 0, /* low_ino */ 10, /* namelen */ "statistics", /* name */ S_IFREG | S_IRUGO | S_IWUSR, /* mode */ 1, /* nlink */ 0, /* uid */ 0, /* gid */ 0, /* size */ &netiucv_stat_iops /* ops */};static struct proc_dir_entry buffer_entry = { 0, /* low_ino */ 10, /* namelen */ "buffersize", /* name */ S_IFREG | S_IRUSR | S_IWUSR, /* mode */ 1, /* nlink */ 0, /* uid */ 0, /* gid */ 0, /* size */ &netiucv_buffer_iops /* ops */};static struct proc_dir_entry user_entry = { 0, /* low_ino */ 8, /* namelen */ "username", /* name */ S_IFREG | S_IRUSR | S_IWUSR, /* mode */ 1, /* nlink */ 0, /* uid */ 0, /* gid */ 0, /* size */ &netiucv_user_iops /* ops */};#if LINUX_VERSION_CODE < 0x020363static struct proc_dir_entry netiucv_dir = { 0, /* low_ino */ 4, /* namelen */ "iucv", /* name */ S_IFDIR | S_IRUGO | S_IXUGO, /* mode */ 2, /* nlink */ 0, /* uid */ 0, /* gid */ 0, /* size */ 0, /* ops */ 0, /* get_info */ netiucv_fill_inode /* fill_ino (for locking) */};static struct proc_dir_entry netiucv_template ={ 0, /* low_ino */ 0, /* namelen */ "", /* name */ S_IFDIR | S_IRUGO | S_IXUGO, /* mode */ 2, /* nlink */ 0, /* uid */ 0, /* gid */ 0, /* size */ 0, /* ops */ 0, /* get_info */ netiucv_fill_inode /* fill_ino (for locking) */};#elsestatic struct proc_dir_entry *netiucv_dir = NULL;static struct proc_dir_entry *netiucv_template = NULL;#endif/** * Create the driver's main directory /proc/net/iucv */static voidnetiucv_proc_create_main(void){ /** * If not registered, register main proc dir-entry now */#if LINUX_VERSION_CODE > 0x020362 if (!netiucv_dir) netiucv_dir = proc_mkdir("iucv", proc_net);#else if (netiucv_dir.low_ino == 0) proc_net_register(&netiucv_dir);#endif}#ifdef MODULE/** * Destroy /proc/net/iucv */static voidnetiucv_proc_destroy_main(void){#if LINUX_VERSION_CODE > 0x020362 remove_proc_entry("iucv", proc_net);#else proc_net_unregister(netiucv_dir.low_ino);#endif}#endif MODULE/** * Create a device specific subdirectory in /proc/net/iucv/ with the * same name like the device. In that directory, create 3 entries * "statistics", "buffersize" and "username". * * @param dev The device for which the subdirectory should be created. * */static voidnetiucv_proc_create_sub(net_device *dev) { netiucv_priv *privptr = dev->priv;#if LINUX_VERSION_CODE > 0x020362 privptr->proc_dentry = proc_mkdir(dev->name, netiucv_dir); privptr->proc_stat_entry = create_proc_entry("statistics", S_IFREG | S_IRUSR | S_IWUSR, privptr->proc_dentry); privptr->proc_stat_entry->proc_fops = &netiucv_stat_fops; privptr->proc_stat_entry->proc_iops = &netiucv_stat_iops; privptr->proc_buffer_entry = create_proc_entry("buffersize", S_IFREG | S_IRUSR | S_IWUSR, privptr->proc_dentry); privptr->proc_buffer_entry->proc_fops = &netiucv_buffer_fops; privptr->proc_buffer_entry->proc_iops = &netiucv_buffer_iops; privptr->proc_user_entry = create_proc_entry("username", S_IFREG | S_IRUSR | S_IWUSR, privptr->proc_dentry); privptr->proc_user_entry->proc_fops = &netiucv_user_fops; privptr->proc_user_entry->proc_iops = &netiucv_user_iops;#else privptr->proc_dentry->name = dev->name; privptr->proc_dentry->namelen = strlen(dev->name); proc_register(&netiucv_dir, privptr->proc_dentry); proc_register(privptr->proc_dentry, privptr->proc_stat_entry); proc_register(privptr->proc_dentry, privptr->proc_buffer_entry); proc_register(privptr->proc_dentry, privptr->proc_user_entry);#endif privptr->proc_registered = 1;}/** * Destroy a device specific subdirectory. * * @param privptr Pointer to device private data. */static voidnetiucv_proc_destroy_sub(netiucv_priv *privptr) { if (!privptr->proc_registered) return;#if LINUX_VERSION_CODE > 0x020362 remove_proc_entry("statistics", privptr->proc_dentry); remove_proc_entry("buffersize", privptr->proc_dentry); remove_proc_entry("username", privptr->proc_dentry); remove_proc_entry(privptr->proc_dentry->name, netiucv_dir);#else proc_unregister(privptr->proc_dentry, privptr->proc_stat_entry->low_ino); proc_unregister(privptr->proc_dentry, privptr->proc_buffer_entry->low_ino); proc_unregister(privptr->proc_dentry, privptr->proc_user_entry->low_ino); proc_unregister(&netiucv_dir, privptr->proc_dentry->low_ino);#endif privptr->proc_registered = 0;}/** * Allocate and initialize a new connection structure. * Add it to the list of connections; */static iucv_connection *netiucv_new_connection(net_device *dev, char *username){ iucv_connection **clist = &connections; iucv_connection *conn = (iucv_connection *)kmalloc(sizeof(iucv_connection), GFP_KERNEL); if (conn) { memset(conn, 0, sizeof(iucv_connection)); skb_queue_head_init(&conn->collect_queue); conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; conn->netdev = dev; conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, GFP_DMA); if (!conn->rx_buff) { kfree(conn); return NULL; } conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, GFP_DMA); if (!conn->tx_buff) { kfree_skb(conn->rx_buff); kfree(conn); return NULL; } conn->fsm = init_fsm("netiucvconn", conn_state_names, conn_event_names, NR_CONN_STATES, NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, GFP_KERNEL); if (!conn->fsm) { kfree_skb(conn->tx_buff); kfree_skb(conn->rx_buff); kfree(conn); return NULL; } fsm_settimer(conn->fsm, &conn->timer); fsm_newstate(conn->fsm, CONN_STATE_INVALID); if (username) { memcpy(conn->userid, username, 9); fsm_newstate(conn->fsm, CONN_STATE_STOPPED); } conn->next = *clist; *clist = conn; } return conn;}/** * Release a connection structure and remove it from the * list of connections. */static voidnetiucv_remove_connection(iucv_connection *conn){ iucv_connection **clist = &connections; if (conn == NULL) return; while (*clist) { if (*clist == conn) { *clist = conn->next; if (conn->handle != 0) { iucv_unregister_program(conn->handle); conn->handle = 0; } fsm_deltimer(&conn->timer); kfree_fsm(conn->fsm); kfree_skb(conn->rx_buff); kfree_skb(conn->tx_buff); return; } clist = &((*clist)->next); }}/** * Allocate and initialize everything of a net device. */static net_device *netiucv_init_netdevice(int ifno, char *username){ netiucv_priv *privptr; int priv_size; net_device *dev = kmalloc(sizeof(net_device)#if LINUX_VERSION_CODE < 0x020300 + 11 /* name + zero */#endif , GFP_KERNEL); if (!dev) return NULL; memset(dev, 0, sizeof(net_device));#if LINUX_VERSION_CODE < 0x020300 dev->name = (char *)dev + sizeof(net_device);#endif sprintf(dev->name, "iucv%d", ifno); priv_size = sizeof(netiucv_priv) + sizeof(netiucv_template) + sizeof(stat_entry) + sizeof(buffer_entry) + sizeof(user_entry); dev->priv = kmalloc(priv_size, GFP_KERNEL); if (dev->priv == NULL) { kfree(dev); return NULL; } memset(dev->priv, 0, priv_size); privptr = (netiucv_priv *)dev->priv; privptr->proc_dentry = (struct proc_dir_entry *) (((char *)privptr) + sizeof(netiucv_priv)); privptr->proc_stat_entry = (struct proc_dir_entry *) (((char *)privptr) + sizeof(netiucv_priv) + sizeof(netiucv_template)); privptr->proc_buffer_entry = (struct proc_dir_entry *) (((char *)privptr) + sizeof(netiucv_priv) + sizeof(netiucv_template) + sizeof(stat_entry)); privptr->proc_user_entry = (struct proc_dir_entry *) (((char *)privptr) + sizeof(netiucv_priv) + sizeof(netiucv_template) + sizeof(stat_entry) + sizeof(buffer_entry)); memcpy(privptr->proc_dentry, &netiucv_template, sizeof(netiucv_template)); memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry)); memcpy(privptr->proc_buffer_entry, &buffer_entry, sizeof(buffer_entry)); memcpy(privptr->proc_user_entry, &user_entry, sizeof(user_entry)); privptr->fsm = init_fsm("netiucvdev", dev_state_names, dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, dev_fsm, DEV_FSM_LEN, GFP_KERNEL); if (privptr->fsm == NULL) { kfree(privptr); kfree(dev); return NULL; } privptr->conn = netiucv_new_connection(dev, username); if (!privptr->conn) { kfree_fsm(privptr->fsm); kfree(privptr); kfree(dev); return NULL; } fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); dev->mtu = NETIUCV_MTU_DEFAULT; dev->hard_start_xmit = netiucv_tx; dev->open = netiucv_open; dev->stop = netiucv_close; dev->get_stats = netiucv_stats; dev->change_mtu = netiucv_change_mtu; dev->hard_header_len = NETIUCV_HDRLEN; dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; dev_init_buffers(dev); dev->flags = IFF_POINTOPOINT | IFF_NOARP; return dev;}/** * Allocate and initialize everything of a net device. */static voidnetiucv_free_netdevice(net_device *dev){ netiucv_priv *privptr; if (!dev) return; privptr = (netiucv_priv *)dev->priv; if (privptr) { if (privptr->conn) netiucv_remove_connection(privptr->conn); if (privptr->fsm) kfree_fsm(privptr->fsm); netiucv_proc_destroy_sub(privptr); kfree(privptr); } kfree(dev);}static voidnetiucv_banner(void){ char vbuf[] = "$Revision: 1.16 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { char *p = strchr(version + 1, '$'); if (p) *p = '\0'; } else version = " ??? "; printk(KERN_INFO "NETIUCV driver Version%s initialized\n", version);}#ifndef MODULE# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))# define init_return(a) return astatic int __initiucv_setup(char *param)# else# define init_return(a) return__initfunc (void iucv_setup(char *param, int *ints))# endif{ /** * We do not parse parameters here because at the time of * calling iucv_setup(), the kernel does not yet have * memory management running. We delay this until probing * is called. */ iucv = param; init_return(1);}# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))__setup ("iucv=", iucv_setup);# endif#elsestatic voidnetiucv_exit(void){ while (connections) { net_device *dev = connections->netdev; unregister_netdev(dev); netiucv_free_netdevice(dev); } netiucv_proc_destroy_main(); printk(KERN_INFO "NETIUCV driver unloaded\n"); return;}#endifstatic intnetiucv_init(void){ char *p = iucv; int ifno = 0; int i = 0; char username[10]; netiucv_proc_create_main(); while (p) { if (isalnum(*p)) { username[i++] = *p++; username[i] = '\0'; if (i > 8) { printk(KERN_WARNING "netiucv: Invalid user name '%s'\n", username); while (*p && (*p != ':') && (*p != ',')) p++; } } else { if (*p && (*p != ':') && (*p != ',')) { printk(KERN_WARNING "netiucv: Invalid delimiter '%c'\n", *p); while (*p && (*p != ':') && (*p != ',')) p++; } else { if (i) { net_device *dev; while (i < 9) username[i++] = ' '; username[9] = '\0'; dev = netiucv_init_netdevice(ifno, username); if (!dev) printk(KERN_WARNING "netiucv: Could not allocate network device structure for user '%s'\n", netiucv_printname(username)); else { if (register_netdev(dev)) { printk(KERN_WARNING "netiucv: Could not register '%s'\n", dev->name); netiucv_free_netdevice(dev); } else { printk(KERN_INFO "%s: '%s'\n", dev->name, netiucv_printname(username)); netiucv_proc_create_sub(dev); ifno++; } } } if (!(*p)) break; i = 0; p++; } } } netiucv_banner(); return 0;}#ifdef MODULEmodule_init(netiucv_init);module_exit(netiucv_exit);#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))MODULE_LICENSE("GPL");#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -