VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 15
+SUBLEVEL = 16
ARCH = i386
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
- bool ' 16 channels instead of 4' SL_SLIP_LOTS n
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
if [ "$CONFIG_PPP" = "y" ]; then
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
- bool ' 16 channels instead of 4' SL_SLIP_LOTS n
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
if [ "$CONFIG_PPP" = "y" ]; then
char x86_vendor_id[13] = "Unknown";
char ignore_irq13 = 0; /* set if exception 16 works */
-char wp_works_ok = 0; /* set if paging hardware honours WP */
+char wp_works_ok = -1; /* set if paging hardware honours WP */
char hlt_works_ok = 1; /* set if the "hlt" instruction works */
/*
*/
#if 0
memset((void *) 0, 0, PAGE_SIZE);
+#endif
+#ifdef CONFIG_TEST_VERIFY_AREA
+ wp_works_ok = 0;
#endif
start_mem = PAGE_ALIGN(start_mem);
address = 0;
pg_dir = swapper_pg_dir;
while (address < end_mem) {
+#ifdef CONFIG_PENTIUM_MM
+ if (address <= end_mem + 4*1024*1024 &&
+ (x86_capability & 8)) {
+#ifdef GAS_KNOWS_CR4
+ __asm__("movl %%cr4,%%eax\n\t"
+ "orl $16,%%eax\n\t"
+ "movl %%eax,%%cr4"
+ : : :"ax");
+#else
+ __asm__(".byte 0x0f,0x20,0xe0\n\t"
+ "orl $16,%%eax\n\t"
+ ".byte 0x0f,0x22,0xe0"
+ : : :"ax");
+#endif
+ wp_works_ok = 1;
+ pgd_val(pg_dir[0]) = _PAGE_TABLE | _PAGE_4M | address;
+ pgd_val(pg_dir[768]) = _PAGE_TABLE | _PAGE_4M | address;
+ pg_dir++;
+ address += 4*1024*1024;
+ continue;
+ }
+#endif
/* map the memory at virtual addr 0xC0000000 */
pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
if (!pg_table) {
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10));
/* test if the WP bit is honoured in supervisor mode */
- wp_works_ok = -1;
- pg0[0] = pte_val(mk_pte(0, PAGE_READONLY));
- invalidate();
- __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory");
- pg0[0] = 0;
- invalidate();
- if (wp_works_ok < 0)
- wp_works_ok = 0;
-#ifdef CONFIG_TEST_VERIFY_AREA
- wp_works_ok = 0;
-#endif
+ if (wp_works_ok < 0) {
+ pg0[0] = pte_val(mk_pte(0, PAGE_READONLY));
+ invalidate();
+ __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory");
+ pg0[0] = 0;
+ invalidate();
+ if (wp_works_ok < 0)
+ wp_works_ok = 0;
+ }
return;
}
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
- bool ' 16 channels instead of 4' SL_SLIP_LOTS n
# bool ' SLIP debugging on' SL_DUMP y
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
bool 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" = "y" ]; then
bool ' CSLIP compressed headers' SL_COMPRESSED y
- bool ' 16 channels instead of 4' SL_SLIP_LOTS n
# bool ' SLIP debugging on' SL_DUMP y
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
extern long rd_init(long mem_start, int length);
extern int ramdisk_size;
+#ifdef CONFIG_BLK_DEV_XD
extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
+#endif
#define RO_IOCTLS(dev,where) \
case BLKROSET: if (!suser()) return -EACCES; \
static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
{
- int i, minor = current_minor, tested_for_dm6 = 0;
+ int i, minor = current_minor;
struct buffer_head *bh;
struct partition *p;
int mask = (1 << hd->minor_shift) - 1;
+#ifdef CONFIG_BLK_DEV_IDE
+ int tested_for_dm6 = 0;
read_mbr:
+#endif
if (!(bh = bread(dev,0,1024))) {
printk(" unable to read partition table\n");
return -1;
NR_HD = hdind+1;
}
-static void dump_status (char *msg, unsigned int stat)
+static void dump_status (const char *msg, unsigned int stat)
{
unsigned long flags;
char devc;
bswap = 1;
if (cmd == WIN_PIDENTIFY) {
if ((id->model[0] == 'N' && id->model[1] == 'E')
- || (id->model[0] == 'F' && id->model[1] == 'X'))
- bswap = 0; /* NEC and *some* Mitsumi units */
+ || (id->model[0] == 'F' && id->model[1] == 'X')
+ || (id->model[0] == 'P' && id->model[1] == 'i'))
+ bswap = 0; /* NEC, Pioneer and *some* Mitsumi units */
} /* Vertos drives may still be weird */
fixstring (id->model, sizeof(id->model), bswap);
fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
extern void vesa_blank(void);
extern void vesa_unblank(void);
extern void compute_shiftstate(void);
-extern int conv_uni_to_pc(long ucs);
extern void reset_palette (int currcons) ;
extern void set_palette (void) ;
extern void change_console(unsigned int new_console);
extern void scrollback(int);
extern void scrollfront(int);
-extern int vc_cons_allocated(unsigned int);
#ifdef __i386__
#define fake_keyboard_interrupt() __asm__ __volatile__("int $0x21")
#include <asm/segment.h>
#include <asm/bitops.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <time.h>
#include <linux/kernel.h>
-long scc_init(long kmem_start);
-
int scc_open(struct tty_struct *tty, struct file *filp);
static void scc_close(struct tty_struct *tty, struct file *filp);
int scc_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
#define CHECK_TTY_COUNT
extern void do_blank_screen(int nopowersave);
-extern void do_unblank_screen(void);
extern void set_vesa_blanking(const unsigned long arg);
struct termios tty_std_termios; /* for the benefit of tty drivers */
#include "selection.h"
extern struct tty_driver console_driver;
-extern int sel_cons;
#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count)
#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
extern void complete_change_console(unsigned int new_console);
extern int vt_waitactive(void);
extern void do_blank_screen(int nopowersave);
-extern void do_unblank_screen(void);
extern unsigned int keymap_count;
#endif /* PLIP */
#if defined(SLIP) || defined(CONFIG_SLIP)
- extern int slip_init(struct device *);
-
-#ifdef SL_SLIP_LOTS
-
- static struct device slip15_dev={"sl15",0,0,0,0,15,0,0,0,0,NEXT_DEV,slip_init};
- static struct device slip14_dev={"sl14",0,0,0,0,14,0,0,0,0,&slip15_dev,slip_init};
- static struct device slip13_dev={"sl13",0,0,0,0,13,0,0,0,0,&slip14_dev,slip_init};
- static struct device slip12_dev={"sl12",0,0,0,0,12,0,0,0,0,&slip13_dev,slip_init};
- static struct device slip11_dev={"sl11",0,0,0,0,11,0,0,0,0,&slip12_dev,slip_init};
- static struct device slip10_dev={"sl10",0,0,0,0,10,0,0,0,0,&slip11_dev,slip_init};
- static struct device slip9_dev={"sl9",0,0,0,0,9,0,0,0,0,&slip10_dev,slip_init};
- static struct device slip8_dev={"sl8",0,0,0,0,8,0,0,0,0,&slip9_dev,slip_init};
- static struct device slip7_dev={"sl7",0,0,0,0,7,0,0,0,0,&slip8_dev,slip_init};
- static struct device slip6_dev={"sl6",0,0,0,0,6,0,0,0,0,&slip7_dev,slip_init};
- static struct device slip5_dev={"sl5",0,0,0,0,5,0,0,0,0,&slip6_dev,slip_init};
- static struct device slip4_dev={"sl4",0,0,0,0,4,0,0,0,0,&slip5_dev,slip_init};
-# undef NEXT_DEV
-# define NEXT_DEV (&slip4_dev)
-#endif /* SL_SLIP_LOTS */
-
- static struct device slip3_dev = {
- "sl3", /* Internal SLIP driver, channel 3 */
- 0x0, /* recv memory end */
- 0x0, /* recv memory start */
- 0x0, /* memory end */
- 0x0, /* memory start */
- 0x3, /* base I/O address */
- 0, /* IRQ */
- 0, 0, 0, /* flags */
- NEXT_DEV, /* next device */
- slip_init /* slip_init should set up the rest */
- };
- static struct device slip2_dev = {
- "sl2", /* Internal SLIP driver, channel 2 */
- 0x0, /* recv memory end */
- 0x0, /* recv memory start */
- 0x0, /* memory end */
- 0x0, /* memory start */
- 0x2, /* base I/O address */
- 0, /* IRQ */
- 0, 0, 0, /* flags */
- &slip3_dev, /* next device */
- slip_init /* slip_init should set up the rest */
- };
- static struct device slip1_dev = {
- "sl1", /* Internal SLIP driver, channel 1 */
- 0x0, /* recv memory end */
- 0x0, /* recv memory start */
- 0x0, /* memory end */
- 0x0, /* memory start */
- 0x1, /* base I/O address */
- 0, /* IRQ */
- 0, 0, 0, /* flags */
- &slip2_dev, /* next device */
- slip_init /* slip_init should set up the rest */
- };
- static struct device slip0_dev = {
- "sl0", /* Internal SLIP driver, channel 0 */
- 0x0, /* recv memory end */
- 0x0, /* recv memory start */
- 0x0, /* memory end */
- 0x0, /* memory start */
- 0x0, /* base I/O address */
- 0, /* IRQ */
- 0, 0, 0, /* flags */
- &slip1_dev, /* next device */
- slip_init /* slip_init should set up the rest */
- };
-# undef NEXT_DEV
-# define NEXT_DEV (&slip0_dev)
+ /* To be exact, this node just hooks the initialization
+ routines to the device structures. */
+extern int slip_init_ctrl_dev(struct device *);
+static struct device slip_bootstrap = {
+ "slip_proto", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, slip_init_ctrl_dev, };
+#undef NEXT_DEV
+#define NEXT_DEV (&slip_bootstrap)
#endif /* SLIP */
#if defined(CONFIG_PPP)
# define NEXT_DEV (&ibmtr_dev1)
- extern int tok_probe(struct device *dev);
static struct device ibmtr_dev0 = {
"tr0", /* IBM Token Ring (Non-DMA) Interface */
0x0, /* recv memory end */
/* The inverse routine to net_open(). */
static int net_close(struct device *dev)
{
- struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
dev->tbusy = 1;
/* Read the station address PROM. */
get_node_ID(dev);
- printk("%s: Pocket adapter found at %#3x, IRQ %d, SAPROM "
+ printk("%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
"%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
}
/*
** Set or clear the multicast filter for this adaptor.
-** num_addrs == -1 Promiscuous mode, receive all packets - not supported.
-** Use the ioctls.
+** num_addrs == -1 Promiscuous mode, receive all packets - now supported.
+** Can also use the ioctls.
** num_addrs == 0 Normal mode, clear multicast list
** num_addrs > 0 Multicast mode, receive normal and MC packets, and do
** best-effort filtering.
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
dev->trans_start = jiffies;
+ } else { /* set promiscuous mode */
+ u32 omr;
+ omr = inl(DE4X5_OMR);
+ omr |= OMR_PR;
+ outl(omr, DE4X5_OMR);
}
}
}
}
}
+
+ if (num_addrs == 0)
+ omr &= ~OMR_PR;
outl(omr, DE4X5_OMR);
return;
*
* Variable Description
*
- * hp100_default_rx_ratio Range 1-99 - onboard memory used for RX
+ * hp100_rx_ratio Range 1-99 - onboard memory used for RX
* packets in %.
+ * hp100_priority_tx If this variable is nonzero - all outgoing
+ * packets will be transmitted as priority.
* hp100_port Adapter port (for example 0x380).
*
* ----------------------------------------------------------------------------
* TO DO:
* ======
* - ioctl handling - some runtime setup things
- * - high priority communications support
- * - memory mapped access support for PCI cards
+ * - 100Mb/s Voice Grade AnyLAN network adapter/hub services support
+ * - 802.5 frames
+ * - promiscuous mode
+ * - bridge mode
+ * - cascaded repeater mode
+ * - 100Mbit MAC
*
* Revision history:
* =================
* 0.12 14-Jul-95 Link down is now handled better.
* 0.20 01-Aug-95 Added PCI support for HP J2585A card.
* Statistics bug fixed.
+ * 0.21 04-Aug-95 Memory mapped access support for PCI card.
+ * Added priority transmit support for 100Mb/s
+ * Voice Grade AnyLAN network.
*
*/
#define HP100_MAX_PACKET_SIZE (1536+4)
#define HP100_MIN_PACKET_SIZE 60
-#ifndef HP100_RX_RATIO
+#ifndef HP100_DEFAULT_RX_RATIO
/* default - 65% onboard memory on the card are used for RX packets */
-#define HP100_RX_RATIO 65
+#define HP100_DEFAULT_RX_RATIO 65
+#endif
+
+#ifndef HP100_DEFAULT_PRIORITY_TX
+/* default - don't enable transmit outgoing packets as priority */
+#define HP100_DEFAULT_PRIORITY_TX 0
#endif
/*
struct hp100_eisa_id *id;
u_short soft_model;
u_int memory_size;
- u_short rx_ratio;
+ u_short rx_ratio; /* 1 - 99 */
+ u_short priority_tx; /* != 0 - priority tx */
short mem_mapped; /* memory mapped access */
- u_char *mem_ptr; /* pointer to memory mapped area */
+ u_char *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
+ u_char *mem_ptr_phys; /* physical memory mapped area */
short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
int hub_status; /* login to hub was successfull? */
u_char mac1_mode;
{ 0x01030103c, "HP J2585", HP100_BUS_PCI },
};
-#ifdef MODULE
-int hp100_default_rx_ratio = HP100_RX_RATIO;
-#endif
+int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
+int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
/*
* prototypes
u_char uc, uc_1;
u_int eisa_id;
short mem_mapped;
- u_char *mem_ptr;
+ u_char *mem_ptr_phys, *mem_ptr_virt;
struct hp100_private *lp;
struct hp100_eisa_id *eid;
hp100_page( HW_MAP );
mem_mapped = ( hp100_inw( OPTION_LSW ) &
( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) ) != 0;
- mem_ptr = NULL;
+ mem_ptr_phys = mem_ptr_virt = NULL;
if ( mem_mapped )
{
- mem_ptr = (u_char *)( hp100_inw( MEM_MAP_LSW ) |
- ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
- (u_int)mem_ptr &= ~0x1fff; /* 8k aligment */
- if ( bus == HP100_BUS_ISA && ( (u_int)mem_ptr & ~0xfffff ) != 0 )
+ mem_ptr_phys = (u_char *)( hp100_inw( MEM_MAP_LSW ) |
+ ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
+ (u_int)mem_ptr_phys &= ~0x1fff; /* 8k aligment */
+ if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 )
{
- mem_ptr = NULL;
+ mem_ptr_phys = NULL;
mem_mapped = 0;
}
if ( mem_mapped && bus == HP100_BUS_PCI )
{
-#if 0
- printk( "writeb !!!\n" );
- writeb( 0, mem_ptr );
-#endif
- mem_ptr = NULL;
- mem_mapped = 0;
+ if ( ( mem_ptr_virt = vremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL )
+ {
+ printk( "hp100: vremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys );
+ mem_ptr_phys = NULL;
+ mem_mapped = 0;
+ }
}
}
#else
mem_mapped = 0;
- mem_ptr = NULL;
+ mem_ptr_phys = mem_ptr_virt = NULL;
#endif
if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL )
lp = (struct hp100_private *)dev -> priv;
lp -> id = eid;
lp -> mem_mapped = mem_mapped;
- lp -> mem_ptr = mem_ptr;
+ lp -> mem_ptr_phys = mem_ptr_phys;
+ lp -> mem_ptr_virt = mem_ptr_virt;
hp100_page( ID_MAC_ADDR );
lp -> soft_model = hp100_inb( SOFT_MODEL );
lp -> mac1_mode = HP100_MAC1MODE3;
dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK;
if ( dev -> irq == 2 ) dev -> irq = 9;
lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 );
-#ifndef MODULE
- lp -> rx_ratio = HP100_RX_RATIO;
-#else
- lp -> rx_ratio = hp100_default_rx_ratio;
-#endif
+ lp -> rx_ratio = hp100_rx_ratio;
dev -> open = hp100_open;
dev -> stop = hp100_close;
printk( " bus, %dk SRAM (rx/tx %d%%).\n",
lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio );
if ( mem_mapped )
- printk( "%s: Memory mapped access used at 0x%x-0x%x.\n",
- dev -> name, (u_int)mem_ptr, (u_int)mem_ptr + 0x1fff );
+ {
+ printk( "%s: Memory area at 0x%lx-0x%lx",
+ dev -> name, (u_long)mem_ptr_phys, (u_long)mem_ptr_phys + 0x1fff );
+ if ( mem_ptr_virt )
+ printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
+ printk( ".\n" );
+ }
printk( "%s: ", dev -> name );
if ( lp -> lan_type != HP100_LAN_ERR )
printk( "Adapter is attached to " );
HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB |
HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW );
-#if 0
- hp100_outw( HP100_PRIORITY_TX | HP100_ADV_NXT_PKT |
- HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
-#else
- hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
-#endif
+ hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB |
+ HP100_PRIORITY_TX | ( hp100_priority_tx ? HP100_SET_HB : HP100_RESET_HB ),
+ OPTION_MSW );
hp100_page( MAC_ADDRESS );
for ( i = 0; i < 6; i++ )
static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
{
- int i;
+ int i, ok_flag;
int ioaddr = dev -> base_addr;
u_short val;
struct hp100_private *lp = (struct hp100_private *)dev -> priv;
#ifdef HP100_DEBUG_TX
printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len );
#endif
+ ok_flag = skb -> len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb -> len : HP100_MIN_PACKET_SIZE;
+ hp100_outw( i, DATA32 ); /* length to memory manager */
+ hp100_outw( i, FRAGMENT_LEN );
if ( lp -> mem_mapped )
{
- if ( skb -> len >= HP100_MIN_PACKET_SIZE )
+ if ( lp -> mem_ptr_virt )
{
- hp100_outw( skb -> len, DATA32 ); /* length to memory manager */
- hp100_outw( skb -> len, FRAGMENT_LEN );
- memcpy_toio( lp -> mem_ptr, skb -> data, skb -> len );
+ memcpy( lp -> mem_ptr_virt, skb -> data, skb -> len );
+ if ( !ok_flag )
+ memset( lp -> mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb -> len );
}
else
{
- hp100_outw( HP100_MIN_PACKET_SIZE, DATA32 ); /* length to memory manager */
- hp100_outw( HP100_MIN_PACKET_SIZE, FRAGMENT_LEN );
- memcpy_toio( lp -> mem_ptr, skb -> data, skb -> len );
- memset_io( lp -> mem_ptr, 0, HP100_MIN_PACKET_SIZE - skb -> len );
+ memcpy_toio( lp -> mem_ptr_phys, skb -> data, skb -> len );
+ if ( !ok_flag )
+ memset_io( lp -> mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb -> len );
}
}
else
{
- if ( skb -> len >= HP100_MIN_PACKET_SIZE )
- {
- hp100_outw( skb -> len, DATA32 ); /* length to memory manager */
- hp100_outw( skb -> len, FRAGMENT_LEN );
- outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
- }
- else
- {
- hp100_outw( HP100_MIN_PACKET_SIZE, DATA32 ); /* length to memory manager */
- hp100_outw( HP100_MIN_PACKET_SIZE, FRAGMENT_LEN );
- i = skb -> len + 3;
- outsl( ioaddr + HP100_REG_DATA32, skb -> data, i >> 2 );
- for ( i &= ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
- hp100_outl( 0, DATA32 );
- }
+ outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
+ if ( !ok_flag )
+ for ( i = ( skb -> len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
+ hp100_outl( 0, DATA32 );
}
hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
lp -> stats.tx_packets++;
printk( "hp100_rx: busy, remaining packets = %d\n", packets );
#endif
}
- header = lp -> mem_mapped ? readl( lp -> mem_ptr ) : hp100_inl( DATA32 );
+ if ( lp -> mem_mapped )
+ {
+ if ( lp -> mem_ptr_virt )
+ header = *(__u32 *)lp -> mem_ptr_virt;
+ else
+ header = readl( lp -> mem_ptr_phys );
+ }
+ else
+ header = hp100_inl( DATA32 );
pkt_len = header & HP100_PKT_LEN_MASK;
#ifdef HP100_DEBUG_RX
printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n",
skb -> dev = dev;
ptr = (u_char *)skb_put( skb, pkt_len );
if ( lp -> mem_mapped )
- memcpy_fromio( ptr, lp -> mem_ptr, ( pkt_len + 3 ) & ~3 );
+ {
+ if ( lp -> mem_ptr_virt )
+ memcpy( ptr, lp -> mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
+ else
+ memcpy_fromio( ptr, lp -> mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
+ }
else
insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
skb -> protocol = eth_type_trans( skb, dev );
lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */
}
else
- {
+ {
lp -> mac2_mode = HP100_MAC2MODE3; /* normal mode, packets for me */
lp -> mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
}
int init_module( void )
{
- if ( hp100_port > 0 ) dev_hp100.base_addr = hp100_port;
- if ( register_netdev( &dev_hp100 ) != 0 ) return -EIO;
+ if ( hp100_port > 0 )
+ dev_hp100.base_addr = hp100_port;
+ if ( register_netdev( &dev_hp100 ) != 0 )
+ return -EIO;
return 0;
}
{
unregister_netdev( &dev_hp100 );
release_region( dev_hp100.base_addr, HP100_REGION_SIZE );
+ if ( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt )
+ vfree( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt );
kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
dev_hp100.priv = NULL;
}
ti->page_mask=0;
if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */
ti->mapped_ram_size = ti->avail_shared_ram;
- } else { unsigned char pg_size;
+ } else {
+#ifdef ENABLE_PAGING
+ unsigned char pg_size;
+#endif
DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
#ifdef ENABLE_PAGING
printk("lance.c: PCI bios is present, checking for devices...\n");
for (pci_index = 0; pci_index < 8; pci_index++) {
unsigned char pci_bus, pci_device_fn;
- unsigned long pci_ioaddr;
+ unsigned int pci_ioaddr;
unsigned short pci_command;
if (pcibios_find_device (PCI_VENDOR_ID_AMD,
pcibios_write_config_word(pci_bus, pci_device_fn,
PCI_COMMAND, pci_command);
}
- printk("Found PCnet/PCI at %#lx, irq %d (mem_start is %#lx).\n",
+ printk("Found PCnet/PCI at %#x, irq %d (mem_start is %#lx).\n",
pci_ioaddr, pci_irq_line, mem_start);
mem_start = lance_probe1(pci_ioaddr, mem_start);
pci_irq_line = 0;
printk("unregister_netdev: device ");
- if (dev == NULL) {
+ if (dev == NULL)
+ {
printk("was NULL\n");
restore_flags(flags);
return;
}
/* else */
if (dev->start)
- printk("'%s' busy\n", dev->name);
- else {
- if (dev_base == dev)
- dev_base = dev->next;
- else {
- while (d && (d->next != dev))
- d = d->next;
-
- if (d && (d->next == dev)) {
- d->next = dev->next;
- printk("'%s' unlinked\n", dev->name);
- }
- else {
- printk("'%s' not found\n", dev->name);
- restore_flags(flags);
- return;
- }
+ printk("ERROR '%s' busy and not MOD_IN_USE.\n", dev->name);
+ if (dev_base == dev)
+ dev_base = dev->next;
+ else
+ {
+ while (d && (d->next != dev))
+ d = d->next;
+
+ if (d && (d->next == dev))
+ {
+ d->next = dev->next;
+ printk("'%s' unlinked\n", dev->name);
+ }
+ else
+ {
+ printk("'%s' not found\n", dev->name);
+ restore_flags(flags);
+ return;
}
- for (i = 0; i < MAX_ETH_CARDS; ++i) {
- if (ethdev_index[i] == dev) {
+ for (i = 0; i < MAX_ETH_CARDS; ++i)
+ {
+ if (ethdev_index[i] == dev)
+ {
ethdev_index[i] = NULL;
break;
}
printk("%s: scb_cmd timed out .. resetting i82586\n",dev->name); \
ni_reset586(); } } }
-extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
-extern void *irq2dev_map[16];
#define NI52_TOTAL_SIZE 16
#define NI52_ADDR0 0x02
|| dev->dev_addr[2] != NI52_ADDR2)
return ENODEV;
- printk("%s: Ni52 found at %#3x, ",dev->name,dev->base_addr);
+ printk("%s: Ni52 found at %#3lx, ",dev->name,dev->base_addr);
request_region(ioaddr,NI52_TOTAL_SIZE,"ni52");
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-extern void *irq2dev_map[16];
-
struct priv
{
struct init_block ib;
if(dev->dma == 0)
dev->dma = dmatab[inw(PORT+L_CONFIG)&3];
- printk("%s: %s found at %#3x, IRQ %d DMA %d.\n", dev->name,
+ printk("%s: %s found at %#3lx, IRQ %d DMA %d.\n", dev->name,
"network card", dev->base_addr, dev->irq,dev->dma);
{
/* IRQ map used to reserve a IRQ (see SK_open()) */
-extern void *irq2dev_map[16];
+/* extern void *irq2dev_map[16]; */ /* Declared in <linux/ioport.h> */
/* static variables */
else
{
printk("## %s: Device Structure. %s\n", SK_NAME, text);
- printk("## Device Name: %s Base Address: %#06x IRQ: %d\n",
+ printk("## Device Name: %s Base Address: %#06lx IRQ: %d\n",
dev->name, dev->base_addr, dev->irq);
- printk("## FLAGS: start: %d tbusy: %d int: %d\n",
+ printk("## FLAGS: start: %d tbusy: %ld int: %d\n",
dev->start, dev->tbusy, dev->interrupt);
printk("## next device: %#08x init function: %#08x\n",
* if it really needed.
* Alan Cox : Free slhc buffers in the right place.
* Alan Cox : Allow for digipeated IP over AX.25
+ * Matti Aarnio : Dynamic SLIP devices, with ideas taken
+ * from Jim Freeman's <jfree@caldera.com>
+ * dynamic PPP devices. We do NOT kfree()
+ * device entries, just reg./unreg. them
+ * as they are needed. We kfree() them
+ * at module cleanup.
+ * With MODULE-loading ``insmod'', user can
+ * issue parameter: slip_maxdev=1024
+ * (Or how much he/she wants.. Default is 256)
*
- *
- *
- * FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
- * CONFIG_INET defined.
- * I hope now it is fixed ;)
*/
#define SL_CHECK_TRANSMIT
#endif
-static struct slip sl_ctrl[SL_NRUNIT];
+typedef struct slip_ctrl {
+ char if_name[8]; /* "sl0\0" .. "sl99999\0" */
+ struct slip ctrl; /* SLIP things */
+ struct device dev; /* the device */
+} slip_ctrl_t;
+static slip_ctrl_t **slip_ctrls = NULL;
+int slip_maxdev = SL_NRUNIT; /* Can be overridden with insmod! */
+
static struct tty_ldisc sl_ldisc;
-static int already = 0;
static int slip_esc(unsigned char *p, unsigned char *d, int len);
static void slip_unesc(struct slip *sl, unsigned char c);
static inline struct slip *
sl_alloc(void)
{
- struct slip *sl;
+ slip_ctrl_t *slp;
int i;
- for (i = 0; i < SL_NRUNIT; i++) {
- sl = &sl_ctrl[i];
- if (!set_bit(SLF_INUSE, &sl->flags)) {
- return sl;
- }
+ if (slip_ctrls == NULL) return NULL; /* Master array missing ! */
+
+ for (i = 0; i < slip_maxdev; i++) {
+ slp = slip_ctrls[i];
+ /* Not allocated ? */
+ if (slp == NULL)
+ break;
+ /* Not in use ? */
+ if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+ break;
+ }
+ /* SLP is set.. */
+
+ /* Sorry, too many, all slots in use */
+ if (i >= slip_maxdev) return NULL;
+
+ /* If no channels are available, allocate one */
+ if (!slp &&
+ (slip_ctrls[i] = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t),
+ GFP_KERNEL)) != NULL) {
+ slp = slip_ctrls[i];
+ memset(slp, 0, sizeof(slip_ctrl_t));
+
+ /* Initialize channel control data */
+ set_bit(SLF_INUSE, &slp->ctrl.flags);
+ slp->ctrl.tty = NULL;
+ sprintf(slp->if_name, "sl%d", i);
+ slp->dev.name = slp->if_name;
+ slp->dev.base_addr = i;
+ slp->dev.priv = (void*)&(slp->ctrl);
+ slp->dev.next = NULL;
+ slp->dev.init = slip_init;
+/* printk(KERN_INFO "slip: kmalloc()ed SLIP control node for line %s\n",
+ slp->if_name); */
}
+ if (slp != NULL) {
+
+ /* register device so that it can be ifconfig'ed */
+ /* slip_init() will be called as a side-effect */
+ /* SIDE-EFFECT WARNING: slip_init() CLEARS slp->ctrl ! */
+
+ if (register_netdev(&(slp->dev)) == 0) {
+ /* (Re-)Set the INUSE bit. Very Important! */
+ set_bit(SLF_INUSE, &slp->ctrl.flags);
+ slp->ctrl.dev = &(slp->dev);
+ slp->dev.priv = (void*)&(slp->ctrl);
+
+/* printk(KERN_INFO "slip: linked in netdev %s for active use\n",
+ slp->if_name); */
+
+ return (&(slp->ctrl));
+
+ } else {
+ clear_bit(SLF_INUSE,&(slp->ctrl.flags));
+ printk("sl_alloc() - register_netdev() failure.\n");
+ }
+ }
+
return NULL;
}
}
}
-/* MTU has been changed by the IP layer. Unfortunately we are not told about this, but
- we spot it ourselves and fix things up. We could be in an upcall from the tty
- driver, or in an ip packet queue. */
+/* MTU has been changed by the IP layer. Unfortunately we are not told
+ about this, but we spot it ourselves and fix things up. We could be
+ in an upcall from the tty driver, or in an ip packet queue. */
static void sl_changedmtu(struct slip *sl)
{
static int
sl_xmit(struct sk_buff *skb, struct device *dev)
{
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
if (!dev->start) {
printk("%s: xmit call when iface is down\n", dev->name);
{
#ifdef CONFIG_AX25
#ifdef CONFIG_INET
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
if (((sl->mode & SL_MODE_AX25) || (sl->mode & SL_MODE_AX25VC)) && type != htons(ETH_P_AX25)) {
return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
{
#ifdef CONFIG_AX25
#ifdef CONFIG_INET
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
if ((sl->mode & SL_MODE_AX25) || (sl->mode & SL_MODE_AX25VC)) {
return ax25_rebuild_header(buff, dev, raddr, skb);
static int
sl_open(struct device *dev)
{
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
unsigned long len;
if (sl->tty == NULL) {
static int
sl_close(struct device *dev)
{
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
if (sl->tty == NULL) {
return -EBUSY;
tty->disc_data = 0;
sl->tty = NULL;
sl_free(sl);
+ unregister_netdev(sl->dev);
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
sl_get_stats(struct device *dev)
{
static struct enet_statistics stats;
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
#ifdef SL_INCLUDE_CSLIP
struct slcompress *comp;
#endif
int sl_get_ax25_mode(struct device *dev)
{
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
return sl->mode & SL_MODE_AX25VC;
}
static int sl_open_dev(struct device *dev)
{
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
if(sl->tty==NULL)
return -ENODEV;
return 0;
}
+/* Initialize SLIP control device -- register SLIP line discipline */
+#ifdef MODULE
+static int slip_init_ctrl_dev()
+#else /* !MODULE */
+int
+slip_init_ctrl_dev(struct device *dummy)
+#endif /* !MODULE */
+{
+ int status;
+
+ if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */
+
+ printk("SLIP: version %s (dynamic channels, max=%d)"
+#ifdef CONFIG_SLIP_MODE_SLIP6
+ " (6 bit encapsulation enabled)"
+#endif
+ "\n",
+ SLIP_VERSION, slip_maxdev );
+#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)
+ printk("CSLIP: code copyright 1989 Regents of the University of California\n");
+#endif
+#ifdef CONFIG_AX25
+ printk("AX25: KISS encapsulation enabled\n");
+#endif
+
+ slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL);
+ if (slip_ctrls == NULL) {
+ printk("SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n");
+ return -ENOMEM;
+ }
+
+ /* Clear the pointer array, we allocate devices when we need them */
+ memset(slip_ctrls, 0, sizeof(void*)*slip_maxdev); /* Pointers */
+
+ /* Fill in our line protocol discipline, and register it */
+ memset(&sl_ldisc, 0, sizeof(sl_ldisc));
+ sl_ldisc.magic = TTY_LDISC_MAGIC;
+ sl_ldisc.flags = 0;
+ sl_ldisc.open = slip_open;
+ sl_ldisc.close = slip_close;
+ sl_ldisc.read = NULL;
+ sl_ldisc.write = NULL;
+ sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *,
+ unsigned int, unsigned long)) slip_ioctl;
+ sl_ldisc.select = NULL;
+ sl_ldisc.receive_buf = slip_receive_buf;
+ sl_ldisc.receive_room = slip_receive_room;
+ sl_ldisc.write_wakeup = slip_write_wakeup;
+ if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
+ printk("SLIP: can't register line discipline (err = %d)\n", status);
+ }
+
+
+ /* If not loadable module, a bootstrap Space.c slip_proto dev
+ * now needs to be unregistered.
+ */
+#ifndef MODULE
+ printk("SLIP: Unregistering bootstrap device "
+ "'slip_proto' - slip OK\n");
+ unregister_netdev(dummy);
+#endif
+ return status;
+ }
+
+
/* Initialize the SLIP driver. Called by DDI. */
int
slip_init(struct device *dev)
{
- struct slip *sl = &sl_ctrl[dev->base_addr];
+ struct slip *sl = (struct slip*)(dev->priv);
int i;
#ifdef CONFIG_AX25
static char ax25_bcast[AX25_ADDR_LEN] =
{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
#endif
- if (already++ == 0) {
- printk("SLIP: version %s (%d channels) %s\n",
- SLIP_VERSION, SL_NRUNIT,
-#ifdef CONFIG_SLIP_MODE_SLIP6
- "(6 bit encapsulation enabled)"
-#else
- ""
-#endif
- );
-#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)
- printk("CSLIP: code copyright 1989 Regents of the University of California\n");
-#endif
-#ifdef CONFIG_AX25
- printk("AX25: KISS encapsulation enabled\n");
-#endif
- /* Fill in our LDISC request block. */
- memset(&sl_ldisc, 0, sizeof(sl_ldisc));
- sl_ldisc.magic = TTY_LDISC_MAGIC;
- sl_ldisc.flags = 0;
- sl_ldisc.open = slip_open;
- sl_ldisc.close = slip_close;
- sl_ldisc.read = NULL;
- sl_ldisc.write = NULL;
- sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *,
- unsigned int, unsigned long)) slip_ioctl;
- sl_ldisc.select = NULL;
- sl_ldisc.receive_buf = slip_receive_buf;
- sl_ldisc.receive_room = slip_receive_room;
- sl_ldisc.write_wakeup = slip_write_wakeup;
- if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
- printk("SLIP: can't register line discipline (err = %d)\n", i);
- }
- }
+ if (sl == NULL) /* Allocation failed ?? */
+ return -ENODEV;
/* Set up the "SLIP Control Block". (And clear statistics) */
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
-static struct device dev_slip[SL_NRUNIT] = {
- {
- "sl0", /* slip */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, slip_init,
- },
- { "sl1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, slip_init },
- { "sl2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, slip_init },
- { "sl3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, slip_init },
-#ifdef SL_SLIP_LOTS
- { "sl4" , 0, 0, 0, 0, 4, 0, 0, 0, 0, NULL, slip_init },
- { "sl5" , 0, 0, 0, 0, 5, 0, 0, 0, 0, NULL, slip_init },
- { "sl6" , 0, 0, 0, 0, 6, 0, 0, 0, 0, NULL, slip_init },
- { "sl7" , 0, 0, 0, 0, 7, 0, 0, 0, 0, NULL, slip_init },
- { "sl8" , 0, 0, 0, 0, 8, 0, 0, 0, 0, NULL, slip_init },
- { "sl9" , 0, 0, 0, 0, 9, 0, 0, 0, 0, NULL, slip_init },
- { "sl10", 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, slip_init },
- { "sl11", 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, slip_init },
- { "sl12", 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, slip_init },
- { "sl13", 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, slip_init },
- { "sl14", 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, slip_init },
- { "sl15", 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, slip_init },
-#endif /* SL_SLIP_LOTS */
-};
-
int
init_module(void)
{
- int err;
- int i;
-
- for (i = 0; i < SL_NRUNIT; i++) {
- if ((err = register_netdev(&dev_slip[i]))) {
- if (err == -EEXIST) {
- printk("SLIP: devices already present. Module not loaded.\n");
- }
- return err;
- }
- }
- return 0;
+ return slip_init_ctrl_dev();
}
void
printk("SLIP: device busy, remove delayed\n");
return;
}
- for (i = 0; i < SL_NRUNIT; i++) {
- unregister_netdev(&dev_slip[i]);
+ if (slip_ctrls != NULL) {
+ for (i = 0; i < slip_maxdev; i++) {
+ if (slip_ctrls[i] != NULL) {
+ unregister_netdev(&(slip_ctrls[i]->dev));
+ kfree(slip_ctrls[i]);
+ }
+ }
+ kfree(slip_ctrls);
+ slip_ctrls = NULL;
}
if ((i = tty_register_ldisc(N_SLIP, NULL))) {
- printk("SLIP: can't unregister line discipline (err = %d)\n", i);
+ printk("SLIP: can't unregister line discipline (err = %d)\n", i);
}
- already = 0;
}
#endif /* MODULE */
#endif
/* SLIP configuration. */
-#ifndef SL_SLIP_LOTS
-#define SL_NRUNIT 4 /* number of SLIP channels */
-#else
-#define SL_NRUNIT 16
-#endif
+#define SL_NRUNIT 256 /* MAX number of SLIP channels;
+ This can be overridden with
+ insmod -oslip_maxdev=nnn */
#define SL_MTU 296 /* 296; I am used to 600- FvK */
/* SLIP protocol characters. */
dev->base_addr = netinfo->iobase1;
dev->irq = netinfo->irq1;
- printk(KERN_INFO "%s: ZNET at %#3x,", dev->name, dev->base_addr);
+ printk(KERN_INFO "%s: ZNET at %#3lx,", dev->name, dev->base_addr);
/* The station address is in the "netidblk" at 0x0f0000. */
for (i = 0; i < 6; i++)
int ioaddr = dev->base_addr;
if (znet_debug > 4)
- printk(KERN_DEBUG "%s: ZNet_send_packet(%d).\n", dev->name, dev->tbusy);
+ printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy);
/* Transmitter timeout, likely just recovery after suspending the machine. */
if (dev->tbusy) {
DEVICE( INTEL, INTEL_82371, "82471 Triton"),
DEVICE( INTEL, INTEL_82438, "82438"),
DEVICE( INTEL, INTEL_7116, "SAA7116"),
+ DEVICE( INTEL, INTEL_82865, "82865"),
DEVICE( SMC, SMC_37C665, "FDC 37C665"),
DEVICE( ATI, ATI_M32, "Mach 32"),
DEVICE( ATI, ATI_M64, "Mach 64"),
DEVICE( AL, AL_M1445, "M1445"),
DEVICE( AL, AL_M1449, "M1449"),
DEVICE( AL, AL_M1451, "M1451"),
+ DEVICE( AL, AL_M1461, "M1461"),
DEVICE( AL, AL_M4803, "M4803"),
DEVICE( TSENG, TSENG_W32P_2, "ET4000W32P"),
DEVICE( TSENG, TSENG_W32P_b, "ET4000W32P rev B"),
case PCI_CLASS_STORAGE_IDE: return "IDE controller";
case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller";
case PCI_CLASS_STORAGE_IPI: return "IPI bus controller";
+ case PCI_CLASS_STORAGE_RAID: return "RAID bus controller";
case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller";
case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller";
case PCI_CLASS_NETWORK_TOKEN_RING: return "Token ring network controller";
case PCI_CLASS_NETWORK_FDDI: return "FDDI network controller";
+ case PCI_CLASS_NETWORK_ATM: return "ATM network controller";
case PCI_CLASS_NETWORK_OTHER: return "Network controller";
case PCI_CLASS_DISPLAY_VGA: return "VGA compatible controller";
case PCI_CLASS_BRIDGE_MC: return "MicroChannel bridge";
case PCI_CLASS_BRIDGE_PCI: return "PCI bridge";
case PCI_CLASS_BRIDGE_PCMCIA: return "PCMCIA bridge";
+ case PCI_CLASS_BRIDGE_NUBUS: return "NuBus bridge";
+ case PCI_CLASS_BRIDGE_CARDBUS: return "CardBus bridge";
case PCI_CLASS_BRIDGE_OTHER: return "Bridge";
+ case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial controller";
+ case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel controller";
+ case PCI_CLASS_COMMUNICATION_OTHER: return "Communication controller";
+
+ case PCI_CLASS_SYSTEM_PIC: return "PIC";
+ case PCI_CLASS_SYSTEM_DMA: return "DMA controller";
+ case PCI_CLASS_SYSTEM_TIMER: return "Timer";
+ case PCI_CLASS_SYSTEM_RTC: return "RTC";
+ case PCI_CLASS_SYSTEM_OTHER: return "System peripheral";
+
+ case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard controller";
+ case PCI_CLASS_INPUT_PEN: return "Digitizer Pen";
+ case PCI_CLASS_INPUT_MOUSE: return "Mouse controller";
+ case PCI_CLASS_INPUT_OTHER: return "Input device controller";
+
+ case PCI_CLASS_DOCKING_GENERIC: return "Generic Docking Station";
+ case PCI_CLASS_DOCKING_OTHER: return "Docking Station";
+
+ case PCI_CLASS_PROCESSOR_386: return "386";
+ case PCI_CLASS_PROCESSOR_486: return "486";
+ case PCI_CLASS_PROCESSOR_PENTIUM: return "Pentium";
+ case PCI_CLASS_PROCESSOR_ALPHA: return "Alpha";
+ case PCI_CLASS_PROCESSOR_POWERPC: return "Power PC";
+ case PCI_CLASS_PROCESSOR_CO: return "Co-processor";
+
+ case PCI_CLASS_SERIAL_FIREWIRE: return "FireWire (IEEE 1394)";
+ case PCI_CLASS_SERIAL_ACCESS: return "ACCESS Bus";
+ case PCI_CLASS_SERIAL_SSA: return "SSA";
+ case PCI_CLASS_SERIAL_FIBER: return "Fiber Channel";
+
default: return "Unknown class";
}
}
/* For PCMCIA cards, always use AUTOCONF */
#if defined(PCMCIA) || defined(MODULE)
+#if !defined(AUTOCONF)
#define AUTOCONF
#endif
+#endif
/* If auto configuration is disabled, IRQ, SCSI_ID and RECONNECT have to
be predefined */
sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
#ifdef AIC7XXX_DEBUG
-extern int vsprintf(char *, const char *, va_list);
static void
debug(const char *fmt, ...)
#if defined(MODULE) && !defined(GFP_DMA)
# define CHECK_DMA_ADDR(isa, addr, badstmt) \
- do { if ((isa) && (addr) > (void *)ISA_DMA_THRESHOLD) badstmt; } while (0)
+ do { if ((isa) && ((const void *)addr) > (const void *)ISA_DMA_THRESHOLD) badstmt; } while (0)
#else
# define CHECK_DMA_ADDR(isa, addr, badstmt)
#endif
#ifndef _CONSTANTS_H
#define _CONSTANTS_H
-extern void print_command(unsigned char *);
extern int print_msg(unsigned char *);
-/* extern void print_sense(const char *, Scsi_Cmnd *); */
extern void print_status(int);
extern void print_Scsi_Cmnd (Scsi_Cmnd *);
#endif /* def _CONSTANTS_H */
-extern void proc_print_scsidevice(Scsi_Device *scd, char *buffer,
- int *size, int len);
-
void swap_statistics(u8 *p)
{
* Cambridge, MA 02139, USA. *
* *
************************************************************
- * last change: 95/07/13 OS: Linux 1.3.9 *
+ * last change: 95/08/04 OS: Linux 1.3.15 *
************************************************************/
/* Look in eata_pio.h for configuration information */
static unchar reg_IRQL[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static uint internal_command_finished = TRUE;
-
static ulong int_counter = 0;
static ulong queue_counter = 0;
hptr3[z*2]=' ';
}
-void eata_pio_scsi_done (Scsi_Cmnd * SCpnt)
-{
- return;
-}
#include "eata_pio_proc.c"
cp->status = FREE; /* now we can release the slot */
restore_flags(flags);
- if(cmd->scsi_done != eata_pio_scsi_done) cmd->scsi_done(cmd);
- else internal_command_finished = TRUE;
+ cmd->scsi_done(cmd);
save_flags(flags);
cli();
}
queue_counter++;
- if (done == (void *)eata_pio_scsi_done) {
- if (internal_command_finished == TRUE)
- internal_command_finished = FALSE;
- else
- cmd->result = (DID_ERROR << 16) + QUEUE_FULL;
- }
-
hd = HD(cmd);
sh = cmd->host;
base = (uint) sh->base;
cp->DataIn = TRUE; /* Input mode */
}
- cp->Interpret = (cmd->target==hd->hostid);
- cp->cp_datalen=htonl((ulong)cmd->request_bufflen);
+ cp->Interpret = (cmd->target == hd->hostid);
+ cp->cp_datalen = htonl((ulong)cmd->request_bufflen);
cp->Auto_Req_Sen = FALSE;
cp->cp_reqDMA = htonl(0);
cp->reqlen = 0;
cp->cmd = cmd;
cmd->host_scribble = (char *)&hd->ccb[y];
- if (cmd->use_sg==0)
+ if (cmd->use_sg == 0)
{
cmd->SCp.buffers_residual=1;
- cmd->SCp.ptr=cmd->request_buffer;
- cmd->SCp.this_residual=cmd->request_bufflen;
- cmd->SCp.buffer=NULL;
- }
- else
- {
- cmd->SCp.buffer=cmd->request_buffer;
- cmd->SCp.buffers_residual=cmd->use_sg;
- cmd->SCp.ptr=cmd->SCp.buffer->address;
- cmd->SCp.this_residual=cmd->SCp.buffer->length;
+ cmd->SCp.ptr = cmd->request_buffer;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ cmd->SCp.buffer = NULL;
+ } else {
+ cmd->SCp.buffer = cmd->request_buffer;
+ cmd->SCp.buffers_residual = cmd->use_sg;
+ cmd->SCp.ptr = cmd->SCp.buffer->address;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
}
- cmd->SCp.Status=(cmd->SCp.this_residual!=0); /* TRUE as long as bytes
- are to transfer */
+ cmd->SCp.Status = (cmd->SCp.this_residual != 0); /* TRUE as long as bytes
+ * are to transfer */
if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
{
cmd->result = DID_ERROR << 16;
- printk("eata_pio_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
- cmd->target, cmd->pid);
+ printk("eata_pio_queue target %d, pid %ld, HBA busy, returning "
+ "DID_ERROR, done.\n", cmd->target, cmd->pid);
restore_flags(flags);
- if(done != (void *)eata_pio_scsi_done) done(cmd);
+ done(cmd);
return (0);
}
while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
outsw(base + HA_RDATA, cp, hd->cplen);
outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
- for (x=0; x<hd->cppadlen; x++) outw(0, base + HA_RDATA);
+ for (x = 0; x < hd->cppadlen; x++) outw(0, base + HA_RDATA);
DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x "
"slot %d irq %d\n", (long)sh->base, cmd->pid,
save_flags(flags);
cli();
- DBG(DBG_ABNORM, printk("eata_pio_abort called pid: %ld target: %x lun: %x reason %x\n",
- cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+ DBG(DBG_ABNORM, printk("eata_pio_abort called pid: %ld target: %x lun: %x"
+ " reason %x\n", cmd->pid, cmd->target, cmd->lun,
+ cmd->abort_reason));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
cp.cp_cdb[4] = 254;
cp.cp_cdb[5] = 0;
- if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP)) return (NULL);
+ if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP))
+ return (NULL);
while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
outsw(base + HA_RDATA, &cp, cplen);
outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
- for (z=0; z<cppadlen; z++) outw(0, base + HA_RDATA);
+ for (z = 0; z < cppadlen; z++) outw(0, base + HA_RDATA);
while (inb(base + HA_RSTATUS) & HA_SBUSY);
if (inb(base + HA_RSTATUS) & HA_SERROR)
else
{
insw(base+HA_RDATA, &buff, 127);
- while (inb(base+HA_RSTATUS)&HA_SDRQ) inw(base+HA_RDATA);
+ while (inb(base + HA_RSTATUS)&HA_SDRQ) inw(base + HA_RDATA);
return (buff);
}
}
loop = R_LIMIT;
for (p = (ushort *) buf;
- (long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
+ (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
if (--loop == 0)
return (FALSE);
#endif
printk("eata_pio: executing controller self test & setup...\n");
- while (inb(base+HA_RSTATUS)&HA_SBUSY);
- outb(EATA_CMD_PIO_SETUPTEST,base+HA_WCOMMAND);
+ while (inb(base + HA_RSTATUS) & HA_SBUSY);
+ outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND);
do {
- while (inb(base+HA_RSTATUS)&HA_SBUSY)
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
/* nothing */ ;
- if (inb(base+HA_RSTATUS)&HA_SDRQ)
+ if (inb(base + HA_RSTATUS) & HA_SDRQ)
{
- insw(base+HA_RDATA,&buffer,256);
+ insw(base + HA_RDATA, &buffer, 256);
#ifdef VERBOSE_SETUP
/* no beeps please... */
- for (z=0; z < 511 && buffer[z]; z++)
+ for (z = 0; z < 511 && buffer[z]; z++)
if (buffer[z] != 7) printk("%c", buffer[z]);
#endif
}
- } while (inb(base+HA_RSTATUS)&(HA_SBUSY|HA_SDRQ));
+ } while (inb(base+HA_RSTATUS) & (HA_SBUSY|HA_SDRQ));
- return (!(inb(base+HA_RSTATUS)&HA_SERROR));
+ return (!(inb(base+HA_RSTATUS) & HA_SERROR));
}
int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
SD(sh)->revision[3] = '.';
SD(sh)->revision[4] = buff[35];
SD(sh)->revision[5] = 0;
+
switch (ntohl(gc->len)) {
case 0x1c:
SD(sh)->EATA_revision = 'a';
case 0x22:
SD(sh)->EATA_revision = 'c';
break;
+ case 0x24:
+ SD(sh)->EATA_revision = 'z';
default:
SD(sh)->EATA_revision = '?';
}
+
+ if(ntohl(gc->len) >= 0x22) {
+ if (gc->is_PCI == TRUE)
+ hd->bustype = IS_PCI;
+ else if (gc->is_EISA == TRUE)
+ hd->bustype = IS_EISA;
+ else
+ hd->bustype = IS_ISA;
+ } else {
+ if (buff[21] == '4')
+ hd->bustype = IS_PCI;
+ else if (buff[21] == '2')
+ hd->bustype = IS_EISA;
+ else
+ hd->bustype = IS_ISA;
+ }
+
SD(sh)->cplen=cplen;
SD(sh)->cppadlen=cppadlen;
SD(sh)->hostid=gc->scsi_id[3];
hd->channel = 0;
- if(ntohl(gc->len) >= 0x22) {
- if (gc->is_PCI == TRUE)
- hd->bustype = IS_PCI;
- else if (gc->is_EISA == TRUE)
- hd->bustype = IS_EISA;
- else
- hd->bustype = IS_ISA;
- } else {
- if (buff[21] == '4')
- hd->bustype = IS_PCI;
- else if (buff[21] == '2')
- hd->bustype = IS_EISA;
- else
- hd->bustype = IS_ISA;
- }
-
sh->max_id = 8;
sh->max_lun = 8;
VER_MAJOR, VER_MINOR, VER_SUB);
printk("Registered HBAs:\n");
- printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr: QS: SG: CPL:\n");
+ printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:"
+ " QS: SG: CPL:\n");
for (i = 1; i <= registered_HBAs; i++) {
- printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %d %d %c %2d %2d %2d\n",
+ printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %d %d %c"
+ " %2d %2d %2d\n",
HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
"PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
- (uint) HBA_ptr->base, HBA_ptr->irq,
- SD(HBA_ptr)->channel, HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
- HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+ (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel,
+ HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
+ HBA_ptr->can_queue, HBA_ptr->sg_tablesize,
+ HBA_ptr->cmd_per_lun);
HBA_ptr = SD(HBA_ptr)->next;
}
}
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_SUB "1a"
+#define VER_SUB "1b"
/************************************************************************
* Here you can switch parts of the code on and of *
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
- * indent-tabs-mode: nil
* tab-width: 8
* End:
*/
/*
* eata_proc_info
- * inout : decides on the direction of the dataflow and the meaning of the variables
+ * inout : decides on the direction of the dataflow and the meaning of the
+ * variables
* buffer: If inout==FALSE data is beeing written to it else read from it
* *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file
+ * from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer
+ * else number of bytes in the buffer
*/
-int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
{
Scsi_Device *scd;
struct Scsi_Host *HBA_ptr;
static u8 buff[512];
- int i, x;
+ int i;
int size, len = 0;
off_t begin = 0;
off_t pos = 0;
while (scd) {
if (scd->host == HBA_ptr) {
-
- size = sprintf(buffer + len, "Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
- scd->channel, scd->id, scd->lun);
- for (x = 0; x < 8; x++) {
- if (scd->vendor[x] >= 0x20)
- size += sprintf(buffer + len + size, "%c", scd->vendor[x]);
- else
- size += sprintf(buffer + len + size," ");
- }
- size += sprintf(buffer + len + size, " Model: ");
- for (x = 0; x < 16; x++) {
- if (scd->model[x] >= 0x20)
- size += sprintf(buffer + len + size, "%c", scd->model[x]);
- else
- size += sprintf(buffer + len + size, " ");
- }
- size += sprintf(buffer + len + size, " Rev: ");
- for (x = 0; x < 4; x++) {
- if (scd->rev[x] >= 0x20)
- size += sprintf(buffer + len + size, "%c", scd->rev[x]);
- else
- size += sprintf(buffer + len + size, " ");
- }
- size += sprintf(buffer + len + size, "\n");
-
- size += sprintf(buffer + len + size, " Type: %s ",
- scd->type < MAX_SCSI_DEVICE_CODE ?
- pio_scsi_dev_types[(int)scd->type] : "Unknown " );
- size += sprintf(buffer + len + size, " ANSI"
- " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
- if (scd->scsi_level == 2)
- size += sprintf(buffer + len + size, " CCS\n");
- else
- size += sprintf(buffer + len + size, "\n");
+ proc_print_scsidevice(scd, buffer, &size, len);
len += size;
pos = begin + len;
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
- * indent-tabs-mode: nil
* tab-width: 8
* End:
*/
+
unsigned int scsi_init(void);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
extern void scsi_unregister(struct Scsi_Host * i);
-extern int scsicam_bios_param (Disk *, int, int *);
#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
extern int dispatch_scsi_info(int ino, char *buffer, char **start,
off_t offset, int length, int inout);
-extern void proc_print_scsidevice(Scsi_Device *scd, char *buffer,
- int *size, int len);
/*
* As the scsi do command functions are intelligent, and may need to
extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
-extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
-extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern void print_command(unsigned char *);
extern void print_sense(const char *, Scsi_Cmnd *);
switch(cmd_in)
{
case SG_SET_TIMEOUT:
- result = verify_area(VERIFY_READ, arg, sizeof(long));
+ result = verify_area(VERIFY_READ, (const void *)arg, sizeof(long));
if (result) return result;
scsi_generics[dev].timeout=get_user((int *) arg);
/* In fact, it is very slow if it has to spin up first */
#define IOCTL_TIMEOUT 3000
-extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
-
static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
{
struct request * req;
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_elf_library(int fd);
-extern int aout_core_dump(long signr, struct pt_regs * regs);
static int elf_core_dump(long signr, struct pt_regs * regs);
extern int dump_fpu (elf_fpregset_t *);
bh->b_dirt=0;
bh->b_lock=0;
bh->b_uptodate=0;
- bh->b_flushtime = 0;
+ bh->b_flushtime=0;
bh->b_req=0;
+ bh->b_reuse=0;
bh->b_dev=dev;
bh->b_blocknr=block;
insert_into_queues(bh);
if (--buf->b_count)
return;
wake_up(&buffer_wait);
+ if (buf->b_reuse) {
+ if (!buf->b_lock && !buf->b_dirt && !buf->b_wait) {
+ buf->b_reuse = 0;
+ if(buf->b_dev == 0xffff) panic("brelse: Wrong list");
+ remove_from_queues(buf);
+ buf->b_dev = 0xffff;
+ put_last_free(buf);
+ }
+ }
return;
}
printk("VFS: brelse: Trying to free free buffer\n");
memset(bh->b_data, RANDOM_INT, inode->i_sb->s_blocksize);
mark_buffer_dirty(bh, 1);
}
+ else if (bh) {
+ mark_buffer_clean(bh);
+ bh->b_reuse = 1;
+ }
brelse (bh);
if (free_count == 0) {
block_to_free = tmp;
memset(bh->b_data, RANDOM_INT, inode->i_sb->s_blocksize);
mark_buffer_dirty(bh, 1);
}
+ else if (bh) {
+ mark_buffer_clean(bh);
+ bh->b_reuse = 1;
+ }
brelse (bh);
if (free_count == 0) {
block_to_free = tmp;
if (ind_bh->b_count != 1)
retry = 1;
else {
+ ind_bh->b_reuse = 1;
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
if (dind_bh->b_count != 1)
retry = 1;
else {
+ dind_bh->b_reuse = 1;
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
if (tind_bh->b_count != 1)
retry = 1;
else {
+ tind_bh->b_reuse = 1;
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
#include <linux/string.h>
#include <linux/mm.h>
-struct file * first_file;
+/*
+ * first_file points to a doubly linked list of all file structures in
+ * the system.
+ * nr_files holds the length of this list.
+ */
+struct file * first_file = NULL;
int nr_files = 0;
+/*
+ * Insert a new file structure at the head of the list of available ones.
+ */
static void insert_file_free(struct file *file)
{
+ file->f_count = 0;
file->f_next = first_file;
file->f_prev = first_file->f_prev;
file->f_next->f_prev = file;
first_file = file;
}
+/*
+ * Remove a file structure from the list of available ones.
+ */
static void remove_file_free(struct file *file)
{
if (first_file == file)
first_file = first_file->f_next;
- if (file->f_next)
- file->f_next->f_prev = file->f_prev;
- if (file->f_prev)
- file->f_prev->f_next = file->f_next;
+ file->f_next->f_prev = file->f_prev;
+ file->f_prev->f_next = file->f_next;
file->f_next = file->f_prev = NULL;
}
+/*
+ * Insert a file structure at the end of the list of available ones.
+ */
static void put_last_free(struct file *file)
{
- remove_file_free(file);
file->f_prev = first_file->f_prev;
file->f_prev->f_next = file;
file->f_next = first_file;
file->f_next->f_prev = file;
}
-void grow_files(void)
+/*
+ * Allocate a new memory page for file structures and
+ * insert the new structures into the global list.
+ * Returns 0, if there is no more memory, 1 otherwise.
+ */
+static int grow_files(void)
{
struct file * file;
int i;
- file = (struct file *) get_free_page(GFP_KERNEL);
+ /*
+ * We don't have to clear the page because we only look into
+ * f_count, f_prev and f_next and they get initialized in
+ * insert_file_free. The rest of the file structure is cleared
+ * by get_empty_filp before it is returned.
+ */
+ file = (struct file *) __get_free_page(GFP_KERNEL);
if (!file)
- return;
+ return 0;
- nr_files+=i= PAGE_SIZE/sizeof(struct file);
+ nr_files += i = PAGE_SIZE/sizeof(struct file);
if (!first_file)
- file->f_next = file->f_prev = first_file = file++, i--;
+ file->f_count = 0,
+ file->f_next = file->f_prev = first_file = file++,
+ i--;
for (; i ; i--)
insert_file_free(file++);
+
+ return 1;
}
unsigned long file_table_init(unsigned long start, unsigned long end)
{
- first_file = NULL;
return start;
}
+/*
+ * Find an unused file structure and return a pointer to it.
+ * Returns NULL, if there are no more free file structures or
+ * we run out of memory.
+ */
struct file * get_empty_filp(void)
{
int i;
struct file * f;
- if (!first_file)
- grow_files();
-repeat:
- for (f = first_file, i=0; i < nr_files; i++, f = f->f_next)
- if (!f->f_count) {
- remove_file_free(f);
- memset(f,0,sizeof(*f));
- put_last_free(f);
- f->f_count = 1;
- f->f_version = ++event;
- return f;
- }
- if (nr_files < NR_FILE) {
- grow_files();
- goto repeat;
- }
+ /* if the return is taken, we are in deep trouble */
+ if (!first_file && !grow_files())
+ return NULL;
+
+ do {
+ for (f = first_file, i=0; i < nr_files; i++, f = f->f_next)
+ if (!f->f_count) {
+ remove_file_free(f);
+ memset(f,0,sizeof(*f));
+ put_last_free(f);
+ f->f_count = 1;
+ f->f_version = ++event;
+ return f;
+ }
+ } while (nr_files < NR_FILE && grow_files());
+
return NULL;
}
}
*p = 0;
inode->i_dirt = 1;
- brelse(bh);
+ if (bh) {
+ mark_buffer_clean(bh);
+ brelse(bh);
+ }
minix_free_block(inode->i_sb,tmp);
}
return retry;
#include <asm/segment.h>
-extern int *blksize_size[];
-
void msdos_put_inode(struct inode *inode)
{
struct inode *depend;
extern void locks_remove_locks(struct task_struct *, struct file *);
-asmlinkage int sys_ustat(int dev, struct ustat * ubuf)
-{
- return -ENOSYS;
-}
-
asmlinkage int sys_statfs(const char * path, struct statfs * buf)
{
struct inode * inode;
extern int close_fp(struct file *filp);
-int smb_notify_change(struct inode *, struct iattr *);
static void smb_put_inode(struct inode *);
static void smb_read_inode(struct inode *);
static void smb_put_super(struct super_block *);
#define LO_WORD(l) ((word)(l % 0xFFFF))
void smb_printerr(int class, int num);
-int smb_request(struct smb_server *);
static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
/*****************************************************************************/
sb->s_op->put_super(sb);
}
+asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf)
+{
+ struct super_block *s;
+ struct ustat tmp;
+ struct statfs sbuf;
+ unsigned long old_fs;
+ int error;
+
+ s = get_super(dev);
+ if (s == NULL)
+ return -EINVAL;
+
+ if (!(s->s_op->statfs))
+ return -ENOSYS;
+
+ error = verify_area(VERIFY_WRITE,ubuf,sizeof(struct ustat));
+ if (error)
+ return error;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ s->s_op->statfs(s,&sbuf,sizeof(struct statfs));
+ set_fs(old_fs);
+
+ memset(&tmp,0,sizeof(struct ustat));
+ tmp.f_tfree = sbuf.f_bfree;
+ tmp.f_tinode = sbuf.f_ffree;
+
+ memcpy_tofs(ubuf,&tmp,sizeof(struct ustat));
+ return 0;
+}
+
static struct super_block * read_super(dev_t dev,const char *name,int flags,
void *data, int silent)
{
#include <linux/fs.h>
#include <linux/sysv_fs.h>
#include <linux/stat.h>
+#include <linux/string.h>
static int sysv_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
while (umsdos_waitcreate (dir) != 0);
dir->u.umsdos_i.u.dir_info.looking++;
}
-void check_page_tables(void);
/*
Unlock the directory.
#endif
+/*
+ * TLB invalidation:
+ *
+ * - invalidate() invalidates the current task TLBs
+ * - invalidate_all() invalidates all processes TLBs
+ * - invalidate_task(task) invalidates the specified tasks TLB's
+ * - invalidate_page(task, vmaddr) invalidates one page
+ *
+ * ..but the i386 has somewhat limited invalidation capabilities.
+ */
#define invalidate() \
__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
+#define invalidate_all() invalidate()
+#define invalidate_task(task) \
+do { if ((task)->mm == current->mm) invalidate(); } while (0)
+#define invalidate_page(task,addr) \
+do { if ((task)->mm == current->mm) invalidate(); } while (0)
+
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
#ifndef _I386_PGTABLE_H
#define _I386_PGTABLE_H
+/*
+ * Define CONFIG_PENTIUM_MM if you want the 4MB page table optimizations.
+ * This works only on a intel Pentium.
+ */
+#define CONFIG_PENTIUM_MM 1
+
/*
* The Linux memory management assumes a three-level page table setup. On
* the i386, we use that, but "fold" the mid level into the top-level page
#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
+/*
+ * The 4MB page is guessing.. Detailed in the infamous "Chapter H"
+ * of the Pentium details, but assuming intel did the straigtforward
+ * thing, this bit set in the page directory entry just means that
+ * the page directory entry points directly to a 4MB-aligned block of
+ * memory.
+ */
#define _PAGE_PRESENT 0x001
#define _PAGE_RW 0x002
#define _PAGE_USER 0x004
#define _PAGE_PCD 0x010
#define _PAGE_ACCESSED 0x020
#define _PAGE_DIRTY 0x040
+#define _PAGE_4M 0x080 /* 4 MB page, Pentium+.. */
#define _PAGE_COW 0x200 /* implemented in software (one of the AVL bits) */
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
__asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \
} while (0)
-extern unsigned long high_memory;
-
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] != 1; }
extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; }
+#ifdef CONFIG_PENTIUM_MM
+extern inline int pmd_inuse(pmd_t *pmdp) { return (pmd_val(*pmdp) & _PAGE_4M) != 0; }
+#else
extern inline int pmd_inuse(pmd_t *pmdp) { return 0; }
+#endif
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
extern inline void pmd_reuse(pmd_t * pmdp) { }
*/
extern inline void pmd_free_kernel(pmd_t * pmd)
{
+ pmd_val(*pmd) = 0;
}
extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
*/
extern inline void pmd_free(pmd_t * pmd)
{
+ pmd_val(*pmd) = 0;
}
extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
return __res;
}
-extern char * ___strtok;
-
#define __HAVE_ARCH_STRTOK
extern inline char * strtok(char * s,const char * ct)
{
extern void eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
extern void eth_copy_and_sum(struct sk_buff *dest,
unsigned char *src, int length, int base);
-extern void eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
+
#endif
unsigned char b_lock; /* 0 - ok, 1 -locked */
unsigned char b_req; /* 0 if the buffer has been invalidated */
unsigned char b_list; /* List that this buffer appears */
- unsigned char b_retain; /* Expected number of times this will
- be used. Put on freelist when 0 */
+ unsigned char b_reuse; /* 0 - normal, 1 - better reused for something else */
unsigned long b_flushtime; /* Time when this (dirty) buffer should be written */
unsigned long b_lru_time; /* Time when this buffer was last used. */
struct wait_queue * b_wait;
#define IP_FW_F_TCPSYN 0x080 /* For tcp packets-check SYN only */
#define IP_FW_F_ICMPRPL 0x100 /* Send back icmp unreachable packet */
#define IP_FW_F_MASQ 0x200 /* Masquerading */
-#define IP_FW_F_MASK 0x3FF /* All possible flag bits mask */
+#define IP_FW_F_TCPACK 0x400 /* For tcp-packets match if ACK is set*/
+#define IP_FW_F_MASK 0x7FF /* All possible flag bits mask */
/*
* New IP firewall options for [gs]etsockopt at the RAW IP level.
/* vmalloc.c */
extern void * vmalloc(unsigned long size);
+extern void * vremap(unsigned long offset, unsigned long size);
extern void vfree(void * addr);
extern int vread(char *buf, char *addr, int count);
#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */
#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */
#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
+#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
+#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
typedef enum {
char *optval, int *optlen);
int (*fcntl) (struct socket *sock, unsigned int cmd,
unsigned long arg);
+ int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, int nonblock, int flags);
+ int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int nonblock, int flags, int *addr_len);
};
struct net_proto {
extern void dev_init(void);
+/* Locking protection for page faults during outputs to devices unloaded during the fault */
+
+extern int dev_lockct;
+
+/*
+ * These two dont currently need to be interrupt safe
+ * but they may do soon. Do it properly anyway.
+ */
+
+extern __inline__ void dev_lock_list(void)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ dev_lockct++;
+ restore_flags(flags);
+}
+
+extern __inline__ void dev_unlock_list(void)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ dev_lockct--;
+ restore_flags(flags);
+}
+
+/*
+ * This almost never occurs, isnt in performance critical paths
+ * and we can thus be relaxed about it
+ */
+
+extern __inline__ void dev_lock_wait(void)
+{
+ while(dev_lockct)
+ schedule();
+}
+
+
/* These functions live elsewhere (drivers/net/net_init.c, but related) */
extern void ether_setup(struct device *dev);
#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features */
+
#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
#define PCI_BASE_ADDRESS_IO_MASK (~0x03)
/* bit 1 is reserved if address_space = 1 */
-/* 0x28-0x2f are reserved */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_ID 0x2c
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2e
#define PCI_ROM_ADDRESS 0x30 /* 32 bits */
#define PCI_ROM_ADDRESS_ENABLE 0x01 /* Write 1 to enable ROM,
bits 31..11 are address,
#define PCI_CLASS_STORAGE_IDE 0x0101
#define PCI_CLASS_STORAGE_FLOPPY 0x0102
#define PCI_CLASS_STORAGE_IPI 0x0103
+#define PCI_CLASS_STORAGE_RAID 0x0104
#define PCI_CLASS_STORAGE_OTHER 0x0180
#define PCI_BASE_CLASS_NETWORK 0x02
#define PCI_CLASS_NETWORK_ETHERNET 0x0200
#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
#define PCI_CLASS_NETWORK_FDDI 0x0202
+#define PCI_CLASS_NETWORK_ATM 0x0203
#define PCI_CLASS_NETWORK_OTHER 0x0280
#define PCI_BASE_CLASS_DISPLAY 0x03
#define PCI_CLASS_BRIDGE_MC 0x0603
#define PCI_CLASS_BRIDGE_PCI 0x0604
#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
+#define PCI_CLASS_BRIDGE_NUBUS 0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
#define PCI_CLASS_BRIDGE_OTHER 0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION 0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
+
+#define PCI_BASE_CLASS_SYSTEM 0x08
+#define PCI_CLASS_SYSTEM_PIC 0x0800
+#define PCI_CLASS_SYSTEM_DMA 0x0801
+#define PCI_CLASS_SYSTEM_TIMER 0x0802
+#define PCI_CLASS_SYSTEM_RTC 0x0803
+#define PCI_CLASS_SYSTEM_OTHER 0x0880
+
+#define PCI_BASE_CLASS_INPUT 0x09
+#define PCI_CLASS_INPUT_KEYBOARD 0x0900
+#define PCI_CLASS_INPUT_PEN 0x0901
+#define PCI_CLASS_INPUT_MOUSE 0x0902
+#define PCI_CLASS_INPUT_OTHER 0x0980
+
+#define PCI_BASE_CLASS_DOCKING 0x0a
+#define PCI_CLASS_DOCKING_GENERIC 0x0a00
+#define PCI_CLASS_DOCKING_OTHER 0x0a01
+
+#define PCI_BASE_CLASS_PROCESSOR 0x0b
+#define PCI_CLASS_PROCESSOR_386 0x0b00
+#define PCI_CLASS_PROCESSOR_486 0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
+#define PCI_CLASS_PROCESSOR_CO 0x0b40
+
+#define PCI_BASE_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+
#define PCI_CLASS_OTHERS 0xff
#define PCI_DEVICE_ID_INTEL_82371 0x122e
#define PCI_DEVICE_ID_INTEL_82438 0x1230
#define PCI_DEVICE_ID_INTEL_7116 0x1223
+#define PCI_DEVICE_ID_INTEL_82865 0x1227
#define PCI_VENDOR_ID_SMC 0x1042
#define PCI_DEVICE_ID_SMC_37C665 0x1000
#define PCI_DEVICE_ID_AL_M1445 0x1445
#define PCI_DEVICE_ID_AL_M1449 0x1449
#define PCI_DEVICE_ID_AL_M1451 0x1451
+#define PCI_DEVICE_ID_AL_M1461 0x1461
#define PCI_DEVICE_ID_AL_M4803 0x5215
#define PCI_VENDOR_ID_TSENG 0x100c
#define FDA 0x40 /* FIFO Data Available Status */
#define FOY 0x80 /* FIFO Overflow Status */
-#endif /* _SCC_H */
-
/* global functions */
extern long scc_init(long kmem_start);
+
+#endif /* _SCC_H */
#include <asm/socket.h> /* arch-dependent defines */
#include <linux/sockios.h> /* the SIOCxxx I/O controls */
-
+#include <linux/uio.h> /* iovec support */
struct sockaddr {
unsigned short sa_family; /* address family, AF_xxx */
int l_linger; /* How long to linger for */
};
+struct msghdr
+{
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ int msg_iovlen; /* Number of blocks */
+ void * msg_accrights; /* Per protocol magic (eg BSD file descriptor passing) */
+ int msg_accrightslen; /* Length of rights list */
+};
+
/* Socket types. */
#define SOCK_STREAM 1 /* stream (connection) socket */
#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
#define SOPRI_NORMAL 1
#define SOPRI_BACKGROUND 2
+#ifdef __KERNEL__
+extern void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
+extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
+extern void memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
+extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
+extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
+#endif
#endif /* _LINUX_SOCKET_H */
--- /dev/null
+#ifndef __LINUX_UIO_H
+#define __LINUX_UIO_H
+
+/*
+ * Berkeley style UIO structures - Alan Cox 1994.
+ *
+ * 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 of the License, or (at your option) any later version.
+ */
+
+
+/* A word of warning: Our uio structure will clash with the C library one (which is now obsolete). Remove the C
+ library one from sys/uio.h */
+
+struct iovec
+{
+ void *iov_base; /* BSD uses caddr_t (same thing in effect) */
+ int iov_len;
+};
+
+#define MAX_IOVEC 8 /* Maximum iovec's in one operation */
+
+#endif
const char *name;
} XD_SIGNATURE;
-u_long xd_init (u_long mem_start,u_long mem_end);
void xd_setup (char *command,int *integers);
static u_char xd_detect (u_char *controller,u_char **address);
static u_char xd_initdrives (void (*init_drive)(u_char drive));
--- /dev/null
+extern void unix_proto_init(struct net_proto *pro);
+
+typedef struct sock unix_socket;
+
#define SOCK_ARRAY_SIZE 256 /* Think big (also on some systems a byte is faster */
+/*
+ * The AF_UNIX specific socket options
+ */
+
+struct unix_opt
+{
+ int family;
+ char * name;
+ int locks;
+ struct inode * inode;
+ struct semaphore readsem;
+ struct sock * other;
+};
+
+
/*
* This structure really needs to be cleaned up.
* Most of it is for TCP, and not used by any of
#ifdef CONFIG_ATALK
struct atalk_sock at;
#endif
+
+/*
+ * This is where all the private (optional) areas that dont overlap will eventually live
+ * for now just AF_UNIX is here.
+ */
+
+ union
+ {
+ struct unix_opt af_unix;
+ } protinfo;
/* IP 'private area' or will be eventually */
int ip_ttl; /* TTL setting */
+++ /dev/null
-/*
- * UNIX An implementation of the AF_UNIX network domain for the
- * LINUX operating system. UNIX is implemented using the
- * BSD Socket interface as the means of communication with
- * the user level.
- *
- * This file describes some things of the UNIX protocol family
- * module. It is mainly used for the "proc" sub-module now,
- * but it may be useful for cleaning up the UNIX module as a
- * whole later.
- *
- * Version: @(#)unix.h 1.0.3 05/25/93
- *
- * Authors: Orest Zborowski, <obz@Kodak.COM>
- * Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * Fixes:
- * Dmitry Gorodchanin - proc locking
- *
- * 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 of the License, or (at your option) any later version.
- */
-
-
-#ifdef _LINUX_UN_H
-
-
-struct unix_proto_data {
- int refcnt; /* cnt of reference 0=free */
- /* -1=not initialised -bgm */
- struct socket *socket; /* socket we're bound to */
- int protocol;
- struct sockaddr_un sockaddr_un;
- short sockaddr_len; /* >0 if name bound */
- char *buf;
- int bp_head, bp_tail;
- struct inode *inode;
- struct unix_proto_data *peerupd;
- struct wait_queue *wait; /* Lock across page faults (FvK) */
- int lock_flag;
-};
-
-extern struct unix_proto_data unix_datas[NSOCKETS_UNIX];
-
-
-#define last_unix_data (unix_datas + NSOCKETS_UNIX - 1)
-
-
-#define UN_DATA(SOCK) ((struct unix_proto_data *)(SOCK)->data)
-#define UN_PATH_OFFSET ((unsigned long)((struct sockaddr_un *)0) \
- ->sun_path)
-
-/*
- * Buffer size must be power of 2. buffer mgmt inspired by pipe code.
- * note that buffer contents can wraparound, and we can write one byte less
- * than full size to discern full vs empty.
- */
-#define BUF_SIZE PAGE_SIZE
-#define UN_BUF_AVAIL(UPD) (((UPD)->bp_head - (UPD)->bp_tail) & \
- (BUF_SIZE-1))
-#define UN_BUF_SPACE(UPD) ((BUF_SIZE-1) - UN_BUF_AVAIL(UPD))
-
-#endif /* _LINUX_UN_H */
-
-
-extern void unix_proto_init(struct net_proto *pro);
envp_init[envs+1] = NULL;
}
-extern void check_bugs(void);
extern void setup_arch(char **, unsigned long *, unsigned long *);
asmlinkage void start_kernel(void)
unsigned long sec = (unsigned) value->tv_sec;
unsigned long usec = (unsigned) value->tv_usec;
- if (sec > (unsigned) (LONG_MAX / HZ))
- return LONG_MAX;
+ if (sec > (ULONG_MAX / HZ))
+ return ULONG_MAX;
usec += 1000000 / HZ - 1;
usec /= 1000000 / HZ;
return HZ*sec+usec;
static int _getitimer(int which, struct itimerval *value)
{
- register long val, interval;
+ register unsigned long val, interval;
switch (which) {
case ITIMER_REAL:
interval = current->it_real_incr;
val = 0;
if (del_timer(¤t->real_timer)) {
- val = current->real_timer.expires-jiffies;
+ unsigned long now = jiffies;
+ val = current->real_timer.expires;
add_timer(¤t->real_timer);
- if (val <= 0)
- val = interval;
+ /* look out for negative/zero itimer.. */
+ if (val <= now)
+ val = now+1;
+ val -= now;
}
break;
case ITIMER_VIRTUAL:
void it_real_fn(unsigned long __data)
{
struct task_struct * p = (struct task_struct *) __data;
+ unsigned long interval;
send_sig(SIGALRM, p, 1);
- if (p->it_real_incr) {
- p->real_timer.expires = jiffies+p->it_real_incr;
+ interval = p->it_real_incr;
+ if (interval) {
+ unsigned long timeout = jiffies + interval;
+ /* check for overflow */
+ if (timeout < interval)
+ timeout = ULONG_MAX;
+ p->real_timer.expires = timeout;
add_timer(&p->real_timer);
}
}
switch (which) {
case ITIMER_REAL:
del_timer(¤t->real_timer);
- if (j) {
- current->real_timer.expires = jiffies+j;
- add_timer(¤t->real_timer);
- }
current->it_real_value = j;
current->it_real_incr = i;
+ if (!j)
+ break;
+ i = j + jiffies;
+ /* check for overflow.. */
+ if (i < j)
+ i = ULONG_MAX;
+ current->real_timer.expires = i;
+ add_timer(¤t->real_timer);
break;
case ITIMER_VIRTUAL:
if (j)
extern void *sys_call_table;
-extern int aout_core_dump(long signr, struct pt_regs * regs);
-
#ifdef CONFIG_FTAPE
extern char * ftape_big_buffer;
#endif
#ifdef CONFIG_SCSI
#include "../drivers/scsi/scsi.h"
+#include "../drivers/scsi/scsi_ioctl.h"
#include "../drivers/scsi/hosts.h"
#include "../drivers/scsi/constants.h"
+#include <linux/scsicam.h>
extern int generic_proc_info(char *, char **, off_t, int, int, int);
#endif
X(kmalloc),
X(kfree_s),
X(vmalloc),
+ X(vremap),
X(vfree),
X(mem_map),
asmlinkage unsigned int sys_alarm(unsigned int seconds)
{
struct itimerval it_new, it_old;
+ unsigned int oldalarm;
it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
it_new.it_value.tv_sec = seconds;
it_new.it_value.tv_usec = 0;
_setitimer(ITIMER_REAL, &it_new, &it_old);
- return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000));
+ oldalarm = it_old.it_value.tv_sec;
+ /* ehhh.. We can't return 0 if we have an alarm pending.. */
+ /* And we'd better return too much than too little anyway */
+ if (it_old.it_value.tv_usec)
+ oldalarm++;
+ return oldalarm;
}
asmlinkage int sys_getpid(void)
static inline void free_one_pgd(pgd_t * dir)
{
- int j;
pmd_t * pmd;
if (pgd_none(*dir))
}
pmd = pmd_offset(dir, 0);
pgd_clear(dir);
- if (pmd_inuse(pmd)) {
- pmd_free(pmd);
- return;
+ if (!pmd_inuse(pmd)) {
+ int j;
+ for (j = 0; j < PTRS_PER_PMD ; j++)
+ free_one_pmd(pmd+j);
}
- for (j = 0; j < PTRS_PER_PMD ; j++)
- free_one_pmd(pmd+j);
pmd_free(pmd);
}
if (pmd_none(*old_pmd))
return 0;
if (pmd_bad(*old_pmd)) {
- printk("copy_one_pmd: bad page table: probable memory corruption\n");
+ printk("copy_one_pmd: bad page table (%08lx): probable memory corruption\n", pmd_val(*old_pmd));
pmd_clear(old_pmd);
return 0;
}
o Merged in the Jorge Cwik fast checksum. [TESTED]
o Added Arnt Gulbrandsen's fast UDP build. [TESTED]
-o Pauline Middelinks masquerade patch [IN/COMPILES]
+o Pauline Middelinks masquerade patch [TESTED(bar spoof bug)]
0.1
o Fixed ip_build_xmit loopback bugs [TESTED]
o Fixes for SIOCGSTAMP on SOCK_PACKET [TESTED]
o Perfect hash on net_bh(). [TESTED]
-o Sonix ISDN driver. [NOT INCLUDED YET]
+o Sonix ISDN driver. [SEPERATED/SENT]
o Use ip_build_xmit for raw sockets [TESTED]
o 3c501 fixed for speed [TESTED]
------->>>>> ALPHA 002 <<<<<--------
o TCP SWS probe fix [TESTED]
o Appletalk DDP [TESTED]
o IP firewall bug fixed [TESTED]
-o IP masquerade ftp port spoof [IN]
+o IP masquerade ftp port spoof [IN/BUG]
o gcc 2.6.3 -O3 fix for checksum assembler [TESTED]
o /proc support shows both timers [TESTED]
o TCP irtt support [TESTED]
o Missing include [TESTED]
-- Lots of people
o Can drop all source routes [TESTED]
-o Printing fixes for ip_fw [IN]
+o Printing fixes for ip_fw [TESTED]
o UDP checksum fix (Gerhard) [TESTED]
o Newer 3c505 driver from Juha Laiho [IN]
o Security fix to axassociate [TESTED]
o Merged loadable firewall code [NOT INCLUDED YET]
o New buffers used totally non optimally [TESTED]
-o Fast ip_forwarding (needs changing) [NOT INCLUDED YET]
+o Fast ip_forwarding (needs changing) [NOW INCLUDED IN 1.3.15]
o Fixed connection hang bug in new SWS code [TESTED]
o Buffer management hack putting skbuff control
after data in the frame because kmalloc is
totally cache non-optimal [TESTED]
-o Faster checksum [Tom May] [IN]
-o Appletalk router fixes [Michael Callahan] [IN]
+o Faster checksum [Tom May] [TESTED]
+o Appletalk router fixes [Michael Callahan] [TESTED]
o TCP state error fixes [Mark Tamsky] [TESTED]
o Verify area fixes [Heiko Eissfeldt] [TESTED]
-o Routes use metric field [John Naylor] [IN]
+o Routes use metric field [John Naylor] [TESTED/NOT YET AS BSD]
o Major AX.25/NetROM fixes [John Nalor] [TESTED]
------->>>>> NET3 030 <<<<<----------
o Long word align ethernet IP headers (64byte align for pentium) [TESTED]
(less helpful than I'd have liked)
o Fixed variable length header support to really work [TESTED]
-o Mend appletalk/ipx partially [IN]
+o Mend appletalk/ipx partially [TESTED]
o Start playing with input checksum & copy [TESTED]
-o Fixed PPP and other oddments [IN]
-o Mended IPIP [Might work ;)]
+o Fixed PPP and other oddments [TESTED]
+o Mended IPIP [TESTED]
------->>>>> 1.3.7 <<<<<----------
o Checksum bug fixed [TESTED]
-o Lance driver panic cured [BROKEN]
+o Lance driver panic cured [TESTED]
o DEC ALPHA stuff (Linus) [ASK HIM NOT ME]
o Always try to keep output packet order
(eg for vat and BSD fast path tcp) [TESTED]
o Copy the mac pointer in skb_clone [TESTED]
-o Fix tcpdump panic [IN]
+o Fix tcpdump panic [TESTED]
o Fix dev_alloc_skb NULL deref bug [TESTED]
o Fix Security error in SIGURG stuff [TESTED]
-o Missing 15 byte slack on ip_loopback [IN, still has mcast bugs left!]
+o Missing 15 byte slack on ip_loopback [TESTED]
------->>>>> 1.3.8 <<<<<----------
-o UDP snmp count fixed [IN]
-o IP snmp out count fixed [IN] (fragment still wrong)
-o First bit of Dave Bonn's fast forwarding [IN]
-o Fix leaks and double free in firewalling [IN]
+o UDP snmp count fixed [TESTED]
+o IP snmp out count fixed [TESTED]
+o First bit of Dave Bonn's fast forwarding [TESTED/NOW WORKS]
+o Fix leaks and double free in firewalling [TESTED]
o Fix memory scribble in ip_build_xmit [TESTED]
o Do fast cases of ip_build_xmit first
slows fragmented I/O down, speeds up smaller
packets. UDP send ttcp can now touch 7.5Mbyte/sec
with nothing else going on. UDP recv is slower 8( [TESTED]
-o Fixed and enabled ethernet header caches [IN]
-o Removed junk from igmp [IN]
-o Obscure UDP/copy&sum bug fix [IN]
-o Fixed multicast [IN]
-o TCP does rerouting for most cases [NOT WORKING YET]
+o Fixed and enabled ethernet header caches [TESTED]
+o Removed junk from igmp [TESTED]
+o Obscure UDP/copy&sum bug fix [TESTED]
+o Fixed multicast [TESTED]
+o TCP does rerouting for most cases [TESTED]
------->>>>> 1.3.14 <<<<<----------
o AX.25 works [IN]
o Most modules need recompiling even though they
load OK [BLAME LINUS]
+o Appletalk works nicely [CHECKED]
+o Fast IP forwarding part 1 works [CHECKED]
------->>>>> 1.3.15 <<<<<---------
o Mike Shaver has started RFC1122 verification [IN PROGRESS]
o Minor bug fixes [IN]
-------->>>> ???? <<<--------
+------->>>> 1.3.16 <<<--------
+
+o Missing patches for device change in TCP [IN]
+o Device locking [IN]
+o Infinite slip devices [IN]
+o New AF_UNIX sockets [IN]
+o Sendmsg/recvmsg (for some stuff only) [IN]
+o Device unload loopholes fixed [IN]
+o Extra firewall abilities [IN]
+o Appletalk node probe bug fix [IN]
+
+
o Finish merging the bridge code
-o Device locking
o SIOCSLEEPRT patch
o Options support in ip_build_xmit [PENDING]
o Fast checksum/copy on outgoing TCP
o Fast dev_grab_next() transmit reload function
and dev_push_failed() ??
-o Faster ip_forward [PENDING]
+o Faster ip_forward last hit cache [PENDING]
o Forwarding queue control (+ fairness algorithms ??)
o IP forward flow control.
-o Infinite PPP/SLIP devices.
-o PI2 card doesn't do AX.25 VC yet [PENDING]
+o Infinite PPP devices.
o AX.25 set protocol type
o Clean up RAW AX.25 sockets.
o Finish 802.2 Class I code to be compliant to the oddities of 802.2
0.2
---
-o New UNIX sockets include Pedro Roque's shutdown.
o New icmp.c.
o Better TCP window handling [Pedro Roque]
o IP option support.
1. Verifying the correctness of implementation against RFC1122 and
making a list of violations (BSD is sufficiently screwed up you can't
-implement all of RFC1122 and talk to it usefully).
+implement all of RFC1122 and talk to it usefully). [In progress - Mike
+Shaver]
2. Verifying all the error returns match the BSD ones (grotty job I
wouldn't wish on anyone).
5. Fixing the IP fragment handling so that the total space allocated to
fragments is limited and old fragments are deleted to make room for new ones
when space is exhausted. Fixing the fragment handling to work at a decent
-speed wouldn't be bad either.
+speed wouldn't be bad either. [In progress - Arnt Gulbrandsen]
6. Delayed ack. This is mostly supported but not actually set up and
used yet. Basically ack frames are held back 1/10th of a second in the hope
14. Bidirectional PLIP. Also PLIP for the newer style parallel ports.
15. 802.2LLC and thus Netbeui sockets. Becoming less important since the
-rumour is microsoft are phasing out netbeui for netbios/IP.
+rumour is microsoft are phasing out netbeui for netbios/IP.
+ [Tentatively in progress]
16. X.25. This is one for a real head case with far too much time on
their hands. [Provisionally taken]
18. Implement swIPe under Linux.
[In progress]
+19. IPv4 IP-AH and IP-ESP.
+
BTW: Don't let the magic words 'kernel programming' worry you. Its like DOS
- you make a mistake you have to reboot. You do at least get dumps and a
kernel logger that is reliable. There is now a loadable module allowing
*
* Fixes:
* Michael Callahan : Made routing work
+ * Wesley Craig : Fix probing to listen to a
+ * passed node id.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
int ct;
int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
int probe_net=ntohs(atif->address.s_net);
+ int probe_node=atif->address.s_node;
int netct;
int nodect;
probe_net=ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
}
+ if(probe_node == ATADDR_ANYNODE)
+ probe_node = jiffies&0xFF;
+
/*
* Scan the networks.
for(netct=0;netct<=netrange;netct++)
{
/*
- * Sweep the available nodes from a random start.
+ * Sweep the available nodes from a given start.
*/
- int nodeoff=jiffies&255;
-
+
atif->address.s_net=htons(probe_net);
for(nodect=0;nodect<256;nodect++)
{
- atif->address.s_node=((nodect+nodeoff)&0xFF);
+ atif->address.s_node=((nodect+probe_node)&0xFF);
if(atif->address.s_node>0&&atif->address.s_node<254)
{
/*
$(AS) -o $*.o $<
-OBJS := sock.o dev.o dev_mcast.o skbuff.o datagram.o
+OBJS := sock.o dev.o dev_mcast.o skbuff.o datagram.o iovec.o
ifdef CONFIG_NET
--- /dev/null
+/*
+ * iovec manipulation routines.
+ *
+ *
+ * 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 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <asm/segment.h>
+
+
+extern inline int min(int x, int y)
+{
+ return x>y?y:x;
+}
+
+int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
+{
+ int err=0;
+ int len=0;
+ int ct;
+
+ if(m->msg_name!=NULL)
+ {
+ if(mode==VERIFY_READ)
+ err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
+ else
+ err=verify_area(mode, m->msg_name, m->msg_namelen);
+ if(err<0)
+ return err;
+ }
+ if(m->msg_accrights!=NULL)
+ {
+ err=verify_area(mode, m->msg_accrights, m->msg_accrightslen);
+ if(err)
+ return err;
+ }
+
+ for(ct=0;ct<m->msg_iovlen;ct++)
+ {
+ err=verify_area(mode, m->msg_iov[ct].iov_base, m->msg_iov[ct].iov_len);
+ if(err)
+ return err;
+ len+=m->msg_iov[ct].iov_len;
+ }
+
+ return len;
+}
+
+/*
+ * Copy kernel to iovec.
+ */
+
+void memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
+{
+ while(len>0)
+ {
+ memcpy_tofs(iov->iov_base, kdata,iov->iov_len);
+ kdata+=iov->iov_len;
+ len-=iov->iov_len;
+ iov++;
+ }
+}
+
+/*
+ * Copy iovec to kernel.
+ */
+
+void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
+{
+ int copy;
+ while(len>0)
+ {
+ copy=min(len,iov->iov_len);
+ memcpy_fromfs(kdata, iov->iov_base, copy);
+ len-=copy;
+ kdata+=copy;
+ iov++;
+ }
+}
+
* See if we need to look up the device.
*/
-#ifdef CONFIG_INET_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
*dev=dev_get(skb->sk->ip_mc_name);
#endif
*/
raw = skb->data;
- iph = (struct iphdr *) (raw + dev->hard_header_len);
-
+#if 0
+ iph = (struct iphdr *) (raw + dev->hard_header_len);
skb->ip_hdr = iph;
+#else
+ iph = skb->ip_hdr;
+#endif
/*
* Setup starting values.
struct sk_buff *skb, int free)
{
struct iphdr *iph;
- unsigned char *ptr;
+/* unsigned char *ptr;*/
/* Sanity check */
if (dev == NULL)
* header length problem
*/
+#if 0
ptr = skb->data;
ptr += dev->hard_header_len;
- iph = (struct iphdr *)ptr;
+ iph = (struct iphdr *)ptr;
skb->ip_hdr = iph;
- iph->tot_len = ntohs(skb->len-dev->hard_header_len);
+#else
+ iph = skb->ip_hdr;
+#endif
+ iph->tot_len = ntohs(skb->len-(((unsigned char *)iph)-skb->data));
#ifdef CONFIG_IP_FIREWALL
if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) != 1)
* bits of it.
*/
- if(skb->len > dev->mtu + dev->hard_header_len)
+ if(ntohs(iph->tot_len)> dev->mtu)
{
ip_fragment(sk,skb,dev,0);
IS_SKB(skb);
ip_statistics.IpOutRequests++;
-#ifdef CONFIG_INET_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
if(sk && MULTICAST(daddr) && *sk->ip_mc_name)
{
- dev=dev_get(skb->ip_mc_name);
+ dev=dev_get(sk->ip_mc_name);
if(!dev)
return -ENODEV;
rt=NULL;
+ if (sk->saddr && (!LOOPBACK(sk->saddr) || LOOPBACK(daddr)))
+ saddr = sk->saddr;
+ else
+ saddr = dev->pa_addr;
}
else
{
saddr = sk->saddr;
dev=rt->rt_dev;
-#ifdef CONFIG_INET_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
}
#endif
if(sk==NULL || sk->ip_mc_loop)
{
if(skb->daddr==IGMP_ALL_HOSTS)
- ip_loopback(rt->rt_dev,skb);
+ ip_loopback(rt?rt->rt_dev:dev,skb);
else
{
- struct ip_mc_list *imc=rt->rt_dev->ip_mc_list;
+ struct ip_mc_list *imc=rt?rt->rt_dev->ip_mc_list:dev->ip_mc_list;
while(imc!=NULL)
{
if(imc->multiaddr==daddr)
{
- ip_loopback(rt->rt_dev,skb);
+ ip_loopback(rt?rt->rt_dev:dev,skb);
break;
}
imc=imc->next;
* Porting bidirectional entries from BSD, fixing accounting issues,
* adding struct ip_fwpkt for checking packets with interface address
* Jos Vos 5/Mar/1995.
+ * Established connections (ACK check), ACK check on bidirectional rules,
+ * ICMP type check.
+ * Wilfred Mollenvanger 7/7/1995.
*
* Masquerading functionality
*
struct ip_fw *f;
struct tcphdr *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
struct udphdr *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
+ struct icmphdr *icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
__u32 src, dst;
- __u16 src_port=0, dst_port=0;
+ __u16 src_port=0, dst_port=0, icmp_type=0;
unsigned short f_prt=0, prt;
- char notcpsyn=1, frag1, match;
+ char notcpsyn=1, notcpack=1, frag1, match;
unsigned short f_flag;
/*
if (frag1) {
src_port=ntohs(tcp->source);
dst_port=ntohs(tcp->dest);
- if(tcp->syn && !tcp->ack)
+ if(tcp->ack)
+ /* We *DO* have ACK, value FALSE */
+ notcpack=0;
+ if(tcp->syn && notcpack)
/* We *DO* have SYN, value FALSE */
notcpsyn=0;
}
prt=IP_FW_F_UDP;
break;
case IPPROTO_ICMP:
- dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff);
+ icmp_type=(__u16)(icmp->type);
+ dprintf2("ICMP:%d ",icmp_type);
prt=IP_FW_F_ICMP;
break;
default:
if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
continue;
+
+ /*
+ * When a bidirectional rule is used we only check
+ * for ack bits on reverse matches. This way it's
+ * easy to set up rules which only allow connections
+ * initiated from "normal" match adresses.
+ */
+
+ if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
+ if(f->fw_flg&IP_FW_F_BIDIR) {
+ if(match & 0x02)
+ continue;
+ } else
+ continue;
+
/*
* Specific firewall - packet's protocol
* must match firewall's.
if(prt!=f_prt)
continue;
- if(!(prt==IP_FW_F_ICMP || ((match & 0x01) &&
+ if((prt==IP_FW_F_ICMP &&
+ ! port_match(&f->fw_pts[0], f->fw_nsp,
+ icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
+ !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
port_match(&f->fw_pts[0], f->fw_nsp, src_port,
f->fw_flg&IP_FW_F_SRNG) &&
port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
if (!ftp->init_seq)
ftp->init_seq = th->seq;
- skb2 = alloc_skb(skb->len+ftp->delta, GFP_ATOMIC);
+ skb2 = alloc_skb(MAX_HEADER + skb->len+ftp->delta, GFP_ATOMIC);
if (skb2 == NULL) {
printk("MASQUERADE: No memory available\n");
return skb;
}
skb2->free = skb->free;
+ skb_reserve(skb2,MAX_HEADER);
skb_put(skb2,skb->len + ftp->delta);
skb2->h.raw = &skb2->data[skb->h.raw - skb->data];
if ( len < sizeof(struct ip_fwpkt) )
{
#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_fw_ctl: length=%d, expected %d\n",
+ printk("ip_fw_ctl: length=%d, expected %d\n",
len, sizeof(struct ip_fwpkt));
#endif
return( EINVAL );
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * Fixes
+ * Alan Cox : Rarp delete on device down needed as
+ * reported by Walter Wolfgang.
+ *
*/
#include <linux/types.h>
static initflag = 1;
-/*
- * Called once when data first added to rarp cache with ioctl.
- */
-
-static void rarp_init (void)
-{
- /* Register the packet type */
- rarp_packet_type.type=htons(ETH_P_RARP);
- dev_add_pack(&rarp_packet_type);
-}
/*
* Release the memory for this entry.
sti();
}
+/*
+ * Flush a device.
+ */
+
+static void rarp_destroy_dev(struct device *dev)
+{
+ struct rarp_table *entry;
+ struct rarp_table **pentry;
+
+ cli();
+ pentry = &rarp_tables;
+ while ((entry = *pentry) != NULL)
+ {
+ if (entry->dev == dev)
+ {
+ *pentry = entry->next;
+ sti();
+ rarp_release_entry(entry);
+ }
+ else
+ pentry = &entry->next;
+ }
+ sti();
+}
+
+static int rarp_device_event(unsigned long event, void *ptr)
+{
+ if(event!=NETDEV_DOWN)
+ return NOTIFY_DONE;
+ rarp_destroy_dev((struct device *)ptr);
+ return NOTIFY_DONE;
+}
+
+/*
+ * Called once when data first added to rarp cache with ioctl.
+ */
+
+static struct notifier_block rarp_dev_notifier={
+ rarp_device_event,
+ NULL,
+ 0
+};
+
+static void rarp_init (void)
+{
+ /* Register the packet type */
+ rarp_packet_type.type=htons(ETH_P_RARP);
+ dev_add_pack(&rarp_packet_type);
+ register_netdevice_notifier(&rarp_dev_notifier);
+}
/*
* Receive an arp request by the device layer. Maybe it should be
/*
* We shouldn't use this type conversion. Check later.
*/
- struct arphdr *rarp = (struct arphdr *)skb->h.raw;
- unsigned char *rarp_ptr = (unsigned char *)(rarp+1);
+ struct arphdr *rarp = (struct arphdr *)skb_pull(skb,sizeof(struct arphdr));
+ unsigned char *rarp_ptr = skb->data;
struct rarp_table *entry;
long sip,tip;
unsigned char *sha,*tha; /* s for "source", t for "target" */
#define CONFIG_UNIX /* always present... */
#ifdef CONFIG_UNIX
-#include <net/unix.h>
+#include <net/af_unix.h>
#endif
#ifdef CONFIG_INET
#include <linux/inet.h>
* Alan Cox : Made sock_alloc()/sock_release() public
* for NetROM and future kernel nfsd type
* stuff.
+ * Alan Cox : sendmsg/recvmsg basics.
*
*
* This program is free software; you can redistribute it and/or
#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, about 80 for AX.25 */
-static int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
+int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
{
int err;
if(ulen<0||ulen>MAX_SOCK_ADDR)
return 0;
}
-static int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
+int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
{
int err;
int len;
return(sock->ops->shutdown(sock, how));
}
+/*
+ * BSD sendmsg interface
+ */
+
+asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags)
+{
+ struct socket *sock;
+ struct file *file;
+ char address[MAX_SOCK_ADDR];
+ struct iovec iov[MAX_IOVEC];
+ struct msghdr msg_sys;
+ int err;
+ int total_len;
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
+ return(-EBADF);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return(-ENOTSOCK);
+
+ err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr));
+ if(err)
+ return err;
+ memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
+ if(msg_sys.msg_iovlen>MAX_IOVEC)
+ return -EINVAL;
+ err=verify_iovec(&msg_sys,iov,address, VERIFY_READ);
+ if(err<0)
+ return err;
+ total_len=err;
+
+ if(sock->ops->sendmsg==NULL)
+ return -EOPNOTSUPP;
+ return sock->ops->sendmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags);
+}
+
+/*
+ * BSD recvmsg interface
+ */
+
+asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
+{
+ struct socket *sock;
+ struct file *file;
+ char address[MAX_SOCK_ADDR];
+ struct iovec iov[MAX_IOVEC];
+ struct msghdr msg_sys;
+ int err;
+ int total_len;
+ int addr_len;
+ int len;
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
+ return(-EBADF);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return(-ENOTSOCK);
+
+ err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr));
+ if(err)
+ return err;
+ memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
+ if(msg_sys.msg_iovlen>MAX_IOVEC)
+ return -EINVAL;
+ err=verify_iovec(&msg_sys,iov,address, VERIFY_WRITE);
+ if(err<0)
+ return err;
+ total_len=err;
+
+ if(sock->ops->recvmsg==NULL)
+ return -EOPNOTSUPP;
+ len=sock->ops->recvmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags, &addr_len);
+ if(len<0)
+ return len;
+ /*
+ * Fixme: writing actual length into original msghdr.
+ */
+ if(msg_sys.msg_name!=NULL && (err=move_addr_to_user(address,addr_len, msg_sys.msg_name, &msg_sys.msg_namelen))<0)
+ return err;
+ return len;
+}
+
/*
* Perform a file control on a socket file descriptor.
asmlinkage int sys_socketcall(int call, unsigned long *args)
{
int er;
- unsigned char nargs[16]={0,3,3,3,2,3,3,3,
- 4,4,4,6,6,2,5,5};
+ unsigned char nargs[18]={0,3,3,3,2,3,3,3,
+ 4,4,4,6,6,2,5,5,3,3};
unsigned long a0,a1;
- if(call<1||call>SYS_GETSOCKOPT)
+ if(call<1||call>SYS_RECVMSG)
return -EINVAL;
er=verify_area(VERIFY_READ, args, nargs[call] * sizeof(unsigned long));
get_user(args+2),
(char *)get_user(args+3),
(int *)get_user(args+4)));
+ case SYS_SENDMSG:
+ return sys_sendmsg(a0,
+ (struct msghdr *) a1,
+ get_user(args+2));
+ case SYS_RECVMSG:
+ return sys_recvmsg(a0,
+ (struct msghdr *) a1,
+ get_user(args+2));
}
return -EINVAL; /* to keep gcc happy */
}
#
-# Makefile for the UNIX Protocol Family.
+# Makefile for the Linux TCP/IP (INET) layer.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
.s.o:
$(AS) -o $*.o $<
-OBJS = sock.o proc.o
-unix.o: $(OBJS)
- $(LD) -r -o unix.o $(OBJS)
+OBJS := af_unix.o
+
+
+unix.o: $(OBJS)
+ $(LD) -r -o unix.o $(OBJS)
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) -M *.c > .depend
tar:
- tar -cvf /dev/f1 .
+ tar -cvf /dev/f1 .
include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * NET3: Implementation of BSD Unix domain sockets.
+ *
+ * Authors: Alan Cox, <alan@cymru.net>
+ *
+ * Currently this contains all but the file descriptor passing code.
+ * Before that goes in the odd bugs in the iovec handlers need
+ * fixing, and this bit testing. BSD fd passing is a trivial part
+ * of the exercise.
+ *
+ * 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 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+/*#include <linux/netprotocol.h>*/
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/af_unix.h>
+
+static unix_socket *volatile unix_socket_list=NULL;
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/*
+ * Make sure the unix name is null-terminated.
+ */
+static inline void unix_mkname(struct sockaddr_un * sun, unsigned long len)
+{
+ if (len >= sizeof(*sun))
+ len = sizeof(*sun)-1;
+ ((char *)sun)[len]=0;
+}
+
+/*
+ * Note: Sockets may not be removed _during_ an interrupt or net_bh
+ * handler using this technique. They can be added although we do not
+ * use this facility.
+ */
+
+static void unix_remove_socket(unix_socket *sk)
+{
+ unix_socket *s;
+
+ cli();
+ s=unix_socket_list;
+ if(s==sk)
+ {
+ unix_socket_list=s->next;
+ sti();
+ return;
+ }
+ while(s && s->next)
+ {
+ if(s->next==sk)
+ {
+ s->next=sk->next;
+ sti();
+ return;
+ }
+ s=s->next;
+ }
+ sti();
+}
+
+static void unix_insert_socket(unix_socket *sk)
+{
+ cli();
+ sk->next=unix_socket_list;
+ unix_socket_list=sk;
+ sti();
+}
+
+static unix_socket *unix_find_socket(struct inode *i)
+{
+ unix_socket *s;
+ cli();
+ s=unix_socket_list;
+ while(s)
+ {
+ if(s->protinfo.af_unix.inode==i)
+ {
+ sti();
+ return(s);
+ }
+ s=s->next;
+ }
+ sti();
+ return(NULL);
+}
+
+/*
+ * Delete a unix socket. We have to allow for deferring this on a timer.
+ */
+
+static void unix_destroy_timer(unsigned long data)
+{
+ unix_socket *sk=(unix_socket *)data;
+ if(sk->protinfo.af_unix.locks==0 && sk->wmem_alloc==0)
+ {
+ if(sk->protinfo.af_unix.name)
+ kfree(sk->protinfo.af_unix.name);
+ kfree_s(sk,sizeof(*sk));
+ return;
+ }
+
+ /*
+ * Retry;
+ */
+
+ init_timer(&sk->timer);
+ sk->timer.expires=jiffies+10*HZ; /* No real hurry try it every 10 seconds or so */
+ add_timer(&sk->timer);
+}
+
+
+static void unix_delayed_delete(unix_socket *sk)
+{
+ init_timer(&sk->timer);
+ sk->timer.data=(unsigned long)sk;
+ sk->timer.expires=jiffies+HZ; /* Normally 1 second after will clean up. After that we try every 10 */
+ sk->timer.function=unix_destroy_timer;
+ add_timer(&sk->timer);
+}
+
+static void unix_destroy_socket(unix_socket *sk)
+{
+ struct sk_buff *skb;
+ unix_remove_socket(sk);
+
+ while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+ {
+ if(sk->state==TCP_LISTEN)
+ {
+ unix_socket *osk=skb->sk;
+ osk->state=TCP_CLOSE;
+ kfree_skb(skb, FREE_WRITE); /* Now surplus - free the skb first before the socket */
+ osk->state_change(osk); /* So the connect wakes and cleans up (if any) */
+ /* osk will be destroyed when it gets to close or the timer fires */
+ }
+ else
+ {
+/* unix_kill_credentials(skb); *//* Throw out any passed fd's */
+ kfree_skb(skb,FREE_WRITE);
+ }
+ }
+
+ if(sk->protinfo.af_unix.inode!=NULL)
+ {
+ iput(sk->protinfo.af_unix.inode);
+ sk->protinfo.af_unix.inode=NULL;
+ }
+
+ if(--sk->protinfo.af_unix.locks==0 && sk->wmem_alloc==0)
+ {
+ if(sk->protinfo.af_unix.name)
+ kfree(sk->protinfo.af_unix.name);
+ kfree_s(sk,sizeof(*sk));
+ }
+ else
+ {
+ sk->dead=1;
+ unix_delayed_delete(sk); /* Try every so often until buffers are all freed */
+ }
+}
+
+/*
+ * Fixme: We need async I/O on AF_UNIX doing next.
+ */
+
+static int unix_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+/*
+ * Yes socket options work with the new unix domain socketry!!!!!!!
+ */
+
+static int unix_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+ unix_socket *sk=sock->data;
+ if(level!=SOL_SOCKET)
+ return -EOPNOTSUPP;
+ return sock_setsockopt(sk,level,optname,optval,optlen);
+}
+
+static int unix_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+ unix_socket *sk=sock->data;
+ if(level!=SOL_SOCKET)
+ return -EOPNOTSUPP;
+ return sock_getsockopt(sk,level,optname,optval,optlen);
+}
+
+static int unix_listen(struct socket *sock, int backlog)
+{
+ unix_socket *sk=sock->data;
+ if(sk->type!=SOCK_STREAM)
+ return -EOPNOTSUPP; /* Only stream sockets accept */
+ sk->max_ack_backlog=backlog;
+ sk->state=TCP_LISTEN;
+ return 0;
+}
+
+static void def_callback1(struct sock *sk)
+{
+ if(!sk->dead)
+ wake_up_interruptible(sk->sleep);
+}
+
+static void def_callback2(struct sock *sk, int len)
+{
+ if(!sk->dead)
+ wake_up_interruptible(sk->sleep);
+}
+
+static int unix_create(struct socket *sock, int protocol)
+{
+ unix_socket *sk;
+/* printk("Unix create\n");*/
+ if(protocol)
+ return -EPROTONOSUPPORT;
+ sk=(unix_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
+ if(sk==NULL)
+ return -ENOMEM;
+ sk->type=sock->type;
+ switch(sock->type)
+ {
+ case SOCK_STREAM:
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ kfree_s(sk,sizeof(*sk));
+ return -ESOCKTNOSUPPORT;
+ }
+ skb_queue_head_init(&sk->write_queue);
+ skb_queue_head_init(&sk->receive_queue);
+ skb_queue_head_init(&sk->back_log);
+ sk->protinfo.af_unix.family=AF_UNIX;
+ sk->protinfo.af_unix.inode=NULL;
+ sk->protinfo.af_unix.locks=1; /* Us */
+ sk->protinfo.af_unix.readsem=MUTEX; /* single task reading lock */
+ sk->protinfo.af_unix.name=NULL;
+ sk->protinfo.af_unix.other=NULL;
+ sk->protocol=0;
+ sk->rmem_alloc=0;
+ sk->wmem_alloc=0;
+ sk->dead=0;
+ sk->next=NULL;
+ sk->broadcast=0;
+ sk->rcvbuf=SK_RMEM_MAX;
+ sk->sndbuf=SK_WMEM_MAX;
+ sk->inuse=0;
+ sk->debug=0;
+ sk->prot=NULL;
+ sk->err=0;
+ sk->localroute=0;
+ sk->send_head=NULL;
+ sk->state=TCP_CLOSE;
+ sk->priority=SOPRI_NORMAL;
+ sk->ack_backlog=0;
+ sk->shutdown=0;
+ sk->state_change=def_callback1;
+ sk->data_ready=def_callback2;
+ sk->write_space=def_callback1;
+ sk->error_report=def_callback1;
+ sk->mtu=4096;
+ sk->socket=sock;
+ sock->data=(void *)sk;
+ sk->sleep=sock->wait;
+ sk->zapped=0;
+ unix_insert_socket(sk);
+ return 0;
+}
+
+static int unix_dup(struct socket *newsock, struct socket *oldsock)
+{
+ return unix_create(newsock,0);
+}
+
+static int unix_release(struct socket *sock, struct socket *peer)
+{
+ unix_socket *sk=sock->data;
+ unix_socket *skpair;
+
+ /* May not have data attached */
+
+ if(sk==NULL)
+ return 0;
+
+ sk->state_change(sk);
+ sk->dead=1;
+ skpair=(unix_socket *)sk->protinfo.af_unix.other; /* Person we send to (default) */
+ if(sk->type==SOCK_STREAM && skpair!=NULL && skpair->state!=TCP_LISTEN)
+ {
+ skpair->shutdown=SHUTDOWN_MASK; /* No more writes */
+ skpair->state_change(skpair); /* Wake any blocked writes */
+ }
+ if(skpair!=NULL)
+ skpair->protinfo.af_unix.locks--; /* It may now die */
+ sk->protinfo.af_unix.other=NULL; /* No pair */
+ unix_destroy_socket(sk); /* Try and flush out this socket. Throw our buffers at least */
+ return 0;
+}
+
+
+static unix_socket *unix_find_other(char *path, int *error)
+{
+ int old_fs;
+ int err;
+ struct inode *inode;
+ unix_socket *u;
+
+ old_fs=get_fs();
+ set_fs(get_ds());
+ err = open_namei(path, 2, S_IFSOCK, &inode, NULL);
+ set_fs(old_fs);
+ if(err<0)
+ {
+ *error=err;
+ return NULL;
+ }
+ u=unix_find_socket(inode);
+ iput(inode);
+ if(u==NULL)
+ {
+ *error=-ECONNREFUSED;
+ return NULL;
+ }
+ return u;
+}
+
+
+static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_un *sun=(struct sockaddr_un *)uaddr;
+ unix_socket *sk=sock->data;
+ int old_fs;
+ int err;
+
+ if(addr_len>sizeof(struct sockaddr_un) || addr_len<3 || sun->sun_family!=AF_UNIX)
+ return -EINVAL;
+ unix_mkname(sun, addr_len);
+ /*
+ * Put ourselves in the filesystem
+ */
+ if(sk->protinfo.af_unix.inode!=NULL)
+ return -EINVAL;
+
+ sk->protinfo.af_unix.name=kmalloc(addr_len+1, GFP_KERNEL);
+ if(sk->protinfo.af_unix.name==NULL)
+ return -ENOMEM;
+ memcpy(sk->protinfo.af_unix.name, sun->sun_path, addr_len+1);
+
+ old_fs=get_fs();
+ set_fs(get_ds());
+
+ err=do_mknod(sk->protinfo.af_unix.name,S_IFSOCK|S_IRWXUGO,0);
+ if(err==0)
+ err=open_namei(sk->protinfo.af_unix.name, 2, S_IFSOCK, &sk->protinfo.af_unix.inode, NULL);
+
+ set_fs(old_fs);
+
+ if(err<0)
+ {
+ kfree_s(sk->protinfo.af_unix.name,addr_len+1);
+ sk->protinfo.af_unix.name=NULL;
+ if(err==-EEXIST)
+ return -EADDRINUSE;
+ else
+ return err;
+ }
+
+ return 0;
+
+}
+
+static int unix_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+{
+ unix_socket *sk=sock->data;
+ struct sockaddr_un *sun=(struct sockaddr_un *)uaddr;
+ unix_socket *other;
+ struct sk_buff *skb;
+ int err;
+
+ unix_mkname(sun, addr_len);
+ if(sk->type==SOCK_STREAM && sk->protinfo.af_unix.other)
+ {
+ if(sock->state==SS_CONNECTING && sk->state==TCP_ESTABLISHED)
+ {
+ sock->state=SS_CONNECTED;
+ return 0;
+ }
+ if(sock->state==SS_CONNECTING && sk->state == TCP_CLOSE)
+ {
+ sock->state=SS_UNCONNECTED;
+ return -ECONNREFUSED;
+ }
+ if(sock->state==SS_CONNECTING)
+ return -EALREADY;
+ return -EISCONN;
+ }
+
+ if(sun->sun_family!=AF_UNIX)
+ return -EINVAL;
+
+ if(sk->type==SOCK_DGRAM && sk->protinfo.af_unix.other)
+ {
+ sk->protinfo.af_unix.other->protinfo.af_unix.locks--;
+ sk->protinfo.af_unix.other=NULL;
+ sock->state=SS_UNCONNECTED;
+ }
+
+ if(sock->type==SOCK_DGRAM)
+ {
+ sock->state=SS_CONNECTED;
+ sk->state=TCP_ESTABLISHED;
+ return 0; /* Done */
+ }
+
+
+ if(sock->state==SS_UNCONNECTED)
+ {
+ /*
+ * Now ready to connect
+ */
+
+ skb=sock_alloc_send_skb(sk, 0, 0, &err); /* Marker object */
+ if(skb==NULL)
+ return err;
+ skb->sk=sk; /* So they know it is us */
+ skb->free=1;
+ sk->state=TCP_CLOSE;
+ unix_mkname(sun, addr_len);
+ other=unix_find_other(sun->sun_path, &err);
+ if(other==NULL)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ return err;
+ }
+ other->protinfo.af_unix.locks++; /* Lock the other socket so it doesn't run off for a moment */
+ other->ack_backlog++;
+ sk->protinfo.af_unix.other=other;
+ skb_queue_tail(&other->receive_queue,skb);
+ sk->state=TCP_SYN_SENT;
+ sock->state=SS_CONNECTING;
+ sti();
+ other->data_ready(other,0); /* Wake up ! */
+ }
+
+
+ /* Wait for an accept */
+
+ cli();
+ while(sk->state==TCP_SYN_SENT)
+ {
+ if(flags&O_NONBLOCK)
+ {
+ sti();
+ return -EINPROGRESS;
+ }
+ interruptible_sleep_on(sk->sleep);
+ if(current->signal & ~current->blocked)
+ {
+ sti();
+ return -ERESTARTSYS;
+ }
+ }
+
+ /*
+ * Has the other end closed on us ?
+ */
+
+ if(sk->state==TCP_CLOSE)
+ {
+ sk->protinfo.af_unix.other->protinfo.af_unix.locks--;
+ sk->protinfo.af_unix.other=NULL;
+ sock->state=SS_UNCONNECTED;
+ return -ECONNREFUSED;
+ }
+
+ /*
+ * Amazingly it has worked
+ */
+
+ sock->state=SS_CONNECTED;
+ return 0;
+
+}
+
+static int unix_socketpair(struct socket *a, struct socket *b)
+{
+ int err;
+ unix_socket *ska,*skb;
+
+ err=unix_create(a, 0);
+ if(err)
+ return err;
+ err=unix_create(b, 0);
+ if(err)
+ {
+ unix_release(a, NULL);
+ a->data=NULL;
+ return err;
+ }
+
+ ska=a->data;
+ skb=b->data;
+
+ /* Join our sockets back to back */
+ ska->protinfo.af_unix.locks++;
+ skb->protinfo.af_unix.locks++;
+ ska->protinfo.af_unix.other=skb;
+ skb->protinfo.af_unix.other=ska;
+ ska->state=TCP_ESTABLISHED;
+ skb->state=TCP_ESTABLISHED;
+ return 0;
+}
+
+static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ unix_socket *sk=sock->data;
+ unix_socket *newsk, *tsk;
+ struct sk_buff *skb;
+
+ if(sk->type!=SOCK_STREAM)
+ {
+ return -EOPNOTSUPP;
+ }
+ if(sk->state!=TCP_LISTEN)
+ {
+ return -EINVAL;
+ }
+
+ newsk=newsock->data;
+ if(sk->protinfo.af_unix.name!=NULL)
+ {
+ newsk->protinfo.af_unix.name=kmalloc(strlen(sk->protinfo.af_unix.name)+1, GFP_KERNEL);
+ if(newsk->protinfo.af_unix.name==NULL)
+ return -ENOMEM;
+ strcpy(newsk->protinfo.af_unix.name, sk->protinfo.af_unix.name);
+ }
+
+ do
+ {
+ cli();
+ skb=skb_dequeue(&sk->receive_queue);
+ if(skb==NULL)
+ {
+ if(flags&O_NONBLOCK)
+ {
+ sti();
+ return -EAGAIN;
+ }
+ interruptible_sleep_on(sk->sleep);
+ if(current->signal & ~current->blocked)
+ {
+ sti();
+ return -ERESTARTSYS;
+ }
+ sti();
+ }
+ }
+ while(skb==NULL);
+ tsk=skb->sk;
+ kfree_skb(skb, FREE_WRITE); /* The buffer is just used as a tag */
+ sk->ack_backlog--;
+ newsk->protinfo.af_unix.other=tsk;
+ tsk->protinfo.af_unix.other=newsk;
+ tsk->state=TCP_ESTABLISHED;
+ newsk->state=TCP_ESTABLISHED;
+ newsk->protinfo.af_unix.locks++; /* Swap lock over */
+ sk->protinfo.af_unix.locks--; /* Locked to child socket not master */
+ tsk->protinfo.af_unix.locks++; /* Back lock */
+ sti();
+ tsk->state_change(tsk); /* Wake up any sleeping connect */
+ return 0;
+}
+
+static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+{
+ unix_socket *sk=sock->data;
+ struct sockaddr_un *sun=(struct sockaddr_un *)uaddr;
+
+ if(peer)
+ {
+ if(sk->protinfo.af_unix.other==NULL)
+ return -ENOTCONN;
+ sk=sk->protinfo.af_unix.other;
+ }
+ sun->sun_family=AF_UNIX;
+ if(sk->protinfo.af_unix.name==NULL)
+ {
+ *sun->sun_path=0;
+ *uaddr_len=3;
+ return 0; /* Not bound */
+ }
+ *uaddr_len=sizeof(short)+strlen(sk->protinfo.af_unix.name)+1;
+ strcpy(sun->sun_path,sk->protinfo.af_unix.name); /* 108 byte limited */
+ return 0;
+}
+
+static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
+{
+ unix_socket *sk=sock->data;
+ unix_socket *other;
+ struct sockaddr_un *sun=msg->msg_name;
+ int err,size;
+ struct sk_buff *skb;
+
+ if(sk->err)
+ {
+ cli();
+ err=sk->err;
+ sk->err=0;
+ sti();
+ return -err;
+ }
+
+ if(flags || msg->msg_accrights) /* For now */
+ return -EINVAL;
+
+ if(sun!=NULL)
+ {
+ if(sock->type==SOCK_STREAM)
+ {
+ if(sk->state==TCP_ESTABLISHED)
+ return -EISCONN;
+ else
+ return -EOPNOTSUPP;
+ }
+ }
+ if(sun==NULL)
+ {
+ if(sk->protinfo.af_unix.other==NULL)
+ return -EINVAL;
+ }
+
+ /*
+ * Optimisation for the fact that under 0.01% of X messages typically
+ * need breaking up.
+ */
+
+ if(len>(sk->sndbuf-sizeof(struct sk_buff))/2) /* Keep two messages in the pipe so it schedules better */
+ {
+ if(sock->type==SOCK_DGRAM)
+ return -EMSGSIZE;
+ len=(sk->sndbuf-sizeof(struct sk_buff))/2;
+ }
+
+ size=/*protocol_size(&proto_unix)+*/len;
+ skb=sock_alloc_send_skb(sk,size,nonblock, &err);
+ if(skb==NULL)
+ return err;
+/* protocol_adjust(skb,&proto_unix);*/
+ skb->sk=sk;
+ skb->free=1;
+ memcpy_fromiovec(skb_put(skb,len),msg->msg_iov, len);
+
+ cli();
+ if(sun==NULL)
+ {
+ other=sk->protinfo.af_unix.other;
+ }
+ else
+ {
+ unix_mkname(sun, msg->msg_namelen);
+ other=unix_find_other(sun->sun_path, &err);
+ if(other==NULL)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ return err;
+ }
+ }
+ skb_queue_tail(&other->receive_queue, skb);
+ sti();
+ other->data_ready(other,len);
+ return len;
+}
+
+static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
+{
+ unix_socket *sk=sock->data;
+ struct sockaddr_un *sun=msg->msg_name;
+ int err;
+ struct sk_buff *skb;
+ int copied=0;
+ unsigned char *sp;
+ int len;
+ int num;
+ struct iovec *iov=msg->msg_iov;
+ int ct=msg->msg_iovlen;
+
+ if(addr_len)
+ *addr_len=0;
+
+ if(sk->err)
+ {
+ cli();
+ err=sk->err;
+ sk->err=0;
+ sti();
+ return -sk->err;
+ }
+
+/* printk("get rcv sem\n");*/
+ down(&sk->protinfo.af_unix.readsem); /* Lock the socket */
+/* printk("got rcv sem\n");*/
+
+ while(ct--)
+ {
+ int done=0;
+ sp=iov->iov_base;
+ len=iov->iov_len;
+ iov++;
+
+ while(done<len)
+ {
+ if(copied & (flags&MSG_PEEK))
+ {
+ up(&sk->protinfo.af_unix.readsem);
+ return copied;
+ }
+ cli();
+ skb=skb_peek(&sk->receive_queue);
+ if(skb==NULL)
+ {
+ up(&sk->protinfo.af_unix.readsem);
+ if(sk->shutdown&RCV_SHUTDOWN)
+ return copied;
+ if(noblock)
+ {
+ if(copied)
+ return copied;
+ return -EAGAIN;
+ }
+ interruptible_sleep_on(sk->sleep);
+ if( current->signal & ~current->blocked)
+ {
+ sti();
+ if(copied)
+ return copied;
+ return -ERESTARTSYS;
+ }
+ sti();
+ down(&sk->protinfo.af_unix.readsem);
+ continue;
+ }
+ if(msg->msg_name!=NULL)
+ {
+ sun->sun_family=AF_UNIX;
+ if(skb->sk->protinfo.af_unix.name)
+ {
+ memcpy(sun->sun_path, skb->sk->protinfo.af_unix.name, 108);
+ if(addr_len)
+ *addr_len=strlen(sun->sun_path)+sizeof(short);
+ }
+ else
+ if(addr_len)
+ *addr_len=sizeof(short);
+ }
+ num=min(skb->len,size-copied);
+ copied+=num;
+ done+=num;
+ if(flags&MSG_PEEK)
+ {
+ memcpy_tofs(sp, skb->data, num);
+ break;
+ }
+ else
+ {
+ memcpy_tofs(sp, skb->data,num);
+ skb_pull(skb,num);
+ sp+=num;
+ if(skb->len==0)
+ {
+ skb_unlink(skb);
+ kfree_skb(skb, FREE_WRITE);
+ if(sock->type==SOCK_DGRAM)
+ break;
+ }
+ }
+ }
+ }
+ up(&sk->protinfo.af_unix.readsem);
+ return copied;
+}
+
+static int unix_shutdown(struct socket *sock, int mode)
+{
+ unix_socket *sk=(unix_socket *)sock->data;
+ unix_socket *other=sk->protinfo.af_unix.other;
+ if(mode&SEND_SHUTDOWN)
+ {
+ sk->shutdown|=SEND_SHUTDOWN;
+ sk->state_change(sk);
+ if(other)
+ {
+ other->shutdown|=RCV_SHUTDOWN;
+ other->state_change(other);
+ }
+ }
+ other=sk->protinfo.af_unix.other;
+ if(mode&RCV_SHUTDOWN)
+ {
+ sk->shutdown|=RCV_SHUTDOWN;
+ sk->state_change(sk);
+ if(other)
+ {
+ other->shutdown|=SEND_SHUTDOWN;
+ other->state_change(other);
+ }
+ }
+ return 0;
+}
+
+
+static int unix_select(struct socket *sock, int sel_type, select_table *wait)
+{
+ return datagram_select(sock->data,sel_type,wait);
+}
+
+static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ unix_socket *sk=sock->data;
+ int err;
+ long amount=0;
+
+ switch(cmd)
+ {
+
+ case TIOCOUTQ:
+ err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
+ if(err)
+ return err;
+ amount=sk->sndbuf-sk->wmem_alloc;
+ if(amount<0)
+ amount=0;
+ put_fs_long(amount,(unsigned long *)arg);
+ return 0;
+ case TIOCINQ:
+ {
+ struct sk_buff *skb;
+ if(sk->state==TCP_LISTEN)
+ return -EINVAL;
+ /* These two are safe on a single CPU system as only user tasks fiddle here */
+ if((skb=skb_peek(&sk->receive_queue))!=NULL)
+ amount=skb->len;
+ err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
+ put_fs_long(amount,(unsigned long *)arg);
+ return 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ /*NOTREACHED*/
+ return(0);
+}
+
+/* Exported for procfs. */
+
+int unix_get_info(char *buffer, char **start, off_t offset, int length)
+{
+ off_t pos=0;
+ off_t begin=0;
+ int len=0;
+ unix_socket *s=unix_socket_list;
+
+ len+= sprintf(buffer,"Num RefCount Protocol Flags Type St Path\n");
+
+ while(s!=NULL)
+ {
+ len+=sprintf(buffer+len,"%p: %08X %08X %08lX %04X %02X",
+ s,
+ s->protinfo.af_unix.locks,
+ 0,
+ s->socket->flags,
+ s->socket->type,
+ s->socket->state);
+ if(s->protinfo.af_unix.name!=NULL)
+ len+=sprintf(buffer+len, " %s\n", s->protinfo.af_unix.name);
+ else
+ buffer[len++]='\n';
+
+ pos=begin+len;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ break;
+ s=s->next;
+ }
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ return len;
+}
+
+/*
+ * For AF_UNIX we flip everything into an iovec. If this doesnt do any speed harm then it will
+ * be easier for all the low levels to be totally iovec based.
+ */
+
+static int unix_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags,
+ struct sockaddr *sa, int *addr_len)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ iov.iov_base=ubuf;
+ iov.iov_len=size;
+ msg.msg_name=(void *)sa;
+ msg.msg_namelen=get_user(addr_len);
+ msg.msg_accrights=NULL;
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ return unix_recvmsg(sock,&msg,size,noblock,flags,addr_len);
+}
+
+static int unix_read(struct socket *sock, char *ubuf, int size, int noblock)
+{
+ return unix_recvfrom(sock,ubuf,size,noblock,0,NULL,NULL);
+}
+
+static int unix_recv(struct socket *sock, void *ubuf, int size, int noblock, unsigned int flags)
+{
+ return unix_recvfrom(sock,ubuf,size,noblock,flags,NULL,NULL);
+}
+
+static int unix_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags,
+ struct sockaddr *sa, int addr_len)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ iov.iov_base=(void *)ubuf;
+ iov.iov_len=size;
+ msg.msg_name=(void *)sa;
+ msg.msg_namelen=addr_len;
+ msg.msg_accrights=NULL;
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ return unix_sendmsg(sock,&msg,size,noblock,flags);
+}
+
+static int unix_write(struct socket *sock, const char *ubuf, int size, int noblock)
+{
+ return unix_sendto(sock,ubuf,size,noblock, 0, NULL, 0);
+}
+
+static int unix_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned int flags)
+{
+ return unix_sendto(sock,ubuf,size,noblock, flags, NULL, 0);
+}
+
+
+static struct proto_ops unix_proto_ops = {
+ AF_UNIX,
+
+ unix_create,
+ unix_dup,
+ unix_release,
+ unix_bind,
+ unix_connect,
+ unix_socketpair,
+ unix_accept,
+ unix_getname,
+ unix_read,
+ unix_write,
+ unix_select,
+ unix_ioctl,
+ unix_listen,
+ unix_send,
+ unix_recv,
+ unix_sendto,
+ unix_recvfrom,
+ unix_shutdown,
+ unix_setsockopt,
+ unix_getsockopt,
+ unix_fcntl,
+ unix_sendmsg,
+ unix_recvmsg
+};
+
+
+void unix_proto_init(struct net_proto *pro)
+{
+ printk("NET3: Unix domain sockets 0.07 BETA for Linux NET3.030.\n");
+ sock_register(unix_proto_ops.family, &unix_proto_ops);
+}
+++ /dev/null
-/*
- * UNIX An implementation of the AF_UNIX network domain for the
- * LINUX operating system. UNIX is implemented using the
- * BSD Socket interface as the means of communication with
- * the user level.
- *
- * The functions in this file provide an interface between
- * the PROC file system and the "unix" family of networking
- * protocols. It is mainly used for debugging and statistics.
- *
- * Version: @(#)proc.c 1.0.4 05/23/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
- * Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
- *
- * Fixes:
- * Dmitry Gorodchanin : /proc locking fix
- * Mathijs Maassen : unbound /proc fix.
- * Alan Cox : Fix sock=NULL race
- *
- * 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 of the License, or (at your option) any later version.
- */
-#include <linux/autoconf.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/net.h>
-#include <linux/un.h>
-#include <linux/param.h>
-#include <net/unix.h>
-
-
-/* Called from PROCfs. */
-int unix_get_info(char *buffer, char **start, off_t offset, int length)
-{
- off_t pos=0;
- off_t begin=0;
- int len=0;
- int i;
- unsigned long flags;
- socket_state s_state;
- short s_type;
- long s_flags;
-
- len += sprintf(buffer, "Num RefCount Protocol Flags Type St Path\n");
-
- for(i = 0; i < NSOCKETS_UNIX; i++)
- {
- save_flags(flags);
- cli();
- if (unix_datas[i].refcnt>0 && unix_datas[i].socket!=NULL)
- {
- /* sprintf is slow... lock only for the variable reads */
- s_type=unix_datas[i].socket->type;
- s_flags=unix_datas[i].socket->flags;
- s_state=unix_datas[i].socket->state;
- restore_flags(flags);
- len += sprintf(buffer+len, "%2d: %08X %08X %08lX %04X %02X", i,
- unix_datas[i].refcnt,
- unix_datas[i].protocol,
- s_flags,
- s_type,
- s_state
- );
-
- /* If socket is bound to a filename, we'll print it. */
- if(unix_datas[i].sockaddr_len>0)
- {
- len += sprintf(buffer+len, " %s\n",
- unix_datas[i].sockaddr_un.sun_path);
- }
- else
- { /* just add a newline */
- buffer[len++]='\n';
- }
-
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
- else
- restore_flags(flags);
- }
-
- *start=buffer+(offset-begin);
- len-=(offset-begin);
- if(len>length)
- len=length;
- return len;
-}
+++ /dev/null
-/*
- * UNIX An implementation of the AF_UNIX network domain for the
- * LINUX operating system. UNIX is implemented using the
- * BSD Socket interface as the means of communication with
- * the user level.
- *
- * Version: @(#)sock.c 1.0.5 05/25/93
- *
- * Authors: Orest Zborowski, <obz@Kodak.COM>
- * Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * Fixes:
- * Alan Cox : Verify Area
- * NET2E Team : Page fault locks
- * Dmitry Gorodchanin : /proc locking
- *
- * To Do:
- * Some nice person is looking into Unix sockets done properly. NET3
- * will replace all of this and include datagram sockets and socket
- * options - so please stop asking me for them 8-)
- *
- *
- * 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 of the License, or(at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/socket.h>
-#include <linux/un.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/fs.h>
-#include <linux/malloc.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-
-#include <stdarg.h>
-
-#include <net/unix.h>
-
-/*
- * Because these have the address in them they casually waste an extra 8K of kernel data
- * space that need not be wasted.
- */
-
-struct unix_proto_data unix_datas[NSOCKETS_UNIX];
-
-static int unix_proto_create(struct socket *sock, int protocol);
-static int unix_proto_dup(struct socket *newsock, struct socket *oldsock);
-static int unix_proto_release(struct socket *sock, struct socket *peer);
-static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
- int sockaddr_len);
-static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags);
-static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2);
-static int unix_proto_accept(struct socket *sock, struct socket *newsock,
- int flags);
-static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
- int *usockaddr_len, int peer);
-static int unix_proto_read(struct socket *sock, char *ubuf, int size,
- int nonblock);
-static int unix_proto_write(struct socket *sock, const char *ubuf, int size,
- int nonblock);
-static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait);
-static int unix_proto_ioctl(struct socket *sock, unsigned int cmd,
- unsigned long arg);
-static int unix_proto_listen(struct socket *sock, int backlog);
-static int unix_proto_send(struct socket *sock, const void *buff, int len,
- int nonblock, unsigned flags);
-static int unix_proto_recv(struct socket *sock, void *buff, int len,
- int nonblock, unsigned flags);
-static int unix_proto_sendto(struct socket *sock, const void *buff, int len,
- int nonblock, unsigned flags,
- struct sockaddr *addr, int addr_len);
-static int unix_proto_recvfrom(struct socket *sock, void *buff, int len,
- int nonblock, unsigned flags,
- struct sockaddr *addr, int *addr_len);
-
-static int unix_proto_shutdown(struct socket *sock, int how);
-
-static int unix_proto_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen);
-static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen);
-
-
-static inline int min(int a, int b)
-{
- if (a < b)
- return(a);
- return(b);
-}
-
-
-
-/* Support routines doing anti page fault locking
- * FvK & Matt Dillon (borrowed From NET2E3)
- */
-
-/*
- * Locking for unix-domain sockets. We don't use the socket structure's
- * wait queue because it is allowed to 'go away' outside of our control,
- * whereas unix_proto_data structures stick around.
- */
-
-static void unix_lock(struct unix_proto_data *upd)
-{
- while (upd->lock_flag)
- sleep_on(&upd->wait);
- upd->lock_flag = 1;
-}
-
-
-static void unix_unlock(struct unix_proto_data *upd)
-{
- upd->lock_flag = 0;
- wake_up(&upd->wait);
-}
-
-/*
- * We don't have to do anything.
- */
-
-static int unix_proto_listen(struct socket *sock, int backlog)
-{
- return(0);
-}
-
-/*
- * Until the new NET3 Unix code is done we have no options.
- */
-
-static int unix_proto_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen)
-{
- return(-EOPNOTSUPP);
-}
-
-
-static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- return(-EOPNOTSUPP);
-}
-
-
-/*
- * SendTo() doesn't matter as we also have no Datagram support!
- */
-
-static int unix_proto_sendto(struct socket *sock, const void *buff, int len, int nonblock,
- unsigned flags, struct sockaddr *addr, int addr_len)
-{
- return(-EOPNOTSUPP);
-}
-
-static int unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags, struct sockaddr *addr, int *addr_len)
-{
- return(-EOPNOTSUPP);
-}
-
-/*
- * You can't shutdown a unix domain socket.
- */
-
-static int unix_proto_shutdown(struct socket *sock, int how)
-{
- return(-EOPNOTSUPP);
-}
-
-
-/*
- * Send data to a unix socket.
- */
-
-static int unix_proto_send(struct socket *sock, const void *buff, int len, int nonblock,
- unsigned flags)
-{
- if (flags != 0)
- return(-EINVAL);
- return(unix_proto_write(sock, (const char *) buff, len, nonblock));
-}
-
-
-/*
- * Receive data. This version of AF_UNIX also lacks MSG_PEEK 8(
- */
-
-static int unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags)
-{
- if (flags != 0)
- return(-EINVAL);
- return(unix_proto_read(sock, (char *) buff, len, nonblock));
-}
-
-/*
- * Given an address and an inode go find a unix control structure
- */
-
-static struct unix_proto_data *
-unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
- struct inode *inode)
-{
- struct unix_proto_data *upd;
-
- for(upd = unix_datas; upd <= last_unix_data; ++upd)
- {
- if (upd->refcnt > 0 && upd->socket &&
- upd->socket->state == SS_UNCONNECTED &&
- upd->sockaddr_un.sun_family == sockun->sun_family &&
- upd->inode == inode)
-
- return(upd);
- }
- return(NULL);
-}
-
-/*
- * We allocate a page of data for the socket. This is woefully inadequate and helps cause vast
- * amounts of excess task switching and blocking when transferring stuff like bitmaps via X.
- * It doesn't help this problem that the Linux scheduler is desperately in need of a major
- * rewrite. Somewhere near 16K would be better maybe 32.
- */
-
-static struct unix_proto_data *
-unix_data_alloc(void)
-{
- struct unix_proto_data *upd;
-
- cli();
- for(upd = unix_datas; upd <= last_unix_data; ++upd)
- {
- if (!upd->refcnt)
- {
- upd->refcnt = -1; /* unix domain socket not yet initialised - bgm */
- sti();
- upd->socket = NULL;
- upd->sockaddr_len = 0;
- upd->sockaddr_un.sun_family = 0;
- upd->buf = NULL;
- upd->bp_head = upd->bp_tail = 0;
- upd->inode = NULL;
- upd->peerupd = NULL;
- return(upd);
- }
- }
- sti();
- return(NULL);
-}
-
-/*
- * The data area is owned by all its users. Thus we need to track owners
- * carefully and not free data at the wrong moment. These look like they need
- * interrupt protection but they don't because no interrupt ever fiddles with
- * these counts. With an SMP Linux you'll need to protect these!
- */
-
-static inline void unix_data_ref(struct unix_proto_data *upd)
-{
- if (!upd)
- {
- return;
- }
- ++upd->refcnt;
-}
-
-
-static void unix_data_deref(struct unix_proto_data *upd)
-{
- if (!upd)
- {
- return;
- }
- if (upd->refcnt == 1)
- {
- if (upd->buf)
- {
- free_page((unsigned long)upd->buf);
- upd->buf = NULL;
- upd->bp_head = upd->bp_tail = 0;
- }
- }
- --upd->refcnt;
-}
-
-
-/*
- * Upon a create, we allocate an empty protocol data,
- * and grab a page to buffer writes.
- */
-
-static int unix_proto_create(struct socket *sock, int protocol)
-{
- struct unix_proto_data *upd;
-
- /*
- * No funny SOCK_RAW stuff
- */
-
- if (protocol != 0)
- {
- return(-EINVAL);
- }
-
- if (!(upd = unix_data_alloc()))
- {
- printk("UNIX: create: can't allocate buffer\n");
- return(-ENOMEM);
- }
- if (!(upd->buf = (char*) get_free_page(GFP_USER)))
- {
- printk("UNIX: create: can't get page!\n");
- unix_data_deref(upd);
- return(-ENOMEM);
- }
- upd->protocol = protocol;
- upd->socket = sock;
- UN_DATA(sock) = upd;
- upd->refcnt = 1; /* Now it's complete - bgm */
- return(0);
-}
-
-/*
- * Duplicate a socket.
- */
-
-static int unix_proto_dup(struct socket *newsock, struct socket *oldsock)
-{
- struct unix_proto_data *upd = UN_DATA(oldsock);
- return(unix_proto_create(newsock, upd->protocol));
-}
-
-
-/*
- * Release a Unix domain socket.
- */
-
-static int unix_proto_release(struct socket *sock, struct socket *peer)
-{
- struct unix_proto_data *upd = UN_DATA(sock);
-
- if (!upd)
- return(0);
-
- if (upd->socket != sock)
- {
- printk("UNIX: release: socket link mismatch!\n");
- return(-EINVAL);
- }
-
- if (upd->inode)
- {
- iput(upd->inode);
- upd->inode = NULL;
- }
-
- UN_DATA(sock) = NULL;
- upd->socket = NULL;
-
- if (upd->peerupd)
- unix_data_deref(upd->peerupd);
- unix_data_deref(upd);
- return(0);
-}
-
-
-/*
- * Bind a name to a socket.
- * This is where much of the work is done: we allocate a fresh page for
- * the buffer, grab the appropriate inode and set things up.
- *
- * FIXME: what should we do if an address is already bound?
- * Here we return EINVAL, but it may be necessary to re-bind.
- * I think thats what BSD does in the case of datagram sockets...
- */
-
-static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
- int sockaddr_len)
-{
- char fname[UNIX_PATH_MAX + 1];
- struct unix_proto_data *upd = UN_DATA(sock);
- unsigned long old_fs;
- int i;
-
- if (sockaddr_len <= UN_PATH_OFFSET ||
- sockaddr_len > sizeof(struct sockaddr_un))
- {
- return(-EINVAL);
- }
- if (upd->sockaddr_len || upd->inode)
- {
- /*printk("UNIX: bind: already bound!\n");*/
- return(-EINVAL);
- }
- memcpy(&upd->sockaddr_un, umyaddr, sockaddr_len);
- upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
- if (upd->sockaddr_un.sun_family != AF_UNIX)
- {
- return(-EINVAL);
- }
-
- memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
- fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
- old_fs = get_fs();
- set_fs(get_ds());
-
- i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
-
- if (i == 0)
- i = open_namei(fname, 2, S_IFSOCK, &upd->inode, NULL);
- set_fs(old_fs);
- if (i < 0)
- {
-/* printk("UNIX: bind: can't open socket %s\n", fname);*/
- if(i==-EEXIST)
- i=-EADDRINUSE;
- return(i);
- }
- upd->sockaddr_len = sockaddr_len; /* now it's legal */
-
- return(0);
-}
-
-
-/*
- * Perform a connection. we can only connect to unix sockets
- * (I can't for the life of me find an application where that
- * wouldn't be the case!)
- */
-
-static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags)
-{
- char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
- struct sockaddr_un sockun;
- struct unix_proto_data *serv_upd;
- struct inode *inode;
- unsigned long old_fs;
- int i;
-
- if (sockaddr_len <= UN_PATH_OFFSET ||
- sockaddr_len > sizeof(struct sockaddr_un))
- {
- return(-EINVAL);
- }
-
- if (sock->state == SS_CONNECTING)
- return(-EINPROGRESS);
- if (sock->state == SS_CONNECTED)
- return(-EISCONN);
-
- memcpy(&sockun, uservaddr, sockaddr_len);
- sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
- if (sockun.sun_family != AF_UNIX)
- {
- return(-EINVAL);
- }
-
-/*
- * Try to open the name in the filesystem - this is how we
- * identify ourselves and our server. Note that we don't
- * hold onto the inode that long, just enough to find our
- * server. When we're connected, we mooch off the server.
- */
-
- memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
- fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
- old_fs = get_fs();
- set_fs(get_ds());
- i = open_namei(fname, 2, S_IFSOCK, &inode, NULL);
- set_fs(old_fs);
- if (i < 0)
- {
- return(i);
- }
-
- serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
- iput(inode);
- if (!serv_upd)
- {
- return(-EINVAL);
- }
-
- if ((i = sock_awaitconn(sock, serv_upd->socket, flags)) < 0)
- {
- return(i);
- }
-
- if (sock->conn)
- {
- unix_data_ref(UN_DATA(sock->conn));
- UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
- }
- return(0);
-}
-
-
-/*
- * To do a socketpair, we just connect the two datas, easy!
- * Since we always wait on the socket inode, they're no contention
- * for a wait area, and deadlock prevention in the case of a process
- * writing to itself is, ignored, in true unix fashion!
- */
-
-static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
-{
- struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
-
- unix_data_ref(upd1);
- unix_data_ref(upd2);
- upd1->peerupd = upd2;
- upd2->peerupd = upd1;
- return(0);
-}
-
-
-/*
- * On accept, we ref the peer's data for safe writes.
- */
-
-static int unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- struct socket *clientsock;
-
-/*
- * If there aren't any sockets awaiting connection,
- * then wait for one, unless nonblocking.
- */
-
- while(!(clientsock = sock->iconn))
- {
- if (flags & O_NONBLOCK)
- return(-EAGAIN);
- sock->flags |= SO_WAITDATA;
- interruptible_sleep_on(sock->wait);
- sock->flags &= ~SO_WAITDATA;
- if (current->signal & ~current->blocked)
- {
- return(-ERESTARTSYS);
- }
- }
-/*
- * Great. Finish the connection relative to server and client,
- * wake up the client and return the new fd to the server.
- */
-
- sock->iconn = clientsock->next;
- clientsock->next = NULL;
- newsock->conn = clientsock;
- clientsock->conn = newsock;
- clientsock->state = SS_CONNECTED;
- newsock->state = SS_CONNECTED;
- unix_data_ref(UN_DATA(clientsock));
- UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
- UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
- UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
- wake_up_interruptible(clientsock->wait);
- sock_wake_async(clientsock, 0);
- return(0);
-}
-
-
-/*
- * Gets the current name or the name of the connected socket.
- */
-
-static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
- int *usockaddr_len, int peer)
-{
- struct unix_proto_data *upd;
- int len;
-
- if (peer)
- {
- if (sock->state != SS_CONNECTED)
- {
- return(-EINVAL);
- }
- upd = UN_DATA(sock->conn);
- }
- else
- upd = UN_DATA(sock);
-
- len = upd->sockaddr_len;
- memcpy(usockaddr, &upd->sockaddr_un, len);
- *usockaddr_len=len;
- return(0);
-}
-
-
-/*
- * We read from our own buf.
- */
-
-static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
-{
- struct unix_proto_data *upd;
- int todo, avail;
-
- if ((todo = size) <= 0)
- return(0);
-
- upd = UN_DATA(sock);
- while(!(avail = UN_BUF_AVAIL(upd)))
- {
- if (sock->state != SS_CONNECTED)
- {
- return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
- }
- if (nonblock)
- return(-EAGAIN);
- sock->flags |= SO_WAITDATA;
- interruptible_sleep_on(sock->wait);
- sock->flags &= ~SO_WAITDATA;
- if (current->signal & ~current->blocked)
- {
- return(-ERESTARTSYS);
- }
- }
-
-/*
- * Copy from the read buffer into the user's buffer,
- * watching for wraparound. Then we wake up the writer.
- */
-
- unix_lock(upd);
- do
- {
- int part, cando;
-
- if (avail <= 0)
- {
- printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
- send_sig(SIGKILL, current, 1);
- return(-EPIPE);
- }
-
- if ((cando = todo) > avail)
- cando = avail;
- if (cando >(part = BUF_SIZE - upd->bp_tail))
- cando = part;
- memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
- upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
- ubuf += cando;
- todo -= cando;
- if (sock->state == SS_CONNECTED)
- {
- wake_up_interruptible(sock->conn->wait);
- sock_wake_async(sock->conn, 2);
- }
- avail = UN_BUF_AVAIL(upd);
- }
- while(todo && avail);
- unix_unlock(upd);
- return(size - todo);
-}
-
-
-/*
- * We write to our peer's buf. When we connected we ref'd this
- * peer so we are safe that the buffer remains, even after the
- * peer has disconnected, which we check other ways.
- */
-
-static int unix_proto_write(struct socket *sock, const char *ubuf, int size, int nonblock)
-{
- struct unix_proto_data *pupd;
- int todo, space;
-
- if ((todo = size) <= 0)
- return(0);
- if (sock->state != SS_CONNECTED)
- {
- if (sock->state == SS_DISCONNECTING)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- return(-EINVAL);
- }
- pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
-
- while(!(space = UN_BUF_SPACE(pupd)))
- {
- sock->flags |= SO_NOSPACE;
- if (nonblock)
- return(-EAGAIN);
- sock->flags &= ~SO_NOSPACE;
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked)
- {
- return(-ERESTARTSYS);
- }
- if (sock->state == SS_DISCONNECTING)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- }
-
-/*
- * Copy from the user's buffer to the write buffer,
- * watching for wraparound. Then we wake up the reader.
- */
-
- unix_lock(pupd);
-
- do
- {
- int part, cando;
-
- if (space <= 0)
- {
- printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
- send_sig(SIGKILL, current, 1);
- return(-EPIPE);
- }
-
- /*
- * We may become disconnected inside this loop, so watch
- * for it (peerupd is safe until we close).
- */
-
- if (sock->state == SS_DISCONNECTING)
- {
- send_sig(SIGPIPE, current, 1);
- unix_unlock(pupd);
- return(-EPIPE);
- }
-
- if ((cando = todo) > space)
- cando = space;
-
- if (cando >(part = BUF_SIZE - pupd->bp_head))
- cando = part;
-
- memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
- pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
- ubuf += cando;
- todo -= cando;
- if (sock->state == SS_CONNECTED)
- {
- wake_up_interruptible(sock->conn->wait);
- sock_wake_async(sock->conn, 1);
- }
- space = UN_BUF_SPACE(pupd);
- }
- while(todo && space);
-
- unix_unlock(pupd);
- return(size - todo);
-}
-
-/*
- * Select on a unix domain socket.
- */
-
-static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
-{
- struct unix_proto_data *upd, *peerupd;
-
- /*
- * Handle server sockets specially.
- */
- if (sock->flags & SO_ACCEPTCON)
- {
- if (sel_type == SEL_IN)
- {
- if (sock->iconn)
- return(1);
- select_wait(sock->wait, wait);
- return(sock->iconn ? 1 : 0);
- }
- select_wait(sock->wait, wait);
- return(0);
- }
-
- if (sel_type == SEL_IN)
- {
- upd = UN_DATA(sock);
- if (UN_BUF_AVAIL(upd)) /* even if disconnected */
- return(1);
- else if (sock->state != SS_CONNECTED)
- {
- return(1);
- }
- select_wait(sock->wait,wait);
- return(0);
- }
-
- if (sel_type == SEL_OUT)
- {
- if (sock->state != SS_CONNECTED)
- {
- return(1);
- }
- peerupd = UN_DATA(sock->conn);
- if (UN_BUF_SPACE(peerupd) > 0)
- return(1);
- select_wait(sock->wait,wait);
- return(0);
- }
-
- /*
- * Exceptions - SEL_EX
- */
-
- return(0);
-}
-
-
-/*
- * ioctl() calls sent to an AF_UNIX socket
- */
-
-static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct unix_proto_data *upd, *peerupd;
- int er;
-
- upd = UN_DATA(sock);
- peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
-
- switch(cmd)
- {
- case TIOCINQ:
- if (sock->flags & SO_ACCEPTCON)
- return(-EINVAL);
- er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
- if(er)
- return er;
- if (UN_BUF_AVAIL(upd) || peerupd)
- put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
- else
- put_fs_long(0,(unsigned long *)arg);
- break;
- case TIOCOUTQ:
- if (sock->flags & SO_ACCEPTCON)
- return(-EINVAL);
- er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
- if(er)
- return er;
- if (peerupd)
- put_fs_long(UN_BUF_SPACE(peerupd),(unsigned long *)arg);
- else
- put_fs_long(0,(unsigned long *)arg);
- break;
- default:
- return(-EINVAL);
- }
- return(0);
-}
-
-
-static struct proto_ops unix_proto_ops = {
- AF_UNIX,
- unix_proto_create,
- unix_proto_dup,
- unix_proto_release,
- unix_proto_bind,
- unix_proto_connect,
- unix_proto_socketpair,
- unix_proto_accept,
- unix_proto_getname,
- unix_proto_read,
- unix_proto_write,
- unix_proto_select,
- unix_proto_ioctl,
- unix_proto_listen,
- unix_proto_send,
- unix_proto_recv,
- unix_proto_sendto,
- unix_proto_recvfrom,
- unix_proto_shutdown,
- unix_proto_setsockopt,
- unix_proto_getsockopt,
- NULL /* unix_proto_fcntl */
-};
-
-/*
- * Initialise the Unix domain protocol.
- */
-
-void unix_proto_init(struct net_proto *pro)
-{
- struct unix_proto_data *upd;
-
- /*
- * Tell SOCKET that we are alive...
- */
-
- (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
-
- for(upd = unix_datas; upd <= last_unix_data; ++upd)
- {
- upd->refcnt = 0;
- }
-}