netiucv.c
来自「linux 内核源代码」· C语言 代码 · 共 2,166 行 · 第 1/4 页
C
2,166 行
/* * IUCV network driver * * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Sysfs integration and all bugs therein by Cornelia Huck * (cornelia.huck@de.ibm.com) * * Documentation used: * the source of the original IUCV driver by: * Stefan Hegewald <hegewald@de.ibm.com> * Hartmut Penner <hpenner@de.ibm.com> * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 * * 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, 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#undef DEBUG#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/timer.h>#include <linux/bitops.h>#include <linux/signal.h>#include <linux/string.h>#include <linux/device.h>#include <linux/ip.h>#include <linux/if_arp.h>#include <linux/tcp.h>#include <linux/skbuff.h>#include <linux/ctype.h>#include <net/dst.h>#include <asm/io.h>#include <asm/uaccess.h>#include <net/iucv/iucv.h>#include "fsm.h"MODULE_AUTHOR ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");/** * Debug Facility stuff */#define IUCV_DBF_SETUP_NAME "iucv_setup"#define IUCV_DBF_SETUP_LEN 32#define IUCV_DBF_SETUP_PAGES 2#define IUCV_DBF_SETUP_NR_AREAS 1#define IUCV_DBF_SETUP_LEVEL 3#define IUCV_DBF_DATA_NAME "iucv_data"#define IUCV_DBF_DATA_LEN 128#define IUCV_DBF_DATA_PAGES 2#define IUCV_DBF_DATA_NR_AREAS 1#define IUCV_DBF_DATA_LEVEL 2#define IUCV_DBF_TRACE_NAME "iucv_trace"#define IUCV_DBF_TRACE_LEN 16#define IUCV_DBF_TRACE_PAGES 4#define IUCV_DBF_TRACE_NR_AREAS 1#define IUCV_DBF_TRACE_LEVEL 3#define IUCV_DBF_TEXT(name,level,text) \ do { \ debug_text_event(iucv_dbf_##name,level,text); \ } while (0)#define IUCV_DBF_HEX(name,level,addr,len) \ do { \ debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ } while (0)DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);#define IUCV_DBF_TEXT_(name,level,text...) \ do { \ char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ sprintf(iucv_dbf_txt_buf, text); \ debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ put_cpu_var(iucv_dbf_txt_buf); \ } while (0)#define IUCV_DBF_SPRINTF(name,level,text...) \ do { \ debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ debug_sprintf_event(iucv_dbf_trace, level, text ); \ } while (0)/** * some more debug stuff */#define IUCV_HEXDUMP16(importance,header,ptr) \PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ *(((char*)ptr)+12),*(((char*)ptr)+13), \ *(((char*)ptr)+14),*(((char*)ptr)+15)); \PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ *(((char*)ptr)+16),*(((char*)ptr)+17), \ *(((char*)ptr)+18),*(((char*)ptr)+19), \ *(((char*)ptr)+20),*(((char*)ptr)+21), \ *(((char*)ptr)+22),*(((char*)ptr)+23), \ *(((char*)ptr)+24),*(((char*)ptr)+25), \ *(((char*)ptr)+26),*(((char*)ptr)+27), \ *(((char*)ptr)+28),*(((char*)ptr)+29), \ *(((char*)ptr)+30),*(((char*)ptr)+31));#define PRINTK_HEADER " iucv: " /* for debugging */static struct device_driver netiucv_driver = { .name = "netiucv", .bus = &iucv_bus,};static int netiucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]);static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]);static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]);static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);static struct iucv_handler netiucv_handler = { .path_pending = netiucv_callback_connreq, .path_complete = netiucv_callback_connack, .path_severed = netiucv_callback_connrej, .path_quiesced = netiucv_callback_connsusp, .path_resumed = netiucv_callback_connres, .message_pending = netiucv_callback_rx, .message_complete = netiucv_callback_txdone};/** * Per connection profiling data */struct connection_profile { unsigned long maxmulti; unsigned long maxcqueue; unsigned long doios_single; unsigned long doios_multi; unsigned long txlen; unsigned long tx_time; struct timespec send_stamp; unsigned long tx_pending; unsigned long tx_max_pending;};/** * Representation of one iucv connection */struct iucv_connection { struct list_head list; struct iucv_path *path; struct sk_buff *rx_buff; struct sk_buff *tx_buff; struct sk_buff_head collect_queue; struct sk_buff_head commit_queue; spinlock_t collect_lock; int collect_len; int max_buffsize; fsm_timer timer; fsm_instance *fsm; struct net_device *netdev; struct connection_profile prof; char userid[9];};/** * Linked list of all connection structs. */static struct list_head iucv_connection_list = LIST_HEAD_INIT(iucv_connection_list);static DEFINE_RWLOCK(iucv_connection_rwlock);/** * Representation of event-data for the * connection state machine. */struct iucv_event { struct iucv_connection *conn; void *data;};/** * Private part of the network device structure */struct netiucv_priv { struct net_device_stats stats; unsigned long tbusy; fsm_instance *fsm; struct iucv_connection *conn; struct device *dev;};/** * Link level header for a packet. */struct ll_header { u16 next;};#define NETIUCV_HDRLEN (sizeof(struct ll_header))#define NETIUCV_BUFSIZE_MAX 32768#define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX#define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)#define NETIUCV_MTU_DEFAULT 9216#define NETIUCV_QUEUELEN_DEFAULT 50#define NETIUCV_TIMEOUT_5SEC 5000/** * Compatibility macros for busy handling * of network devices. */static inline void netiucv_clear_busy(struct net_device *dev){ struct netiucv_priv *priv = netdev_priv(dev); clear_bit(0, &priv->tbusy); netif_wake_queue(dev);}static inline int netiucv_test_and_set_busy(struct net_device *dev){ struct netiucv_priv *priv = netdev_priv(dev); netif_stop_queue(dev); return test_and_set_bit(0, &priv->tbusy);}static u8 iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40};/** * Convert an iucv userId to its printable * form (strip whitespace at end). * * @param An iucv userId * * @returns The printable string (static data!!) */static char *netiucv_printname(char *name){ static char tmp[9]; char *p = tmp; memcpy(tmp, name, 8); tmp[8] = '\0'; while (*p && (!isspace(*p))) p++; *p = '\0'; return tmp;}/** * States of the interface statemachine. */enum dev_states { DEV_STATE_STOPPED, DEV_STATE_STARTWAIT, DEV_STATE_STOPWAIT, DEV_STATE_RUNNING, /** * MUST be always the last element!! */ NR_DEV_STATES};static const char *dev_state_names[] = { "Stopped", "StartWait", "StopWait", "Running",};/** * Events of the interface statemachine. */enum dev_events { DEV_EVENT_START, DEV_EVENT_STOP, DEV_EVENT_CONUP, DEV_EVENT_CONDOWN, /** * MUST be always the last element!! */ NR_DEV_EVENTS};static const char *dev_event_names[] = { "Start", "Stop", "Connection up", "Connection down",};/** * Events of the connection statemachine */enum conn_events { /** * Events, representing callbacks from * lowlevel iucv layer) */ CONN_EVENT_CONN_REQ, CONN_EVENT_CONN_ACK, CONN_EVENT_CONN_REJ, CONN_EVENT_CONN_SUS, CONN_EVENT_CONN_RES, CONN_EVENT_RX, CONN_EVENT_TXDONE, /** * Events, representing errors return codes from * calls to lowlevel iucv layer */ /** * Event, representing timer expiry. */ CONN_EVENT_TIMER, /** * Events, representing commands from upper levels. */ CONN_EVENT_START, CONN_EVENT_STOP, /** * MUST be always the last element!! */ NR_CONN_EVENTS,};static const char *conn_event_names[] = { "Remote connection request", "Remote connection acknowledge", "Remote connection reject", "Connection suspended", "Connection resumed", "Data received", "Data sent", "Timer", "Start", "Stop",};/** * States of the connection statemachine. */enum conn_states { /** * Connection not assigned to any device, * initial state, invalid */ CONN_STATE_INVALID, /** * Userid assigned but not operating */ CONN_STATE_STOPPED, /** * Connection registered, * no connection request sent yet, * no connection request received */ CONN_STATE_STARTWAIT, /** * Connection registered and connection request sent, * no acknowledge and no connection request received yet. */ CONN_STATE_SETUPWAIT, /** * Connection up and running idle */ CONN_STATE_IDLE, /** * Data sent, awaiting CONN_EVENT_TXDONE */ CONN_STATE_TX, /** * Error during registration. */ CONN_STATE_REGERR, /** * Error during registration. */ CONN_STATE_CONNERR, /** * MUST be always the last element!! */ NR_CONN_STATES,};static const char *conn_state_names[] = { "Invalid", "Stopped", "StartWait", "SetupWait", "Idle", "TX", "Terminating", "Registration error", "Connect error",};/** * Debug Facility Stuff */static debug_info_t *iucv_dbf_setup = NULL;static debug_info_t *iucv_dbf_data = NULL;static debug_info_t *iucv_dbf_trace = NULL;DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);static void iucv_unregister_dbf_views(void){ if (iucv_dbf_setup) debug_unregister(iucv_dbf_setup); if (iucv_dbf_data) debug_unregister(iucv_dbf_data); if (iucv_dbf_trace) debug_unregister(iucv_dbf_trace);}static int iucv_register_dbf_views(void){ iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, IUCV_DBF_SETUP_PAGES, IUCV_DBF_SETUP_NR_AREAS, IUCV_DBF_SETUP_LEN); iucv_dbf_data = debug_register(IUCV_DBF_DATA_NAME, IUCV_DBF_DATA_PAGES, IUCV_DBF_DATA_NR_AREAS, IUCV_DBF_DATA_LEN); iucv_dbf_trace = debug_register(IUCV_DBF_TRACE_NAME, IUCV_DBF_TRACE_PAGES, IUCV_DBF_TRACE_NR_AREAS, IUCV_DBF_TRACE_LEN); if ((iucv_dbf_setup == NULL) || (iucv_dbf_data == NULL) || (iucv_dbf_trace == NULL)) { iucv_unregister_dbf_views(); return -ENOMEM; } debug_register_view(iucv_dbf_setup, &debug_hex_ascii_view); debug_set_level(iucv_dbf_setup, IUCV_DBF_SETUP_LEVEL); debug_register_view(iucv_dbf_data, &debug_hex_ascii_view); debug_set_level(iucv_dbf_data, IUCV_DBF_DATA_LEVEL); debug_register_view(iucv_dbf_trace, &debug_hex_ascii_view); debug_set_level(iucv_dbf_trace, IUCV_DBF_TRACE_LEVEL); return 0;}/* * Callback-wrappers, called from lowlevel iucv layer. */static void netiucv_callback_rx(struct iucv_path *path, struct iucv_message *msg){ struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_RX, &ev);}static void netiucv_callback_txdone(struct iucv_path *path, struct iucv_message *msg){ struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);}static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]){ struct iucv_connection *conn = path->private; fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn);}static int netiucv_callback_connreq(struct iucv_path *path, u8 ipvmid[8], u8 ipuser[16]){ struct iucv_connection *conn = path->private; struct iucv_event ev; int rc; if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) /* ipuser must match iucvMagic. */ return -EINVAL; rc = -EINVAL; read_lock_bh(&iucv_connection_rwlock); list_for_each_entry(conn, &iucv_connection_list, list) { if (strncmp(ipvmid, conn->userid, 8)) continue;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?