/*
* linux/net/iucv/af_iucv.c
*
* IUCV protocol stack for Linux on zSeries
*
* Copyright 2006 IBM Corporation
*
* Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
*/
#define KMSG_COMPONENT "af_iucv"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <net/sock.h>
#include <asm/ebcdic.h>
#include <asm/cpcmd.h>
#include <linux/kmod.h>
#include <net/iucv/iucv.h>
#include <net/iucv/af_iucv.h>
#define CONFIG_IUCV_SOCK_DEBUG 1
#define IPRMDATA 0x80
#define VERSION "1.0"
static char iucv_userid[80];
static struct proto_ops iucv_sock_ops;
static struct proto iucv_proto = {
.name = "AF_IUCV",
.owner = THIS_MODULE,
.obj_size = sizeof(struct iucv_sock),
};
static void iucv_sock_kill(struct sock *sk);
static void iucv_sock_close(struct sock *sk);
/* Call Back functions */
static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8],
u8 ipuser[16]);
static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
static struct iucv_sock_list iucv_sk_list = {
.lock = __RW_LOCK_UNLOCKED(iucv_sk_list.lock),
.autobind_name = ATOMIC_INIT(0)
};
static struct iucv_handler af_iucv_handler = {
.path_pending = iucv_callback_connreq,
.path_complete = iucv_callback_connack,
.path_severed = iucv_callback_connrej,
.message_pending = iucv_callback_rx,
.message_complete = iucv_callback_txdone
};
static inline void high_nmcpy(unsigned char *dst, char *src)
{
memcpy(dst, src, 8);
}
static inline void low_nmcpy(unsigned char *dst, char *src)
{
memcpy(&dst[8], src, 8);
}
/* Timers */
static void iucv_sock_timeout(unsigned long arg)
{
struct sock *sk = (struct sock *)arg;
bh_lock_sock(sk);
sk->sk_err = ETIMEDOUT;
sk->sk_state_change(sk);
bh_unlock_sock(sk);
iucv_sock_kill(sk);
sock_put(sk);
}
static void iucv_sock_clear_timer(struct sock *sk)
{
sk_stop_timer(sk, &sk->sk_timer