Commit 74beaae0 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.47

parent ab114917
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 46
SUBLEVEL = 47
ARCH = i386
......
......@@ -223,10 +223,6 @@ static void floppy_off(unsigned int nr);
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#else
#error "unknown blk device"
#endif
#if (MAJOR_NR != SCSI_TAPE_MAJOR)
......
......@@ -231,7 +231,7 @@ static struct {
{{3, 250, 16, 16, 3000, 100, 300, 0, 2, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 4,22,21,30, 3, 0, 0, 0}, 150, 4 }, "720k" }, /*3 1/2 DD*/
{{4, 500, 16, 16, 3000, 40, 300, 10, 2, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
{{4, 500, 16, 16, 4000, 40, 300, 10, 2, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
{{5, 1000, 15, 8, 3000, 40, 300, 10, 2, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
......
......@@ -866,6 +866,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
if (err)
return err;
memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
return 0;
RO_IOCTLS(inode->i_rdev,arg);
default:
......
......@@ -1457,13 +1457,13 @@ void poke_blanked_console(void)
}
}
void * memsetw(void * s,unsigned short c,int count)
void * memsetw(void * s, unsigned short c, unsigned int count)
{
__asm__("cld\n\t"
"rep\n\t"
"stosw"
: /* no output */
:"a" (c),"D" (s),"c" (count)
:"a" (c),"D" (s),"c" (count/2)
:"cx","di");
return s;
}
......
......@@ -16,13 +16,17 @@
* Note: lockstate is used as index in the array key_map.
*/
struct kbd_struct {
unsigned char ledstate; /* 3 bits */
unsigned char ledstate; /* 3 bits */
unsigned char default_ledstate;
unsigned char lockstate; /* 3 bits */
#define VC_SCROLLOCK 0 /* scroll-lock mode */
#define VC_NUMLOCK 1 /* numeric lock mode */
#define VC_CAPSLOCK 2 /* capslock mode */
unsigned char lockstate; /* 4 bits - must be in 0..15 */
#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */
#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */
#define VC_CTRLLOCK KG_CTRL /* control lock mode */
#define VC_ALTLOCK KG_ALT /* alt lock mode */
unsigned char modeflags;
#define VC_APPLIC 0 /* application key mode */
......
......@@ -344,15 +344,15 @@ static void keyboard_interrupt(int int_pt_regs)
u_char type;
/* the XOR below used to be an OR */
int shift_final = shift_state ^ vc_kbd_lock(kbd,VC_CAPSLOCK);
int shift_final = shift_state ^ kbd->lockstate;
key_code = key_map[shift_final][scancode];
type = KTYP(key_code);
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_lock(kbd,VC_CAPSLOCK))
key_code = key_map[shift_final][scancode];
if (vc_kbd_led(kbd,VC_CAPSLOCK))
key_code = key_map[shift_final ^ (1<<KG_SHIFT)][scancode];
}
(*key_handler[type])(key_code & 0xff, up_flag);
}
......@@ -404,7 +404,6 @@ static void caps_toggle(void)
if (rep)
return;
chg_vc_kbd_led(kbd,VC_CAPSLOCK);
chg_vc_kbd_lock(kbd,VC_CAPSLOCK);
}
static void caps_on(void)
......@@ -412,7 +411,6 @@ static void caps_on(void)
if (rep)
return;
set_vc_kbd_led(kbd,VC_CAPSLOCK);
set_vc_kbd_lock(kbd,VC_CAPSLOCK);
}
static void show_ptregs(void)
......@@ -463,10 +461,8 @@ static void num(void)
applkey('P', 1);
return;
}
if (!rep) { /* no autorepeat for numlock, ChN */
if (!rep) /* no autorepeat for numlock, ChN */
chg_vc_kbd_led(kbd,VC_NUMLOCK);
chg_vc_kbd_lock(kbd,VC_NUMLOCK);
}
}
static void lastcons(void)
......@@ -647,7 +643,8 @@ static void do_pad(unsigned char value, char up_flag)
applkey(app_map[value], 1);
return;
}
if (!vc_kbd_lock(kbd,VC_NUMLOCK))
if (!vc_kbd_led(kbd,VC_NUMLOCK))
switch (value) {
case KVAL(K_PCOMMA):
case KVAL(K_PDOT):
......@@ -709,10 +706,8 @@ static void do_shift(unsigned char value, char up_flag)
/* kludge... */
if (value == KVAL(K_CAPSSHIFT)) {
value = KVAL(K_SHIFT);
if (!up_flag) {
if (!up_flag)
clr_vc_kbd_led(kbd, VC_CAPSLOCK);
clr_vc_kbd_lock(kbd, VC_CAPSLOCK);
}
}
if (up_flag) {
......
......@@ -931,9 +931,9 @@ static int write_chan(struct tty_struct * tty, struct file * file,
if (opost(c, tty) < 0)
break;
b++; nr--;
if (tty->driver.flush_chars)
tty->driver.flush_chars(tty);
}
if (tty->driver.flush_chars)
tty->driver.flush_chars(tty);
} else {
c = tty->driver.write(tty, 1, b, nr);
b += c;
......
......@@ -1535,8 +1535,10 @@ int tty_register_driver(struct tty_driver *driver)
return 0;
error = register_chrdev(driver->major, driver->name, &tty_fops);
if (error)
if (error < 0)
return error;
else if(driver->major == 0)
driver->major = error;
if (!driver->put_char)
driver->put_char = tty_default_put_char;
......@@ -1545,7 +1547,7 @@ int tty_register_driver(struct tty_driver *driver)
driver->next = tty_drivers;
tty_drivers->prev = driver;
tty_drivers = driver;
return 0;
return error;
}
/*
......@@ -1589,7 +1591,7 @@ long tty_init(long kmem_start)
panic("size of tty structure > PAGE_SIZE!");
if (register_chrdev(TTY_MAJOR,"tty",&tty_fops))
panic("unable to get major %d for tty device", TTY_MAJOR);
if (register_chrdev(TTYAUX_MAJOR,"tty",&tty_fops))
if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
panic("unable to get major %d for tty device", TTYAUX_MAJOR);
kmem_start = kbd_init(kmem_start);
......
......@@ -193,6 +193,11 @@
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
* transceivers.
*
* LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
* bytes at a time. Since interrupts are disabled by default during
* these transfers, we might need this to give reasonable interrupt
* service time if the transfer size gets too large.
*
* LINKED - if defined, linked commands are supported.
*
* PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
......@@ -1980,10 +1985,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
if (!cmd->device->borken &&
(transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
#else
if (!cmd->device->borken &&
(transfersize = cmd->transfersize) &&
cmd->SCp.this_residual && !(cmd->SCp.this_residual %
transfersize)) {
transfersize = cmd->transfersize;
#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */
if( transfersize > 512 )
transfersize = 512;
#endif /* LIMIT_TRANSFERSIZE */
if (!cmd->device->borken && transfersize &&
cmd->SCp.this_residual && !(cmd->SCp.this_residual %
transfersize)) {
#endif
len = transfersize;
if (NCR5380_transfer_dma(instance, &phase,
......
......@@ -4,4 +4,5 @@ extern void print_command(unsigned char *);
extern int print_msg(unsigned char *);
extern void print_sense(char *, Scsi_Cmnd *);
extern void print_status(int);
extern void print_Scsi_Cmnd (Scsi_Cmnd *);
#endif /* def _CONSTANTS_H */
#define AUTOSENSE
#define PSEUDO_DMA
#define FOO
#define UNSAFE /* Not unsafe for PAS16 -- use it */
/*
* This driver adapted from Drew Eckhardt's Trantor T128 driver
......@@ -40,6 +42,11 @@
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
* for commands that return with a CHECK CONDITION status.
*
* LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
* bytes at a time. Since interrupts are disabled by default during
* these transfers, we might need this to give reasonable interrupt
* service time if the transfer size gets too large.
*
* PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
* increase compared to polled I/O.
*
......@@ -47,11 +54,13 @@
*
* SCSI2 - enable support for SCSI-II tagged queueing. Untested.
*
*
* UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
* only really want to use this if you're having a problem with
* dropped characters during high speed communications, and even
* then, you're going to be better off twiddling with transfersize.
* UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This
* parameter comes from the NCR5380 code. It is NOT unsafe with
* the PAS16 and you should use it. If you don't you will have
* a problem with dropped characters during high speed
* communications during SCSI transfers. If you really don't
* want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
* twiddle with the transfer size in the high level code.
*
* USLEEP - enable support for devices that don't disconnect. Untested.
*
......@@ -242,7 +251,7 @@ void init_board( unsigned short io_port, int irq, int force_irq )
int pas16_hw_detect( unsigned short board_num )
{
unsigned char board_rev, tmp;
unsigned short port = bases[ board_num ].io_port;
unsigned short io_port = bases[ board_num ].io_port;
/* See if we can find a PAS16 board at the address associated
* with this logical board number.
......@@ -251,26 +260,39 @@ int pas16_hw_detect( unsigned short board_num )
/* First, attempt to take a newer model board out of reset and
* give it a base address. This shouldn't affect older boards.
*/
enable_board( board_num, port );
enable_board( board_num, io_port );
/* Now see if it looks like a PAS16 board */
board_rev = inb( port + PCB_CONFIG );
board_rev = inb( io_port + PCB_CONFIG );
if( board_rev == 0xff )
return 0;
tmp = board_rev ^ 0xe0;
outb( tmp, port + PCB_CONFIG );
tmp = inb( port + PCB_CONFIG );
outb( board_rev, port + PCB_CONFIG );
outb( tmp, io_port + PCB_CONFIG );
tmp = inb( io_port + PCB_CONFIG );
outb( board_rev, io_port + PCB_CONFIG );
if( board_rev != tmp ) /* Not a PAS-16 */
return 0;
if( ( inb( port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
return 0; /* return if no SCSI interface found */
/* Mediavision has some new model boards that return ID bits
* that indicate a SCSI interface, but they're not (LMS). We'll
* put in an additional test to try and weed them out.
*/
outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */
if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */
return 0; /* and try to read */
NCR5380_write( MODE_REG, 0x00 ); /* it back. */
if( NCR5380_read( MODE_REG ) != 0x00 )
return 0;
return 1;
}
......@@ -426,7 +448,15 @@ int pas16_biosparam(Disk * disk, int dev, int * ip)
int size = disk->capacity;
ip[0] = 64;
ip[1] = 32;
ip[2] = size >> 11;
ip[2] = size >> 11; /* I think I have it as /(32*64) */
if( ip[2] > 1024 ) { /* yes, >, not >= */
ip[0]=255;
ip[1]=63;
ip[2]=size/(63*255);
if( ip[2] > 1023 ) /* yes >1023... */
ip[2] = 1023;
}
return 0;
}
......
......@@ -627,7 +627,20 @@ are any multiple of 512 bytes long. */
printk("\n");
};
#endif
/* Some dumb host adapters can speed transfers by knowing the
* minimum tranfersize in advance.
*
* We shouldn't disconnect in the middle of a sector, but the cdrom
* sector size can be larger than the size of a buffer and the
* transfer may be split to the size of a buffer. So it's safe to
* assume that we can at least transfer the minimum of the buffer
* size (1024) and the sector size between each connect / disconnect.
*/
SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
1024 : scsi_CDs[dev].sector_size;
SCpnt->this_count = this_count;
scsi_do_cmd (SCpnt, (void *) cmd, buffer,
realcount * scsi_CDs[dev].sector_size,
......
......@@ -316,10 +316,7 @@ int ext2_new_block (struct super_block * sb, unsigned long goal,
else
lmap |= 0xffffffff << (31 - (j & 31));
if (lmap != 0xffffffffl) {
__asm__ ("bsfl %1,%0"
: "=r" (k)
: "r" (~lmap));
k++;
k = ffz(lmap) + 1;
if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) {
j += k;
goto got_block;
......
......@@ -121,4 +121,16 @@ extern inline int find_next_zero_bit (unsigned long * addr, int size,
return (offset + set + res);
}
/*
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
extern inline unsigned long ffz(unsigned long word)
{
__asm__("bsfl %1,%0"
:"=r" (word)
:"r" (~word));
return word;
}
#endif /* _I386_BITOPS_H */
#ifndef _LINUX_NCP_H_
#define _LINUX_NCP_H_
#define NCP_OPEN 0x1111
#define NCP_CLOSE 0x5555
#define NCP_REQUEST 0x2222
#define NCP_REPLY 0x3333
struct ncp_request
{
unsigned short p_type __attribute__ ((packed));
unsigned char seq __attribute__ ((packed));
unsigned char c_low __attribute__ ((packed));
unsigned char task __attribute__ ((packed));
unsigned char c_high __attribute__ ((packed));
unsigned char func __attribute__ ((packed));
};
struct ncp_request_sf
{
unsigned short p_type __attribute__ ((packed));
unsigned char seq __attribute__ ((packed));
unsigned char c_low __attribute__ ((packed));
unsigned char task __attribute__ ((packed));
unsigned char c_high __attribute__ ((packed));
unsigned char func __attribute__ ((packed));
unsigned short s_len __attribute__ ((packed));
unsigned char s_func __attribute__ ((packed));
};
struct ncp_reply
{
unsigned short p_type __attribute__ ((packed));
unsigned char seq __attribute__ ((packed));
unsigned char c_low __attribute__ ((packed));
unsigned char task __attribute__ ((packed));
unsigned char c_high __attribute__ ((packed));
unsigned char f_stat __attribute__ ((packed));
unsigned char c_stat __attribute__ ((packed));
};
#define OTYPE_USER 0x0001
#define OTYPE_GROUP 0x0002
#define OTYPE_PQUEUE 0x0003
#define OTYPE_FSERVER 0x0004
#define OTYPE_JSERVER 0x0005
#define OTYPE_PSERVER 0x0007
#define OTYPE_UNKNOWN_1 0x002E
#define OTYPE_ADV_PSERVER 0x0047
#define OTYPE_AFSERVER 0x0107
#define OTYPE_UNKNOWN_2 0x0143
#define OTYPE_UNKNOWN_3 0x01F5
#define OTYPE_UNKNOWN_4 0x023F
#define LIMIT_OBJNAME 47
struct bind_obj
{
unsigned long id __attribute__ ((packed));
unsigned short type __attribute__ ((packed));
char name[LIMIT_OBJNAME+1] __attribute__ ((packed));
};
struct get_bind_obj
{
unsigned short type __attribute__ ((packed));
unsigned char n_len __attribute__ ((packed));
char name[0] __attribute__ ((packed));
};
struct scan_bind_obj
{
unsigned long id __attribute__ ((packed));
unsigned short type __attribute__ ((packed));
unsigned char n_len __attribute__ ((packed));
char name[0] __attribute__ ((packed));
};
struct login_req
{
unsigned char password[8] __attribute__ ((packed));
unsigned short type __attribute__ ((packed));
unsigned char n_len __attribute__ ((packed));
char name[0] __attribute__ ((packed));
};
struct ncp_time
{
unsigned char year __attribute__ ((packed));
unsigned char month __attribute__ ((packed));
unsigned char day __attribute__ ((packed));
unsigned char hours __attribute__ ((packed));
unsigned char mins __attribute__ ((packed));
unsigned char secs __attribute__ ((packed));
unsigned char c_secs __attribute__ ((packed));
};
struct login_info
{
unsigned long id __attribute__ ((packed));
unsigned short un1 __attribute__ ((packed));
char name[LIMIT_OBJNAME+1] __attribute__ ((packed));
struct ncp_time time __attribute__ ((packed));
};
#endif
......@@ -20,6 +20,7 @@ struct linger {
#define SOCK_RAW 3 /* raw socket */
#define SOCK_RDM 4 /* reliably-delivered message */
#define SOCK_SEQPACKET 5 /* sequential packet socket */
#define SOCK_NCP 6 /* Novell NCP socket */
#define SOCK_PACKET 10 /* linux specific way of */
/* getting packets at the dev */
/* level. For writing rarp and */
......
......@@ -177,7 +177,8 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
switch(sel_type)
{
case SEL_IN:
if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
if ((sk->type==SOCK_SEQPACKET || sk->type==SOCK_NCP)
&& sk->state==TCP_CLOSE)
{
/* Connection closed: Wake up */
return(1);
......
......@@ -56,8 +56,16 @@
#include <linux/termios.h> /* For TIOCOUTQ/INQ */
#include <linux/interrupt.h>
#include "p8022.h"
#include "ncp.h"
#ifdef CONFIG_IPX
static void ipx_delete_timer (ipx_socket *sk);
static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
void *ubuf, int len, int flag, unsigned char type);
static void ipx_add_timer (ipx_socket *sk, int len);
static void ipx_reset_timer (ipx_socket *sk, int len);
/***********************************************************************************************************************\
* *
* Handlers for the socket list. *
......@@ -75,7 +83,9 @@ static ipx_socket *volatile ipx_socket_list=NULL;
static void ipx_remove_socket(ipx_socket *sk)
{
ipx_socket *s;
unsigned long flags;
save_flags(flags);
cli();
s=ipx_socket_list;
if(s==sk)
......@@ -89,20 +99,23 @@ static void ipx_remove_socket(ipx_socket *sk)
if(s->next==sk)
{
s->next=sk->next;
sti();
restore_flags(flags);
return;
}
s=s->next;
}
sti();
restore_flags(flags);
}
static void ipx_insert_socket(ipx_socket *sk)
{
unsigned long flags;
save_flags(flags);
cli();
sk->next=ipx_socket_list;
ipx_socket_list=sk;
sti();
restore_flags(flags);
}
static ipx_socket *ipx_find_socket(int port)
......@@ -133,9 +146,10 @@ static void ipx_destroy_socket(ipx_socket *sk)
ipx_remove_socket(sk);
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{
kfree_skb(skb,FREE_READ);
}
while((skb=skb_dequeue(&sk->write_queue))!=NULL)
kfree_skb(skb,FREE_WRITE);
kfree_s(sk,sizeof(*sk));
}
......@@ -151,20 +165,24 @@ int ipx_get_info(char *buffer, char **start, off_t offset, int length)
/* Theory.. Keep printing in the same place until we pass offset */
len += sprintf (buffer,"Type local_address rem_address tx_queue rx_queue st uid\n");
len += sprintf (buffer," local_address rem_address tx_queue rx_queue st uid\n");
for (s = ipx_socket_list; s != NULL; s = s->next)
{
len += sprintf (buffer+len,"%02X ", s->ipx_type);
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_source_addr.net),
len += sprintf (buffer+len,"%02X ", s->ipx_type);
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%04X ", htonl(s->ipx_source_addr.net),
s->ipx_source_addr.node[0], s->ipx_source_addr.node[1], s->ipx_source_addr.node[2],
s->ipx_source_addr.node[3], s->ipx_source_addr.node[4], s->ipx_source_addr.node[5],
htons(s->ipx_source_addr.sock));
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_dest_addr.net),
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%04X ", htonl(s->ipx_dest_addr.net),
s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1], s->ipx_dest_addr.node[2],
s->ipx_dest_addr.node[3], s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5],
htons(s->ipx_dest_addr.sock));
len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc);
len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid);
len += sprintf (buffer+len,"%02X ", s->state);
if (s->socket)
len += sprintf (buffer+len,"%d\n", SOCK_INODE(s->socket)->i_uid);
else
len += sprintf (buffer+len,"%d\n", SOCK_INODE(s->ncp.ncp->socket)->i_uid);
/* Are we still dumping unwanted data then discard the record */
pos=begin+len;
......@@ -566,20 +584,56 @@ static void def_callback2(struct sock *sk, int len)
wake_up_interruptible(sk->sleep);
}
static int ipx_create(struct socket *sock, int protocol)
static void watch_callback(struct sock *sk, int len)
{
ipx_socket *sk;
sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
if(sk==NULL)
return(-ENOMEM);
switch(sock->type)
ipx_packet *ipx;
struct sk_buff *skb;
char *data;
skb=skb_dequeue(&sk->receive_queue);
if(skb==NULL)
return;
ipx = (ipx_packet *)(skb->h.raw);
data = (char *)(ipx+1);
if (*(data+1) == '?')
ipx_do_sendto(sk,&(ipx->ipx_source),"\0Y",2,0,sk->ipx_type);
kfree_skb(skb, FREE_READ);
}
static void mail_callback(struct sock *sk, int len)
{
ipx_packet *ipx;
struct sk_buff *skb;
char *data;
skb=skb_dequeue(&sk->receive_queue);
if(skb==NULL)
return;
ipx = (ipx_packet *)(skb->h.raw);
data = (char *)(ipx+1);
if (*(data+1) == '!')
{
case SOCK_DGRAM:
break;
default:
kfree_s((void *)sk,sizeof(*sk));
return(-ESOCKTNOSUPPORT);
struct ncp_request_sf req;
req.func=0x15;
req.s_func=0x01;
req.s_len=htons(1);
ipx_do_sendto(sk->ncp.ncp, &(sk->ncp.ncp->ipx_dest_addr),
&req, sizeof(req), 0,sk->ncp.ncp->ipx_type);
}
kfree_skb(skb, FREE_READ);
}
static void ipx_do_create(struct socket *sock, ipx_socket *sk)
{
sk->dead=0;
sk->next=NULL;
sk->broadcast=0;
......@@ -598,7 +652,6 @@ static int ipx_create(struct socket *sock, int protocol)
skb_queue_head_init(&sk->back_log);
sk->state=TCP_CLOSE;
sk->socket=sock;
sk->type=sock->type;
sk->ipx_type=0; /* General user level IPX */
sk->debug=0;
......@@ -610,14 +663,76 @@ static int ipx_create(struct socket *sock, int protocol)
{
sock->data=(void *)sk;
sk->sleep=sock->wait;
sk->type=sock->type;
}
else
sk->type=SOCK_DGRAM;
sk->priority=SOPRI_NORMAL;
sk->state_change=def_callback1;
sk->data_ready=def_callback2;
sk->write_space=def_callback1;
sk->error_report=def_callback1;
sk->zapped=1;
return;
}
static int ncp_create(struct socket *sock, int protocol)
{
ipx_socket *sk;
ipx_socket *skw;
ipx_socket *skm;
if ((sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL))==NULL)
return(-ENOMEM);
if ((skw=(ipx_socket *)kmalloc(sizeof(*skw),GFP_KERNEL))==NULL)
{
kfree_s((void *)sk, sizeof(*sk));
return(-ENOMEM);
}
if ((skm=(ipx_socket *)kmalloc(sizeof(*skm),GFP_KERNEL))==NULL)
{
kfree_s((void *)skw, sizeof(*skw));
kfree_s((void *)sk, sizeof(*sk));
return(-ENOMEM);
}
ipx_do_create(sock, sk);
sk->ncp.ncp=NULL;
sk->ncp.watchdog=skw;
sk->ncp.mail=skm;
ipx_do_create(NULL, skw);
skw->ncp.ncp=sk;
skw->data_ready=watch_callback;
ipx_do_create(NULL, skm);
skm->ncp.ncp=sk;
skm->data_ready=mail_callback;
return(0);
}
static int ipx_create(struct socket *sock, int protocol)
{
ipx_socket *sk;
switch(sock->type)
{
case SOCK_DGRAM:
break;
case SOCK_NCP:
return(ncp_create(sock, protocol));
default:
return(-ESOCKTNOSUPPORT);
}
if ((sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL))==NULL)
return(-ENOMEM);
ipx_do_create(sock, sk);
return(0);
}
......@@ -633,47 +748,79 @@ static int ipx_release(struct socket *sock, struct socket *peer)
return(0);
if(!sk->dead)
sk->state_change(sk);
sk->dead=1;
sock->data=NULL;
ipx_destroy_socket(sk);
if (sk->type == SOCK_NCP)
{
sk->ncp.watchdog->dead=1;
ipx_destroy_socket(sk->ncp.watchdog);
sk->ncp.mail->dead=1;
ipx_destroy_socket(sk->ncp.mail);
if ((sk->state == TCP_ESTABLISHED) || (sk->state == TCP_SYN_SENT))
{
struct ncp_request req;
sk->state=TCP_CLOSE_WAIT;
ipx_do_sendto(sk, &(sk->ipx_dest_addr), &req,
sizeof(req), 0, sk->ipx_type);
}
else
{
sk->dead=1;
if (sk->state != TCP_CLOSE)
ipx_delete_timer(sk);
ipx_destroy_socket(sk);
}
}
else
{
sk->dead=1;
ipx_destroy_socket(sk);
}
return(0);
}
static unsigned short first_free_socketnum(void)
{
static unsigned short socketNum = 0x4000;
static unsigned short socketNum = 0x3fff;
while (ipx_find_socket(htons(socketNum)) != NULL)
if (socketNum > 0x7ffc) socketNum = 0x4000;
while (ipx_find_socket(htons(++socketNum)) != NULL)
if (socketNum > 0x7ffc) socketNum = 0x3fff;
return htons(socketNum++);
return htons(socketNum);
}
static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
{
ipx_socket *sk;
ipx_socket *sk=(ipx_socket *)sock->data;
struct ipx_route *rt;
unsigned char *nodestart;
struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
sk=(ipx_socket *)sock->data;
if(sk->zapped==0)
return(-EIO);
if(addr_len!=sizeof(struct sockaddr_ipx))
return -EINVAL;
if (addr->sipx_port == 0)
{
addr->sipx_port = first_free_socketnum();
if (sk->type == SOCK_NCP)
while ((ipx_find_socket(htons(ntohs(addr->sipx_port)+1)))
|| (ipx_find_socket(htons(ntohs(addr->sipx_port)+2))))
addr->sipx_port = first_free_socketnum();
if (addr->sipx_port == 0)
return -EINVAL;
}
if(ntohs(addr->sipx_port)<0x4000 && !suser())
return(-EPERM); /* protect IPX system stuff like routing/sap */
/* Source addresses are easy. It must be our network:node pair for
an interface routed to IPX with the ipx routing ioctl() */
......@@ -685,6 +832,19 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
return -EADDRINUSE;
}
if (sk->type == SOCK_NCP)
{
if ((ipx_find_socket(htons(ntohs(addr->sipx_port)+1)))
|| (ipx_find_socket(htons(ntohs(addr->sipx_port)+2))))
{
if(sk->debug)
printk("IPX: bind failed because port %X in use.\n",
(int)addr->sipx_port);
return -EADDRINUSE;
}
addr->sipx_type=IPX_TYPE_NCP;
}
sk->ipx_source_addr.sock=addr->sipx_port;
if (addr->sipx_network == 0L)
......@@ -705,6 +865,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
}
sk->ipx_source_addr.net=rt->net;
sk->ipx_type=addr->sipx_type;
/* IPX addresses zero pad physical addresses less than 6 */
memset(sk->ipx_source_addr.node,'\0',6);
......@@ -713,41 +874,102 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
ipx_insert_socket(sk);
sk->zapped=0;
if (sk->type == SOCK_NCP)
{
sk->ncp.watchdog->ipx_source_addr.net=rt->net;
sk->ncp.watchdog->ipx_source_addr.sock=htons(ntohs(addr->sipx_port)+1);
memset(sk->ncp.watchdog->ipx_source_addr.node,'\0',6);
nodestart = sk->ncp.watchdog->ipx_source_addr.node + (6 - rt->dev->addr_len);
memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len);
ipx_insert_socket(sk->ncp.watchdog);
sk->ncp.watchdog->zapped=0;
sk->ncp.mail->ipx_source_addr.net=rt->net;
sk->ncp.mail->ipx_source_addr.sock=htons(ntohs(addr->sipx_port)+2);
memset(sk->ncp.mail->ipx_source_addr.node,'\0',6);
nodestart = sk->ncp.mail->ipx_source_addr.node + (6 - rt->dev->addr_len);
memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len);
ipx_insert_socket(sk->ncp.mail);
sk->ncp.mail->zapped=0;
sk->mtu=rt->dev->mtu;
}
if(sk->debug)
printk("IPX: socket is bound.\n");
return(0);
}
static int ncp_connect(struct socket *sock, ipx_socket *sk)
{
struct ncp_request req;
int err;
sk->ncp.conn=0xffff;
sk->ncp.seq=0;
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
sk->rto = 0;
ipx_do_sendto(sk, &(sk->ipx_dest_addr), &req, sizeof(req), 0, sk->ipx_type);
while(sk->state != TCP_ESTABLISHED)
{
if (sk->err)
{
err=sk->err;
sk->err=0;
return -err;
}
interruptible_sleep_on(sk->sleep);
}
return(0);
}
static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
ipx_socket *sk=(ipx_socket *)sock->data;
struct sockaddr_ipx *addr;
struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
if(addr_len!=sizeof(addr))
if(addr_len!=sizeof(struct sockaddr_ipx))
return(-EINVAL);
addr=(struct sockaddr_ipx *)uaddr;
if(sk->ipx_source_addr.net==0)
if(sk->ipx_source_addr.sock==0)
/* put the autobinding in */
{
struct sockaddr_ipx uaddr;
int ret;
struct sockaddr_ipx addr;
uaddr.sipx_port = 0;
uaddr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
addr.sipx_type = 0;
addr.sipx_port = 0;
addr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
sk->ipx_dest_addr.net=addr->sipx_network;
sk->ipx_dest_addr.sock=addr->sipx_port;
memcpy(sk->ipx_dest_addr.node,addr->sipx_node,sizeof(sk->ipx_source_addr.node));
if(ipxrtr_get_dev(sk->ipx_dest_addr.net)==NULL)
return -ENETUNREACH;
if (sk->type == SOCK_NCP)
return(ncp_connect(sock, sk));
sk->ipx_type=addr->sipx_type;
sock->state = SS_CONNECTED;
sk->state=TCP_ESTABLISHED;
return(0);
......@@ -770,10 +992,9 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
{
ipx_address *addr;
struct sockaddr_ipx sipx;
ipx_socket *sk;
sk=(ipx_socket *)sock->data;
ipx_socket *sk=(ipx_socket *)sock->data;
*uaddr_len = sizeof(struct sockaddr_ipx);
if(peer)
......@@ -783,7 +1004,21 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
addr=&sk->ipx_dest_addr;
}
else
{
if(sk->ipx_source_addr.sock==0)
/* put the autobinding in */
{
int ret;
sipx.sipx_type = 0;
sipx.sipx_port = 0;
sipx.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&sipx, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
addr=&sk->ipx_source_addr;
}
sipx.sipx_family = AF_IPX;
sipx.sipx_port = addr->sock;
......@@ -793,6 +1028,411 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
return(0);
}
static int ipx_build_header(ipx_address *ipx, struct sk_buff *skb,
ipx_socket *sk, int len, unsigned char type)
{
ipx_packet *ipx_pack;
ipx_route *rt;
struct datalink_proto *dl = NULL;
unsigned char IPXaddr[6];
int self_addressing = 0;
int broadcast = 0;
if(sk->debug)
printk("IPX: build_header: Addresses built.\n");
if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0)
{
if (!sk->broadcast)
return -ENETUNREACH;
broadcast = 1;
}
/* Build a packet */
if(sk->debug)
printk("IPX: build_header: building packet.\n");
/* Find out where this has to go */
if (ipx->net == 0L) {
rt = ipxrtr_get_default_net();
if (rt != NULL)
ipx->net = rt->net;
} else
rt=ipxrtr_get_dev(ipx->net);
if(rt==NULL)
{
return -ENETUNREACH;
}
dl=rt->datalink;
skb->mem_addr=skb;
skb->sk=sk;
skb->free=1;
skb->arp=1;
skb->tries=0;
if(sk->debug)
printk("Building MAC header.\n");
skb->dev=rt->dev;
/* Build Data Link header */
dl->datalink_header(dl, skb,
(rt->flags&IPX_RT_ROUTED)?rt->router_node:ipx->node);
/* See if we are sending to ourself */
memset(IPXaddr, '\0', 6);
memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr,
skb->dev->addr_len);
self_addressing = !memcmp(IPXaddr,
(rt->flags&IPX_RT_ROUTED)?rt->router_node
:ipx->node,
6);
/* Now the IPX */
if(sk->debug)
printk("Building IPX Header.\n");
ipx_pack=(ipx_packet *)skb->h.raw;
ipx_pack->ipx_checksum=0xFFFF;
ipx_pack->ipx_pktsize=htons(len+sizeof(ipx_packet));
ipx_pack->ipx_tctrl=0;
ipx_pack->ipx_type=type;
memcpy(&ipx_pack->ipx_source,&sk->ipx_source_addr,sizeof(ipx_pack->ipx_source));
memcpy(&ipx_pack->ipx_dest,ipx,sizeof(ipx_pack->ipx_dest));
if((skb->dev->flags&IFF_LOOPBACK) || self_addressing)
skb->pkt_type=PACKET_HOST;
else
if (broadcast)
skb->pkt_type=PACKET_BROADCAST;
else
skb->pkt_type=PACKET_OTHERHOST;
return 0;
}
static int ipx_xmit(struct sk_buff *skb)
{
struct sk_buff *skb1;
struct device *dev= skb->dev;
ipx_packet *ipx=(ipx_packet *)skb->h.raw;
ipx_route *rt;
struct packet_type pt;
if (ipx->ipx_dest.net == 0L)
rt = ipxrtr_get_default_net();
else
rt=ipxrtr_get_dev(ipx->ipx_dest.net);
if (rt == NULL)
return -ENETUNREACH;
pt.type=rt->dlink_type;
skb->tries++;
switch (skb->pkt_type)
{
case PACKET_HOST:
if (!skb->free)
{
skb1=alloc_skb(skb->len, GFP_ATOMIC);
if (skb1 != NULL)
{
skb1->mem_addr=skb1;
skb1->free=1;
skb1->arp=1;
skb1->len=skb->len;
skb1->sk = NULL;
skb1->h.raw = skb1->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb1->data, skb->data, skb->len);
ipx_rcv(skb1,dev,&pt);
}
}
else
{
/* loop back */
skb->sk->wmem_alloc-=skb->mem_len;
skb->sk = NULL;
ipx_rcv(skb,dev,&pt);
}
break;
case PACKET_BROADCAST:
skb1=alloc_skb(skb->len, GFP_ATOMIC);
if (skb1 != NULL)
{
skb1->mem_addr=skb1;
skb1->free=1;
skb1->arp=1;
skb1->len=skb->len;
skb1->sk = NULL;
skb1->h.raw = skb1->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb1->data, skb->data, skb->len);
ipx_rcv(skb1,dev,&pt);
}
default:
if (!skb->free)
{
skb1=alloc_skb(skb->len, GFP_ATOMIC);
if (skb1 != NULL)
{
skb1->mem_addr=skb1;
skb1->free=1;
skb1->arp=1;
skb1->len=skb->len;
skb1->sk = NULL;
skb1->h.raw = skb1->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb1->data, skb->data, skb->len);
}
}
else
skb1=skb;
if (skb1 != NULL)
{
if (skb1->sk)
dev_queue_xmit(skb1,dev,skb->sk->priority);
else
dev_queue_xmit(skb1,dev,SOPRI_NORMAL);
}
}
return(0);
}
static int ipx_retransmit(ipx_socket *sk)
{
struct sk_buff *skb = sk->write_queue.next;
int num=0;
ipx_packet *ipx;
struct ncp_request *req;
if (skb == NULL)
return(num);
if (skb == skb->next)
return(num);
do
{
ipx=(ipx_packet *)skb->h.raw;
req=(struct ncp_request *)(ipx+1);
ipx_xmit(skb);
num++;
skb=skb->next;
}
while (skb->next != sk->write_queue.next);
return (num);
}
static void ipx_timer (unsigned long data)
{
ipx_socket *sk = (ipx_socket *) data;
int num;
cli();
if (in_bh)
{
sk->timer.expires = 10;
add_timer(&sk->timer);
sti();
return;
}
sti();
num=ipx_retransmit(sk);
sk->rto++;
if (sk->rto >= MAX_TIMEOUT)
{
struct sk_buff *skb;
while((skb=skb_dequeue(&sk->write_queue))!=NULL)
kfree_skb(skb,FREE_WRITE);
sk->err=ETIMEDOUT;
sk->state=TCP_CLOSE;
sk->socket->state=SS_UNCONNECTED;
if(!sk->dead)
sk->error_report(sk);
return;
}
if (num)
ipx_reset_timer(sk, NCP_TIMEOUT);
return;
}
static void ipx_delete_timer (ipx_socket *sk)
{
unsigned long flags;
save_flags (flags);
cli();
del_timer (&sk->timer);
restore_flags(flags);
}
static void ipx_add_timer (ipx_socket *sk, int len)
{
init_timer (&sk->timer);
sk->timer.data = (unsigned long) sk;
sk->timer.function = &ipx_timer;
sk->timer.expires = len;
add_timer(&sk->timer);
}
static void ipx_reset_timer (ipx_socket *sk, int len)
{
ipx_delete_timer (sk);
sk->timer.data = (unsigned long) sk;
sk->timer.function = &ipx_timer;
sk->timer.expires = len;
add_timer(&sk->timer);
}
static struct sk_buff *find_req(ipx_socket *sk, unsigned char seq)
{
ipx_packet *ipx;
struct ncp_request *req;
struct sk_buff *skb = sk->write_queue.next;
if (skb == NULL)
return (NULL);
if (skb == skb->next)
return (NULL);
do
{
ipx=(ipx_packet *)skb->h.raw;
req=(struct ncp_request *)(ipx+1);
if (req->seq == seq)
{
skb_unlink(skb);
return (skb);
}
skb=skb->next;
}
while (skb->next != sk->write_queue.next);
return (NULL);
}
static int ncp_rcv(ipx_socket *sk, struct sk_buff *skb)
{
ipx_packet *ipx=(ipx_packet *)skb->h.raw;
struct ncp_reply *rep= (struct ncp_reply *)(ipx+1);
struct ncp_request_sf *req;
struct sk_buff *skb1;
if (rep->p_type != NCP_REPLY)
{
kfree_skb(skb, FREE_READ);
return (0);
}
skb1=find_req(sk, rep->seq);
if (skb1 == NULL)
{
kfree_skb(skb, FREE_READ);
return (0);
}
if (&sk->write_queue == sk->write_queue.next)
{
sk->rto=0;
ipx_delete_timer(sk);
}
ipx=(ipx_packet *)skb1->h.raw;
req=(struct ncp_request_sf *)(ipx+1);
switch (sk->state)
{
case TCP_CLOSE_WAIT:
kfree_skb(skb, FREE_READ);
sk->socket->data = NULL;
sk->state=TCP_CLOSE;
if(!sk->dead)
sk->state_change(sk);
sk->dead=1;
if (&sk->write_queue != sk->write_queue.next)
ipx_delete_timer(sk);
ipx_destroy_socket(sk);
break;
case TCP_SYN_SENT:
if ((rep->f_stat == 0) && (rep->c_stat == 0))
{
sk->state=TCP_ESTABLISHED;
sk->socket->state = SS_CONNECTED;
sk->ncp.conn=rep->c_low + (rep->c_high * 0xff);
if(!sk->dead)
sk->state_change(sk);
}
else
{
sk->state=TCP_CLOSE;
sk->socket->state = SS_UNCONNECTED;
sk->err=ECONNREFUSED;
if (&sk->write_queue != sk->write_queue.next)
ipx_delete_timer(sk);
if(!sk->dead)
sk->error_report(sk);
}
kfree_skb(skb, FREE_READ);
break;
default:
if ((req->func==0x15)&&(req->s_func==0x01))
{
char *data = (char *)(rep+1);
int len=(int)*data;
if (len != 0)
{
memcpy(data, data+1, len);
*(data+len)='\0';
printk("\007%s\n",data);
}
kfree_skb(skb, FREE_READ);
}
else
{
sk->rmem_alloc+=skb->mem_len;
skb->sk = sk;
skb_queue_tail(&sk->receive_queue,skb);
if(!sk->dead)
sk->data_ready(sk,skb->len);
}
}
kfree_skb(skb1, FREE_WRITE);
return(0);
}
int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
/* NULL here for pt means the packet was looped back */
......@@ -942,6 +1582,9 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
kfree_skb(skb,FREE_READ); /* Socket is full */
return(0);
}
if (sock->type == SOCK_NCP)
return (ncp_rcv(sock, skb));
sock->rmem_alloc+=skb->mem_len;
skb->sk = sock;
......@@ -952,65 +1595,27 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0);
}
static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
unsigned flags, struct sockaddr *usip, int addr_len)
static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
void *ubuf, int len, int flag, unsigned char type)
{
ipx_socket *sk=(ipx_socket *)sock->data;
struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
struct sockaddr_ipx local_sipx;
struct sk_buff *skb;
struct device *dev;
struct ipx_packet *ipx;
ipx_packet *ipx_pack;
int size;
ipx_route *rt;
struct datalink_proto *dl = NULL;
unsigned char IPXaddr[6];
int self_addressing = 0;
int broadcast = 0;
if(flags)
return -EINVAL;
if(usipx)
{
if(sk->ipx_source_addr.net==0)
/* put the autobinding in */
{
struct sockaddr_ipx uaddr;
int ret;
uaddr.sipx_port = 0;
uaddr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
if(addr_len <sizeof(*usipx))
return(-EINVAL);
if(usipx->sipx_family != AF_IPX)
return -EINVAL;
if(htons(usipx->sipx_port)<0x4000 && !suser())
return -EPERM;
}
else
{
if(sk->state!=TCP_ESTABLISHED)
return -ENOTCONN;
usipx=&local_sipx;
usipx->sipx_family=AF_IPX;
usipx->sipx_port=sk->ipx_dest_addr.sock;
usipx->sipx_network=sk->ipx_dest_addr.net;
memcpy(usipx->sipx_node,sk->ipx_dest_addr.node,sizeof(usipx->sipx_node));
}
if(sk->debug)
printk("IPX: sendto: Addresses built.\n");
if(memcmp(&usipx->sipx_node,&ipx_broadcast_node,6)==0)
if ((sk->type == SOCK_NCP) && (len < sizeof (struct ncp_request)))
return -EINVAL;
if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0)
{
if (!sk->broadcast)
return -ENETUNREACH;
broadcast = 1;
}
/* Build a packet */
......@@ -1021,12 +1626,12 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
size=sizeof(ipx_packet)+len; /* For mac headers */
/* Find out where this has to go */
if (usipx->sipx_network == 0L) {
if (ipx->net == 0L) {
rt = ipxrtr_get_default_net();
if (rt != NULL)
usipx->sipx_network = rt->net;
ipx->net = rt->net;
} else
rt=ipxrtr_get_dev(usipx->sipx_network);
rt=ipxrtr_get_dev(ipx->net);
if(rt==NULL)
{
......@@ -1046,86 +1651,117 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
return -EAGAIN;
}
skb=alloc_skb(size,GFP_KERNEL);
if (flag)
skb=alloc_skb(size,GFP_KERNEL);
else
skb=alloc_skb(size,GFP_ATOMIC);
if(skb==NULL)
return -ENOMEM;
sk->wmem_alloc+=skb->mem_len;
skb->mem_addr=skb;
skb->sk=sk;
skb->free=1;
skb->arp=1;
skb->len=size;
sk->wmem_alloc+=skb->mem_len;
ipx_build_header(ipx, skb, sk, len, type);
if(sk->debug)
printk("Building MAC header.\n");
skb->dev=rt->dev;
/* Build Data Link header */
dl->datalink_header(dl, skb,
(rt->flags&IPX_RT_ROUTED)?rt->router_node:usipx->sipx_node);
ipx_pack = (ipx_packet *)(skb->h.raw);
/* See if we are sending to ourself */
memset(IPXaddr, '\0', 6);
memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr,
skb->dev->addr_len);
/* User data follows immediately after the IPX data */
if (flag)
memcpy_fromfs((char *)(ipx_pack+1),ubuf,len);
else
memcpy((char *)(ipx_pack+1),ubuf,len);
self_addressing = !memcmp(IPXaddr,
(rt->flags&IPX_RT_ROUTED)?rt->router_node
:usipx->sipx_node,
6);
if (sk->type == SOCK_NCP)
{
struct ncp_request *req=(struct ncp_request *)(ipx_pack+1);
switch (sk->state)
{
case TCP_SYN_SENT:
req->p_type = NCP_OPEN;
break;
case TCP_CLOSE_WAIT:
req->p_type = NCP_CLOSE;
break;
default:
req->p_type = NCP_REQUEST;
}
req->c_low = (sk->ncp.conn) & 0xff;
req->c_high = (sk->ncp.conn >>8) & 0xff;
req->seq = (sk->ncp.seq)++;
req->task = 1;
skb->free=0;
if (&sk->write_queue == sk->write_queue.next)
ipx_add_timer(sk, NCP_TIMEOUT);
else
ipx_reset_timer(sk, NCP_TIMEOUT);
skb_queue_tail(&sk->write_queue,skb);
}
/* Now the IPX */
if(sk->debug)
printk("Building IPX Header.\n");
ipx=(ipx_packet *)skb->h.raw;
ipx->ipx_checksum=0xFFFF;
ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
ipx->ipx_tctrl=0;
ipx->ipx_type=usipx->sipx_type;
memcpy(&ipx->ipx_source,&sk->ipx_source_addr,sizeof(ipx->ipx_source));
ipx->ipx_dest.net=usipx->sipx_network;
memcpy(ipx->ipx_dest.node,usipx->sipx_node,sizeof(ipx->ipx_dest.node));
ipx->ipx_dest.sock=usipx->sipx_port;
if(sk->debug)
printk("IPX: Appending user data.\n");
/* User data follows immediately after the IPX data */
memcpy_fromfs((char *)(ipx+1),ubuf,len);
if(sk->debug)
printk("IPX: Transmitting buffer\n");
if((dev->flags&IFF_LOOPBACK) || self_addressing) {
struct packet_type pt;
/* loop back */
pt.type = rt->dlink_type;
sk->wmem_alloc-=skb->mem_len;
skb->sk = NULL;
ipx_rcv(skb,dev,&pt);
} else {
if (broadcast) {
struct packet_type pt;
struct sk_buff *skb2;
/* loop back */
pt.type = rt->dlink_type;
skb2=alloc_skb(skb->len, GFP_ATOMIC);
skb2->mem_addr=skb2;
skb2->free=1;
skb2->arp=1;
skb2->len=skb->len;
skb2->sk = NULL;
skb2->h.raw = skb2->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb2->data, skb->data, skb->len);
ipx_rcv(skb2,dev,&pt);
ipx_xmit(skb);
return len;
}
static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
unsigned flags, struct sockaddr *usip, int addr_len)
{
ipx_socket *sk=(ipx_socket *)sock->data;
ipx_address ipx;
struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
struct sockaddr_ipx local_sipx;
if(flags)
return -EINVAL;
if(usipx)
{
if (sk->type == SOCK_NCP)
return -EINVAL;
if(sk->ipx_source_addr.sock==0)
/* put the autobinding in */
{
int ret;
local_sipx.sipx_type = 0;
local_sipx.sipx_port = 0;
local_sipx.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&local_sipx, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
dev_queue_xmit(skb,dev,SOPRI_NORMAL);
if(addr_len <sizeof(*usipx))
return(-EINVAL);
if(usipx->sipx_family != AF_IPX)
return -EINVAL;
if(htons(usipx->sipx_port)<0x4000 && !suser())
return -EPERM;
ipx.net=usipx->sipx_network;
ipx.sock=usipx->sipx_port;
memcpy(ipx.node,usipx->sipx_node, sizeof(ipx.node));
return (ipx_do_sendto(sk, &ipx, ubuf, len, 1,
usipx->sipx_type));
}
else
{
if(sk->state!=TCP_ESTABLISHED)
return -ENOTCONN;
return (ipx_do_sendto(sk, &(sk->ipx_dest_addr), ubuf,
len, 1, sk->ipx_type));
}
return len;
}
static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
{
......@@ -1142,7 +1778,7 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
int copied = 0;
struct sk_buff *skb;
int er;
if(sk->err)
{
er= -sk->err;
......@@ -1170,12 +1806,14 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
sipx->sipx_type = ipx->ipx_type;
}
skb_free_datagram(skb);
return(copied);
}
static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock)
{
return ipx_send(sock,ubuf,size,noblock,0);
}
......
/*
*
* Kernel support for NCP
*
* Mark Evans 1994
*
*/
#ifndef _NCP_H
#define _NCP_H
#include <linux/ncp.h>
struct ncp_info
{
unsigned short conn; /* connection number */
unsigned char seq; /* sequence number */
ipx_socket *ncp; /* ncp socket */
ipx_socket *watchdog; /* watchdog socket */
ipx_socket *mail; /* mail socket */
};
#define NCP_TIMEOUT (3*HZ)
#define MAX_TIMEOUT 15
#endif /* _NCP_H */
......@@ -41,6 +41,7 @@
#endif
#ifdef CONFIG_IPX
#include "ipx.h"
#include "ncp.h"
#endif
#define SOCK_ARRAY_SIZE 64
......@@ -137,6 +138,7 @@ struct sock {
#ifdef CONFIG_IPX
ipx_address ipx_source_addr,ipx_dest_addr;
unsigned short ipx_type;
struct ncp_info ncp;
#endif
#ifdef CONFIG_AX25
/* Really we want to add a per protocol private area */
......
......@@ -592,7 +592,8 @@ static int sock_socket(int family, int type, int protocol)
if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
type != SOCK_SEQPACKET && type != SOCK_RAW &&
type != SOCK_PACKET) || protocol < 0)
type != SOCK_PACKET && type != SOCK_NCP)
|| protocol < 0)
return(-EINVAL);
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment