📄 netiucv.c
字号:
/* * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $ * * IUCV network driver * * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Driverfs integration and all bugs therein by Cornelia Huck(cohuck@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. * * RELEASE-TAG: IUCV network driver $Revision: 1.66 $ * */#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/sched.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 "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");#define PRINTK_HEADER " iucv: " /* for debugging */static struct device_driver netiucv_driver = { .name = "netiucv", .bus = &iucv_bus,};/** * 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 iucv_connection *next; iucv_handle_t handle; __u16 pathid; 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 iucv_connection *iucv_connections;/** * 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. */typedef struct ll_header_t { __u16 next;} ll_header;#define NETIUCV_HDRLEN (sizeof(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){ clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); netif_wake_queue(dev);}static __inline__ int netiucv_test_and_set_busy(struct net_device *dev){ netif_stop_queue(dev); return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy);}static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };static __u8 iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40};/** * This mask means the 16-byte IUCV "magic" and the origin userid must * match exactly as specified in order to give connection_pending() * control. */static __u8 netiucv_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};/** * Convert an iucv userId to its printable * form (strip whitespace at end). * * @param An iucv userId * * @returns The printable string (static data!!) */static __inline__ 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 voidiucv_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 intiucv_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 voidnetiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_RX, &ev);}static voidnetiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);}static voidnetiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev);}static voidnetiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);}static voidnetiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev);}static voidnetiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev);}static voidnetiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data){ struct iucv_connection *conn = (struct iucv_connection *)pgm_data; struct iucv_event ev; ev.conn = conn; ev.data = (void *)eib; fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev);}static iucv_interrupt_ops_t netiucv_ops = { .ConnectionPending = netiucv_callback_connreq, .ConnectionComplete = netiucv_callback_connack, .ConnectionSevered = netiucv_callback_connrej, .ConnectionQuiesced = netiucv_callback_connsusp, .ConnectionResumed = netiucv_callback_connres, .MessagePending = netiucv_callback_rx, .MessageComplete = netiucv_callback_txdone};/** * Dummy NOP action for all statemachines */static voidfsm_action_nop(fsm_instance *fi, int event, void *arg){}/** * Actions of the connection statemachine *****************************************************************************//** * Helper function for conn_action_rx() * Unpack a just received skb and hand it over to * upper layers. * * @param conn The connection where this skb has been received. * @param pskb The received skb. *///static __inline__ voidstatic voidnetiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -