diff -urpN linux-2.4.0-test6/drivers/net/irda/Makefile linux-2.4.0-test6-irda-patch/drivers/net/irda/Makefile --- linux-2.4.0-test6/drivers/net/irda/Makefile Sun Aug 13 20:00:01 2000 +++ linux-2.4.0-test6-irda-patch/drivers/net/irda/Makefile Sun Aug 20 22:03:19 2000 @@ -7,110 +7,49 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := irda_drivers.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_IRTTY_SIR),y) -L_OBJS += irtty.o -else - ifeq ($(CONFIG_IRTTY_SIR),m) - M_OBJS += irtty.o - endif -endif - -ifeq ($(CONFIG_IRPORT_SIR),y) -LX_OBJS += irport.o -else - ifeq ($(CONFIG_IRPORT_SIR),m) - MX_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += nsc-ircc.o -else - ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += nsc-ircc.o - endif -endif - -ifeq ($(CONFIG_WINBOND_FIR),y) -L_OBJS += w83977af_ir.o -else - ifeq ($(CONFIG_WINBOND_FIR),m) - M_OBJS += w83977af_ir.o - endif -endif - -ifeq ($(CONFIG_TOSHIBA_FIR),y) -L_OBJS += toshoboe.o -else - ifeq ($(CONFIG_TOSHIBA_FIR),m) - M_OBJS += toshoboe.o - endif -endif - -ifeq ($(CONFIG_SMC_IRCC_FIR),y) -L_OBJS += smc-ircc.o -LX_OBJS += irport.o -else - ifeq ($(CONFIG_SMC_IRCC_FIR),m) - M_OBJS += smc-ircc.o - MX_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_ESI_DONGLE),y) -L_OBJS += esi.o -else - ifeq ($(CONFIG_ESI_DONGLE),m) - M_OBJS += esi.o - endif -endif - -ifeq ($(CONFIG_TEKRAM_DONGLE),y) -L_OBJS += tekram.o -else - ifeq ($(CONFIG_TEKRAM_DONGLE),m) - M_OBJS += tekram.o - endif -endif - -ifeq ($(CONFIG_ACTISYS_DONGLE),y) -L_OBJS += actisys.o -else - ifeq ($(CONFIG_ACTISYS_DONGLE),m) - M_OBJS += actisys.o - endif -endif - -ifeq ($(CONFIG_GIRBIL_DONGLE),y) -L_OBJS += girbil.o -else - ifeq ($(CONFIG_GIRBIL_DONGLE),m) - M_OBJS += girbil.o - endif -endif - -ifeq ($(CONFIG_LITELINK_DONGLE),y) -L_OBJS += litelink.o -else - ifeq ($(CONFIG_LITELINK_DONGLE),m) - M_OBJS += litelink.o - endif -endif - -ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y) -L_OBJS += old_belkin.o -else - ifeq ($(CONFIG_OLD_BELKIN_DONGLE),m) - M_OBJS += old_belkin.o - endif -endif +# All of the (potential) objects that export symbols. -include $(TOPDIR)/Rules.make +export-objs := irport.o + +# Object file lists. +obj-y := +obj-m := +obj-n := +obj- := + +# Each configuration option enables a list of files. + +obj-$(CONFIG_IRTTY_SIR) += irtty.o +obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_NSC_FIR) += nsc-ircc.o +obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o +obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o +obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o +obj-$(CONFIG_SMC_IRCC_FIR) += irport.o +obj-$(CONFIG_ESI_DONGLE) += esi.o +obj-$(CONFIG_TEKRAM_DONGLE) += tekram.o +obj-$(CONFIG_ACTISYS_DONGLE) += actisys.o +obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o +obj-$(CONFIG_LITELINK_DONGLE) += litelink.o +obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) + +# Translate to Rules.make lists. + +L_TARGET := irda_drivers.a +MOD_LIST_NAME := IRDA_DRIVERS_MODULES + +L_OBJS := $(filter-out $(export-objs), $(obj-y)) +LX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(filter-out $(export-objs), $(obj-m)) +MX_OBJS := $(filter $(export-objs), $(obj-m)) + +include $(TOPDIR)/Rules.make + clean: rm -f core *.o *.a *.s diff -urpN linux-2.4.0-test6/drivers/net/irda/irport.c linux-2.4.0-test6-irda-patch/drivers/net/irda/irport.c --- linux-2.4.0-test6/drivers/net/irda/irport.c Tue Mar 21 20:17:28 2000 +++ linux-2.4.0-test6-irda-patch/drivers/net/irda/irport.c Sun Aug 20 22:03:19 2000 @@ -941,7 +941,12 @@ static int irport_net_ioctl(struct net_d switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) + /* + * This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + if (!in_interrupt() && !capable(CAP_NET_ADMIN)) return -EPERM; irda_task_execute(self, __irport_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); @@ -999,7 +1004,9 @@ static struct net_device_stats *irport_n #ifdef MODULE MODULE_PARM(io, "1-4i"); +MODULE_PARM_DESC(io, "Base I/O adresses"); MODULE_PARM(irq, "1-4i"); +MODULE_PARM_DESC(irq, "IRQ lines"); MODULE_AUTHOR("Dag Brattli "); MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode"); diff -urpN linux-2.4.0-test6/drivers/net/irda/irtty.c linux-2.4.0-test6-irda-patch/drivers/net/irda/irtty.c --- linux-2.4.0-test6/drivers/net/irda/irtty.c Tue Mar 21 20:17:28 2000 +++ linux-2.4.0-test6-irda-patch/drivers/net/irda/irtty.c Sun Aug 20 22:03:19 2000 @@ -176,7 +176,7 @@ static int irtty_open(struct tty_struct MINOR(tty->device) - tty->driver.minor_start + tty->driver.name_base); - hashbin_insert(irtty, (queue_t *) self, (int) self, NULL); + hashbin_insert(irtty, (irda_queue_t *) self, (int) self, NULL); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); @@ -233,8 +233,6 @@ static int irtty_open(struct tty_struct ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - /* dev_alloc doesn't clear the struct */ - memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); dev->priv = (void *) self; self->netdev = dev; @@ -962,7 +960,12 @@ static int irtty_net_ioctl(struct net_de switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) + /* + * This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + if (!in_interrupt() && !capable(CAP_NET_ADMIN)) return -EPERM; irda_task_execute(self, irtty_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); @@ -1029,6 +1032,7 @@ MODULE_AUTHOR("Dag Brattli ifr_baudrate); break; @@ -2029,10 +2034,15 @@ MODULE_AUTHOR("Dag Brattli 2050)) { + if ((len < 2) || (len > 2050)) { WARNING(__FUNCTION__ "(), bogus len=%d\n", len); return; } @@ -1039,7 +1039,9 @@ static int ircc_pmproc(struct pm_dev *de MODULE_AUTHOR("Thomas Davis "); MODULE_DESCRIPTION("SMC IrCC controller driver"); MODULE_PARM(ircc_dma, "1i"); +MODULE_PARM_DESC(ircc_dma, "DMA channel"); MODULE_PARM(ircc_irq, "1i"); +MODULE_PARM_DESC(ircc_irq, "IRQ line"); int init_module(void) { diff -urpN linux-2.4.0-test6/drivers/net/irda/toshoboe.c linux-2.4.0-test6-irda-patch/drivers/net/irda/toshoboe.c --- linux-2.4.0-test6/drivers/net/irda/toshoboe.c Tue Mar 21 20:17:28 2000 +++ linux-2.4.0-test6-irda-patch/drivers/net/irda/toshoboe.c Sun Aug 20 22:03:19 2000 @@ -603,7 +603,12 @@ static int toshoboe_net_ioctl(struct net switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) + /* + * This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + if (!in_interrupt() && !capable(CAP_NET_ADMIN)) return -EPERM; /* toshoboe_setbaud(self, irq->ifr_baudrate); */ /* Just change speed once - inserted by Paul Bristow */ @@ -628,7 +633,10 @@ static int toshoboe_net_ioctl(struct net #ifdef MODULE +MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver"); +MODULE_AUTHOR("James McKenzie "); MODULE_PARM (max_baud, "i"); +MODULE_PARM_DESC(max_baus, "Maximum baud rate"); static int toshoboe_close (struct toshoboe_cb *self) diff -urpN linux-2.4.0-test6/drivers/net/irda/w83977af_ir.c linux-2.4.0-test6-irda-patch/drivers/net/irda/w83977af_ir.c --- linux-2.4.0-test6/drivers/net/irda/w83977af_ir.c Tue Mar 21 20:17:28 2000 +++ linux-2.4.0-test6-irda-patch/drivers/net/irda/w83977af_ir.c Sun Aug 20 22:03:19 2000 @@ -255,13 +255,12 @@ int w83977af_open(int i, unsigned int io dev->get_stats = w83977af_net_get_stats; rtnl_lock(); - err = register_netdev(dev); + err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR(__FUNCTION__ "(), register_netdevice() failed!\n"); return -1; } - MESSAGE("IrDA: Registered device %s\n", dev->name); return 0; @@ -1332,7 +1331,12 @@ static int w83977af_net_ioctl(struct net switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) + /* + * This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + if (!in_interrupt() && !capable(CAP_NET_ADMIN)) return -EPERM; w83977af_change_speed(self, irq->ifr_baudrate); break; @@ -1366,9 +1370,11 @@ MODULE_AUTHOR("Dag Brattli */ +struct lsap_cb; /* in */ +struct iriap_cb; /* in */ +struct ias_value; /* in */ +struct discovery_t; /* in */ + /* IrDA Socket */ -struct tsap_cb; struct irda_sock { __u32 saddr; /* my local address */ __u32 daddr; /* peer address */ @@ -137,14 +143,18 @@ struct irda_sock { struct ias_object *ias_obj; /* Our service name + lsap in IAS */ struct iriap_cb *iriap; /* Used to query remote IAS */ - struct ias_value *ias_result; /* Used by getsockopt(IRLMP_IAS_QUERY) */ + struct ias_value *ias_result; /* Result of remote IAS query */ + + hashbin_t *cachelog; /* Result of discovery query */ + struct discovery_t *cachediscovery; /* Result of selective discovery query */ int nslots; /* Number of slots to use for discovery */ int errno; /* status of the IAS query */ struct sock *sk; - wait_queue_head_t ias_wait; /* Wait for LM-IAS answer */ + wait_queue_head_t query_wait; /* Wait for the answer to a query */ + struct timer_list watchdog; /* Timeout for discovery */ LOCAL_FLOW tx_flow; LOCAL_FLOW rx_flow; diff -urpN linux-2.4.0-test6/include/net/irda/irda_device.h linux-2.4.0-test6-irda-patch/include/net/irda/irda_device.h --- linux-2.4.0-test6/include/net/irda/irda_device.h Sun Aug 13 20:02:19 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irda_device.h Sun Aug 20 22:03:00 2000 @@ -79,7 +79,7 @@ struct irda_task; typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task); struct irda_task { - queue_t q; + irda_queue_t q; magic_t magic; IRDA_TASK_STATE state; @@ -111,7 +111,7 @@ typedef struct { /* Dongle registration info */ struct dongle_reg { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ IRDA_DONGLE type; void (*open)(dongle_t *dongle, struct qos_info *qos); diff -urpN linux-2.4.0-test6/include/net/irda/iriap.h linux-2.4.0-test6-irda-patch/include/net/irda/iriap.h --- linux-2.4.0-test6/include/net/irda/iriap.h Sun Aug 13 20:08:43 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/iriap.h Sun Aug 20 22:03:00 2000 @@ -58,7 +58,7 @@ typedef void (*CONFIRM_CALLBACK)(int res struct ias_value *value, void *priv); struct iriap_cb { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ magic_t magic; /* Magic cookie */ int mode; /* Client or server */ diff -urpN linux-2.4.0-test6/include/net/irda/irias_object.h linux-2.4.0-test6-irda-patch/include/net/irda/irias_object.h --- linux-2.4.0-test6/include/net/irda/irias_object.h Sun Aug 13 20:08:43 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irias_object.h Sun Aug 20 22:03:00 2000 @@ -34,11 +34,15 @@ #define IAS_OCT_SEQ 2 #define IAS_STRING 3 +/* Object ownership of attributes (user or kernel) */ +#define IAS_KERNEL_ATTR 0 +#define IAS_USER_ATTR 1 + /* * LM-IAS Object */ struct ias_object { - queue_t q; /* Must be first! */ + irda_queue_t q; /* Must be first! */ magic_t magic; char *name; @@ -51,6 +55,7 @@ struct ias_object { */ struct ias_value { __u8 type; /* Value description */ + __u8 owner; /* Managed from user/kernel space */ int charset; /* Only used by string type */ int len; @@ -66,7 +71,7 @@ struct ias_value { * Attributes used by LM-IAS objects */ struct ias_attrib { - queue_t q; /* Must be first! */ + irda_queue_t q; /* Must be first! */ int magic; char *name; /* Attribute name */ @@ -78,12 +83,15 @@ char *strdup(char *str); struct ias_object *irias_new_object(char *name, int id); void irias_insert_object(struct ias_object *obj); int irias_delete_object(struct ias_object *obj); +int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib); void __irias_delete_object(struct ias_object *obj); -void irias_add_integer_attrib(struct ias_object *obj, char *name, int value); -void irias_add_string_attrib(struct ias_object *obj, char *name, char *value); +void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, + int user); +void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, + int user); void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, - int len); + int len, int user); int irias_object_change_attribute(char *obj_name, char *attrib_name, struct ias_value *new_value); struct ias_object *irias_find_object(char *name); diff -urpN linux-2.4.0-test6/include/net/irda/irlan_client.h linux-2.4.0-test6-irda-patch/include/net/irda/irlan_client.h --- linux-2.4.0-test6/include/net/irda/irlan_client.h Sun Aug 13 20:09:07 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irlan_client.h Sun Aug 20 22:03:00 2000 @@ -34,7 +34,7 @@ #include void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout); -void irlan_client_discovery_indication(discovery_t *); +void irlan_client_discovery_indication(discovery_t *, void *); void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr); void irlan_client_open_ctrl_tsap( struct irlan_cb *self); diff -urpN linux-2.4.0-test6/include/net/irda/irlan_common.h linux-2.4.0-test6-irda-patch/include/net/irda/irlan_common.h --- linux-2.4.0-test6/include/net/irda/irlan_common.h Sun Aug 13 20:09:07 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irlan_common.h Sun Aug 20 22:03:00 2000 @@ -161,28 +161,26 @@ struct irlan_provider_cb { * IrLAN control block */ struct irlan_cb { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ int magic; struct net_device dev; /* Ethernet device structure*/ struct net_device_stats stats; - __u32 saddr; /* Source device address */ - __u32 daddr; /* Destination device address */ - int netdev_registered; - int notify_irmanager; + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + int disconnect_reason; /* Why we got disconnected */ - int media; /* Media type */ - __u8 version[2]; /* IrLAN version */ + int media; /* Media type */ + __u8 version[2]; /* IrLAN version */ - struct tsap_cb *tsap_data; + struct tsap_cb *tsap_data; /* Data TSAP */ - int master; /* Master instance? */ - int use_udata; /* Use Unit Data transfers */ + int use_udata; /* Use Unit Data transfers */ - __u8 stsap_sel_data; /* Source data TSAP selector */ - __u8 dtsap_sel_data; /* Destination data TSAP selector */ - __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */ + __u8 stsap_sel_data; /* Source data TSAP selector */ + __u8 dtsap_sel_data; /* Destination data TSAP selector */ + __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */ struct irlan_client_cb client; /* Client specific fields */ struct irlan_provider_cb provider; /* Provider specific fields */ @@ -190,10 +188,11 @@ struct irlan_cb { __u32 max_sdu_size; __u8 max_header_size; + wait_queue_head_t open_wait; struct timer_list watchdog_timer; }; -struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev); +struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr); void irlan_close(struct irlan_cb *self); void irlan_close_tsaps(struct irlan_cb *self); void irlan_mod_inc_use_count(void); diff -urpN linux-2.4.0-test6/include/net/irda/irlap.h linux-2.4.0-test6-irda-patch/include/net/irda/irlap.h --- linux-2.4.0-test6/include/net/irda/irlap.h Sun Aug 13 20:02:19 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irlap.h Sun Aug 20 22:03:00 2000 @@ -81,7 +81,7 @@ #define irda_incomp (*self->decompressor.cp->incomp) struct irda_compressor { - queue_t q; + irda_queue_t q; struct compressor *cp; void *state; /* Not used by IrDA */ @@ -90,7 +90,7 @@ struct irda_compressor { /* Main structure of IrLAP */ struct irlap_cb { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ magic_t magic; struct net_device *netdev; diff -urpN linux-2.4.0-test6/include/net/irda/irlmp.h linux-2.4.0-test6-irda-patch/include/net/irda/irlmp.h --- linux-2.4.0-test6/include/net/irda/irlmp.h Sun Aug 13 20:06:05 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irlmp.h Sun Aug 20 22:03:00 2000 @@ -71,22 +71,23 @@ typedef enum { S_END, } SERVICE; -typedef void (*DISCOVERY_CALLBACK1) (discovery_t *); -typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *); +typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, void *); +typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *); typedef struct { - queue_t queue; /* Must be first */ + irda_queue_t queue; /* Must be first */ __u16 hints; /* Hint bits */ } irlmp_service_t; typedef struct { - queue_t queue; /* Must be first */ + irda_queue_t queue; /* Must be first */ __u16 hint_mask; DISCOVERY_CALLBACK1 callback1; DISCOVERY_CALLBACK2 callback2; + void *priv; /* Used to identify client */ } irlmp_client_t; struct lap_cb; /* Forward decl. */ @@ -95,7 +96,7 @@ struct lap_cb; /* Forward decl. */ * Information about each logical LSAP connection */ struct lsap_cb { - queue_t queue; /* Must be first */ + irda_queue_t queue; /* Must be first */ magic_t magic; int connected; @@ -121,7 +122,7 @@ struct lsap_cb { * Information about each registred IrLAP layer */ struct lap_cb { - queue_t queue; /* Must be first */ + irda_queue_t queue; /* Must be first */ magic_t magic; int reason; /* LAP disconnect reason */ @@ -174,10 +175,10 @@ struct irlmp_cb { hashbin_t *clients; hashbin_t *services; - hashbin_t *cachelog; - int running; + hashbin_t *cachelog; /* Current discovery log */ + spinlock_t log_lock; /* discovery log spinlock */ - spinlock_t lock; + int running; __u16_host_order hints; /* Hint bits */ }; @@ -192,10 +193,10 @@ __u16 irlmp_service_to_hint(int service) __u32 irlmp_register_service(__u16 hints); int irlmp_unregister_service(__u32 handle); __u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1, - DISCOVERY_CALLBACK2 callback2); + DISCOVERY_CALLBACK2 callback2, void *priv); int irlmp_unregister_client(__u32 handle); int irlmp_update_client(__u32 handle, __u16 hint_mask, - DISCOVERY_CALLBACK1, DISCOVERY_CALLBACK2); + DISCOVERY_CALLBACK1, DISCOVERY_CALLBACK2, void *priv); void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *); void irlmp_unregister_link(__u32 saddr); @@ -214,6 +215,7 @@ int irlmp_disconnect_request(struct lsa void irlmp_discovery_confirm(hashbin_t *discovery_log); void irlmp_discovery_request(int nslots); +struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask); void irlmp_do_discovery(int nslots); discovery_t *irlmp_get_discovery_response(void); diff -urpN linux-2.4.0-test6/include/net/irda/irmod.h linux-2.4.0-test6-irda-patch/include/net/irda/irmod.h --- linux-2.4.0-test6/include/net/irda/irmod.h Sun Aug 13 20:06:04 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irmod.h Sun Aug 20 22:03:00 2000 @@ -69,7 +69,7 @@ typedef void (*TODO_CALLBACK)( void *sel * addtional information */ struct irda_event { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ struct irmanager_event event; }; @@ -78,7 +78,7 @@ struct irda_event { * Funtions with needs to be called with a process context */ struct irda_todo { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ void *self; TODO_CALLBACK callback; @@ -94,8 +94,8 @@ struct irda_cb { int in_use; - queue_t *event_queue; /* Events queued for the irmanager */ - queue_t *todo_queue; /* Todo list */ + irda_queue_t *event_queue; /* Events queued for the irmanager */ + irda_queue_t *todo_queue; /* Todo list */ }; int irmod_init_module(void); diff -urpN linux-2.4.0-test6/include/net/irda/irqueue.h linux-2.4.0-test6-irda-patch/include/net/irda/irqueue.h --- linux-2.4.0-test6/include/net/irda/irqueue.h Sun Aug 13 20:02:19 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irqueue.h Sun Aug 20 22:03:00 2000 @@ -30,8 +30,8 @@ #include #include -#ifndef QUEUE_H -#define QUEUE_H +#ifndef IRDA_QUEUE_H +#define IRDA_QUEUE_H #define NAME_SIZE 32 @@ -62,39 +62,39 @@ typedef void (*FREE_FUNC)(void *arg); */ #define GET_HASHBIN(x) ( x & HASHBIN_MASK ) -struct irqueue { - struct irqueue *q_next; - struct irqueue *q_prev; +struct irda_queue { + struct irda_queue *q_next; + struct irda_queue *q_prev; char q_name[NAME_SIZE]; __u32 q_hash; }; -typedef struct irqueue queue_t; +typedef struct irda_queue irda_queue_t; typedef struct hashbin_t { __u32 magic; int hb_type; int hb_size; spinlock_t hb_mutex[HASHBIN_SIZE] ALIGN; - queue_t *hb_queue[HASHBIN_SIZE] ALIGN; + irda_queue_t *hb_queue[HASHBIN_SIZE] ALIGN; - queue_t* hb_current; + irda_queue_t* hb_current; } hashbin_t; hashbin_t *hashbin_new(int type); int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func); int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func); -void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, +void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, char* name); void* hashbin_find(hashbin_t* hashbin, __u32 hashv, char* name); void* hashbin_remove(hashbin_t* hashbin, __u32 hashv, char* name); void* hashbin_remove_first(hashbin_t *hashbin); -queue_t *hashbin_get_first(hashbin_t *hashbin); -queue_t *hashbin_get_next(hashbin_t *hashbin); +irda_queue_t *hashbin_get_first(hashbin_t *hashbin); +irda_queue_t *hashbin_get_next(hashbin_t *hashbin); -void enqueue_last(queue_t **queue, queue_t* element); -void enqueue_first(queue_t **queue, queue_t* element); -queue_t *dequeue_first(queue_t **queue); +void enqueue_last(irda_queue_t **queue, irda_queue_t* element); +void enqueue_first(irda_queue_t **queue, irda_queue_t* element); +irda_queue_t *dequeue_first(irda_queue_t **queue); #define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size diff -urpN linux-2.4.0-test6/include/net/irda/irttp.h linux-2.4.0-test6-irda-patch/include/net/irda/irttp.h --- linux-2.4.0-test6/include/net/irda/irttp.h Sun Aug 13 20:08:43 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irttp.h Sun Aug 20 22:03:00 2000 @@ -63,7 +63,7 @@ * connection. */ struct tsap_cb { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ magic_t magic; /* Just in case */ __u8 stsap_sel; /* Source TSAP */ diff -urpN linux-2.4.0-test6/include/net/irda/irtty.h linux-2.4.0-test6-irda-patch/include/net/irda/irtty.h --- linux-2.4.0-test6/include/net/irda/irtty.h Sun Aug 13 20:06:05 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/irtty.h Sun Aug 20 22:03:00 2000 @@ -45,7 +45,7 @@ struct irtty_info { #define IRTTY_IOC_MAXNR 2 struct irtty_cb { - queue_t q; /* Must be first */ + irda_queue_t q; /* Must be first */ magic_t magic; struct net_device *netdev; /* Yes! we are some kind of netdevice */ diff -urpN linux-2.4.0-test6/include/net/irda/timer.h linux-2.4.0-test6-irda-patch/include/net/irda/timer.h --- linux-2.4.0-test6/include/net/irda/timer.h Sun Aug 13 20:06:05 2000 +++ linux-2.4.0-test6-irda-patch/include/net/irda/timer.h Sun Aug 20 22:03:00 2000 @@ -82,6 +82,7 @@ struct lap_cb; inline void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout); inline void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout); inline void irlmp_start_idle_timer(struct lap_cb *, int timeout); +inline void irlmp_stop_idle_timer(struct lap_cb *self); #endif Binary files linux-2.4.0-test6/net/irda/.irqueue.c.swp and linux-2.4.0-test6-irda-patch/net/irda/.irqueue.c.swp differ diff -urpN linux-2.4.0-test6/net/irda/af_irda.c linux-2.4.0-test6-irda-patch/net/irda/af_irda.c --- linux-2.4.0-test6/net/irda/af_irda.c Mon Apr 24 22:43:05 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/af_irda.c Sun Aug 20 22:03:12 2000 @@ -11,7 +11,7 @@ * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. * * Copyright (c) 1999 Dag Brattli - * Copyright (c) 1999 Jean Tourrilhes + * Copyright (c) 1999 Jean Tourrilhes * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -79,9 +79,6 @@ static struct proto_ops irda_ultra_ops; #define ULTRA_MAX_DATA 382 #endif /* CONFIG_IRDA_ULTRA */ -static hashbin_t *cachelog = NULL; -static DECLARE_WAIT_QUEUE_HEAD(discovery_wait); /* Wait for discovery */ - #define IRDA_MAX_HEADER (TTP_MAX_HEADER) /* @@ -326,19 +323,19 @@ static void irda_flow_indication(void *i /* * Function irda_getvalue_confirm (obj_id, value, priv) * - * Got answer from remote LM-IAS + * Got answer from remote LM-IAS, just pass object to requester... * + * Note : duplicate from above, but we need our own version that + * doesn't touch the dtsap_sel and save the full value structure... */ static void irda_getvalue_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv) + struct ias_value *value, void *priv) { struct irda_sock *self; IRDA_DEBUG(2, __FUNCTION__ "()\n"); - ASSERT(priv != NULL, return;); self = (struct irda_sock *) priv; - if (!self) { WARNING(__FUNCTION__ "(), lost myself!\n"); return; @@ -348,51 +345,117 @@ static void irda_getvalue_confirm(int re iriap_close(self->iriap); self->iriap = NULL; - self->errno = result; - /* Check if request succeeded */ if (result != IAS_SUCCESS) { - IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), IAS query failed! (%d)\n", + result); + + self->errno = result; /* We really need it later */ /* Wake up any processes waiting for result */ - wake_up_interruptible(&self->ias_wait); + wake_up_interruptible(&self->query_wait); return; } - switch (value->type) { - case IAS_INTEGER: - IRDA_DEBUG(4, __FUNCTION__ "() int=%d\n", value->t.integer); - - if (value->t.integer != -1) { - self->dtsap_sel = value->t.integer; - } else - self->dtsap_sel = 0; - break; - default: - IRDA_DEBUG(0, __FUNCTION__ "(), bad type!\n"); - break; - } - irias_delete_value(value); + /* Pass the object to the caller (so the caller must delete it) */ + self->ias_result = value; + self->errno = 0; /* Wake up any processes waiting for result */ - wake_up_interruptible(&self->ias_wait); + wake_up_interruptible(&self->query_wait); } +#if 0 +/* Obsolete */ /* * Function irda_discovery_indication (log) * - * Got a discovery log from IrLMP, wake ut any process waiting for answer + * Got a discovery log from IrLMP, wake up any process waiting for answer + * + */ +static void irda_discovery_indication(hashbin_t *log, void *priv) +{ + struct irda_sock *self; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + self = (struct irda_sock *) priv; + if (!self) { + WARNING(__FUNCTION__ "(), lost myself!\n"); + return; + } + + self->cachelog = log; + + /* Wake up process if its waiting for device to be discovered */ + wake_up_interruptible(&self->query_wait); +} +#endif + +/* + * Function irda_selective_discovery_indication (discovery) + * + * Got a selective discovery indication from IrLMP. * + * IrLMP is telling us that this node is matching our hint bit + * filter. Check if it's a newly discovered node (or if node changed its + * hint bits), and then wake up any process waiting for answer... */ -static void irda_discovery_indication(hashbin_t *log) +static void irda_selective_discovery_indication(discovery_t *discovery, + void *priv) { + struct irda_sock *self; + IRDA_DEBUG(2, __FUNCTION__ "()\n"); - cachelog = log; + self = (struct irda_sock *) priv; + if (!self) { + WARNING(__FUNCTION__ "(), lost myself!\n"); + return; + } + + /* Check if node is discovered is a new one or an old one. + * We check when how long ago this node was discovered, with a + * coarse timeout (we may miss some discovery events or be delayed). + * Note : by doing this test here, we avoid waking up a process ;-) + */ + if((jiffies - discovery->first_timestamp) > + (sysctl_discovery_timeout * HZ)) { + return; /* Too old, not interesting -> goodbye */ + } + + /* Pass parameter to the caller */ + self->cachediscovery = discovery; /* Wake up process if its waiting for device to be discovered */ - wake_up_interruptible(&discovery_wait); + wake_up_interruptible(&self->query_wait); +} + +/* + * Function irda_discovery_timeout (priv) + * + * Timeout in the selective discovery process + * + * We were waiting for a node to be discovered, but nothing has come up + * so far. Wake up the user and tell him that we failed... + */ +static void irda_discovery_timeout(u_long priv) +{ + struct irda_sock *self; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + self = (struct irda_sock *) priv; + ASSERT(self != NULL, return;); + + /* Nothing for the caller */ + self->cachelog = NULL; + self->cachediscovery = NULL; + self->errno = -ETIME; + + /* Wake up process if its still waiting... */ + wake_up_interruptible(&self->query_wait); } /* @@ -470,6 +533,11 @@ static int irda_open_lsap(struct irda_so * * Try to lookup LSAP selector in remote LM-IAS * + * Basically, we start a IAP query, and then go to sleep. When the query + * return, irda_getvalue_confirm will wake us up, and we can examine the + * result of the query... + * Note that in some case, the query fail even before we go to sleep, + * creating some races... */ static int irda_find_lsap_sel(struct irda_sock *self, char *name) { @@ -485,19 +553,53 @@ static int irda_find_lsap_sel(struct ird self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, irda_getvalue_confirm); + /* Treat unexpected signals as disconnect */ + self->errno = -EHOSTUNREACH; + /* Query remote LM-IAS */ iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr, name, "IrDA:TinyTP:LsapSel"); - /* Wait for answer */ - interruptible_sleep_on(&self->ias_wait); + /* Wait for answer (if not already failed) */ + if(self->iriap != NULL) + interruptible_sleep_on(&self->query_wait); + + /* Check what happened */ + if (self->errno) + { + /* Requested object/attribute doesn't exist */ + if((self->errno == IAS_CLASS_UNKNOWN) || + (self->errno == IAS_ATTRIB_UNKNOWN)) + return (-EADDRNOTAVAIL); + else + return (-EHOSTUNREACH); + } + + /* Get the remote TSAP selector */ + switch (self->ias_result->type) { + case IAS_INTEGER: + IRDA_DEBUG(4, __FUNCTION__ "() int=%d\n", + self->ias_result->t.integer); + + if (self->ias_result->t.integer != -1) + self->dtsap_sel = self->ias_result->t.integer; + else + self->dtsap_sel = 0; + break; + default: + self->dtsap_sel = 0; + IRDA_DEBUG(0, __FUNCTION__ "(), bad type!\n"); + break; + } + if (self->ias_result) + irias_delete_value(self->ias_result); if (self->dtsap_sel) return 0; - return -ENETUNREACH; /* May not be true */ + return -EADDRNOTAVAIL; } - /* +/* * Function irda_discover_daddr_and_lsap_sel (self, name) * * This try to find a device with the requested service. @@ -516,71 +618,78 @@ static int irda_find_lsap_sel(struct ird */ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) { - discovery_t *discovery; - int err = -ENETUNREACH; - __u32 daddr = 0x0; /* Address we found the service on */ + struct irda_device_info *discoveries; /* Copy of the discovery log */ + int number; /* Number of nodes in the log */ + int i; + int err = -ENETUNREACH; + __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */ __u8 dtsap_sel = 0x0; /* TSAP associated with it */ IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name); ASSERT(self != NULL, return -1;); - /* Tell IrLMP we want to be notified */ - irlmp_update_client(self->ckey, self->mask, NULL, - irda_discovery_indication); - - /* Do some discovery */ - irlmp_discovery_request(self->nslots); - + /* Ask lmp for the current discovery log + * Note : we have to use irlmp_get_discoveries(), as opposed + * to play with the cachelog directly, because while we are + * making our ias query, le log might change... */ + discoveries = irlmp_get_discoveries(&number, self->mask); /* Check if the we got some results */ - if (!cachelog) - /* Wait for answer */ - /*interruptible_sleep_on(&self->discovery_wait);*/ - return -EAGAIN; + if (discoveries == NULL) + return -ENETUNREACH; /* No nodes discovered */ /* * Now, check all discovered devices (if any), and connect * client only about the services that the client is * interested in... */ - discovery = (discovery_t *) hashbin_get_first(cachelog); - while (discovery != NULL) { - /* Mask out the ones we don't want */ - if (discovery->hints.word & self->mask) { - /* Try this address */ - self->daddr = discovery->daddr; - self->saddr = 0x0; - IRDA_DEBUG(1, __FUNCTION__ "(), trying daddr = %08x\n", - self->daddr); - - /* Query remote LM-IAS for this service */ - err = irda_find_lsap_sel(self, name); - if (err == 0) { - /* We found the requested service */ - if(daddr != 0x0) { - IRDA_DEBUG(0, __FUNCTION__ - "(), discovered service ''%s'' in two different devices !!!\n", - name); - return(-ENOTUNIQ); - } - /* First time we foun that one, save it ! */ - daddr = self->daddr; - dtsap_sel = self->dtsap_sel; + for(i = 0; i < number; i++) { + /* Try the address in the log */ + self->daddr = discoveries[i].daddr; + self->saddr = 0x0; + IRDA_DEBUG(1, __FUNCTION__ "(), trying daddr = %08x\n", + self->daddr); + + /* Query remote LM-IAS for this service */ + err = irda_find_lsap_sel(self, name); + switch (err) { + case 0: + /* We found the requested service */ + if(daddr != DEV_ADDR_ANY) { + IRDA_DEBUG(1, __FUNCTION__ + "(), discovered service ''%s'' in two different devices !!!\n", + name); + self->daddr = DEV_ADDR_ANY; + kfree(discoveries); + return(-ENOTUNIQ); } + /* First time we found that one, save it ! */ + daddr = self->daddr; + dtsap_sel = self->dtsap_sel; + break; + case -EADDRNOTAVAIL: + /* Requested service simply doesn't exist on this node */ + break; + default: + /* Something bad did happen :-( */ + IRDA_DEBUG(0, __FUNCTION__ + "(), unexpected IAS query failure\n"); + self->daddr = DEV_ADDR_ANY; + kfree(discoveries); + return(-EHOSTUNREACH); + break; } - - /* Next node, maybe we will be more lucky... */ - discovery = (discovery_t *) hashbin_get_next(cachelog); } - cachelog = NULL; + /* Cleanup our copy of the discovery log */ + kfree(discoveries); /* Check out what we found */ - if(daddr == 0x0) { - IRDA_DEBUG(0, __FUNCTION__ + if(daddr == DEV_ADDR_ANY) { + IRDA_DEBUG(1, __FUNCTION__ "(), cannot discover service ''%s'' in any device !!!\n", name); - self->daddr = 0; /* Guessing */ - return(-ENETUNREACH); + self->daddr = DEV_ADDR_ANY; + return(-EADDRNOTAVAIL); } /* Revert back to discovered device & service */ @@ -588,7 +697,7 @@ static int irda_discover_daddr_and_lsap_ self->saddr = 0x0; self->dtsap_sel = dtsap_sel; - IRDA_DEBUG(0, __FUNCTION__ + IRDA_DEBUG(1, __FUNCTION__ "(), discovered requested service ''%s'' at address %08x\n", name, self->daddr); @@ -606,25 +715,26 @@ static int irda_getname(struct socket *s { struct sockaddr_irda saddr; struct sock *sk = sock->sk; + struct irda_sock *self = sk->protinfo.irda; if (peer) { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; saddr.sir_family = AF_IRDA; - saddr.sir_lsap_sel = sk->protinfo.irda->dtsap_sel; - saddr.sir_addr = sk->protinfo.irda->daddr; + saddr.sir_lsap_sel = self->dtsap_sel; + saddr.sir_addr = self->daddr; } else { saddr.sir_family = AF_IRDA; - saddr.sir_lsap_sel = sk->protinfo.irda->stsap_sel; - saddr.sir_addr = sk->protinfo.irda->saddr; + saddr.sir_lsap_sel = self->stsap_sel; + saddr.sir_addr = self->saddr; } IRDA_DEBUG(1, __FUNCTION__ "(), tsap_sel = %#x\n", saddr.sir_lsap_sel); IRDA_DEBUG(1, __FUNCTION__ "(), addr = %08x\n", saddr.sir_addr); - if (*uaddr_len > sizeof (struct sockaddr_irda)) - *uaddr_len = sizeof (struct sockaddr_irda); + /* uaddr_len come to us uninitialised */ + *uaddr_len = sizeof (struct sockaddr_irda); memcpy(uaddr, &saddr, *uaddr_len); return 0; @@ -709,7 +819,7 @@ static int irda_bind(struct socket *sock /* Register with LM-IAS */ self->ias_obj = irias_new_object(addr->sir_name, jiffies); irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", - self->stsap_sel); + self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); #if 1 /* Will be removed in near future */ @@ -821,6 +931,20 @@ static int irda_accept(struct socket *so * * Connect to a IrDA device * + * The main difference with a "standard" connect is that with IrDA we need + * to resolve the service name into a TSAP selector (in TCP, port number + * doesn't have to be resolved). + * Because of this service name resoltion, we can offer "auto-connect", + * where we connect to a service without specifying a destination address. + * + * Note : by consulting "errno", the user space caller may learn the cause + * of the failure. Most of them are visible in the function, others may come + * from subroutines called and are listed here : + * o EBUSY : already processing a connect + * o EHOSTUNREACH : bad addr->sir_addr argument + * o EADDRNOTAVAIL : bad addr->sir_name argument + * o ENOTUNIQ : more than one node has addr->sir_name (auto-connect) + * o ENETUNREACH : no node found on the network (auto-connect) */ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) @@ -858,13 +982,13 @@ static int irda_connect(struct socket *s return -EINVAL; /* Check if user supplied any destination device address */ - if (!addr->sir_addr) { + if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) { /* Try to find one suitable */ err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name); if (err) { IRDA_DEBUG(0, __FUNCTION__ "(), auto-connect failed!\n"); - return -EINVAL; + return err; } } else { /* Use the one provided by the user */ @@ -922,6 +1046,9 @@ static int irda_connect(struct socket *s sti(); + /* At this point, IrLMP has assigned our source address */ + self->saddr = irttp_get_saddr(self->tsap); + return 0; } @@ -957,7 +1084,7 @@ static int irda_create(struct socket *so return -ENOMEM; memset(self, 0, sizeof(struct irda_sock)); - init_waitqueue_head(&self->ias_wait); + init_waitqueue_head(&self->query_wait); self->sk = sk; sk->protinfo.irda = self; @@ -996,11 +1123,12 @@ static int irda_create(struct socket *so sk->protocol = protocol; /* Register as a client with IrLMP */ - self->ckey = irlmp_register_client(0, NULL, NULL); + self->ckey = irlmp_register_client(0, NULL, NULL, NULL); self->mask = 0xffff; self->rx_flow = self->tx_flow = FLOW_START; self->nslots = DISCOVERY_DEFAULT_SLOTS; - self->daddr = DEV_ADDR_ANY; + self->daddr = DEV_ADDR_ANY; /* Until we get connected */ + self->saddr = 0x0; /* so IrLMP assign us any link */ /* Notify that we are using the irda module, so nobody removes it */ irda_mod_inc_use_count(); @@ -1096,7 +1224,8 @@ static int irda_sendmsg(struct socket *s IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len); - if (msg->msg_flags & ~MSG_DONTWAIT) + /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ + if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR)) return -EINVAL; if (sk->shutdown & SEND_SHUTDOWN) { @@ -1483,6 +1612,11 @@ static int irda_shutdown(struct socket * self->tsap = NULL; } + /* A few cleanup so the socket look as good as new... */ + self->rx_flow = self->tx_flow = FLOW_START; /* needed ??? */ + self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ + self->saddr = 0x0; /* so IrLMP assign us any link */ + return 0; } @@ -1606,6 +1740,7 @@ static int irda_setsockopt(struct socket struct irda_sock *self; struct irda_ias_set ias_opt; struct ias_object *ias_obj; + struct ias_attrib * ias_attr; /* Attribute in IAS object */ int opt; self = sk->protinfo.irda; @@ -1616,6 +1751,13 @@ static int irda_setsockopt(struct socket switch (optname) { case IRLMP_IAS_SET: + /* The user want to add an attribute to an existing IAS object + * (in the IAS database) or to create a new object with this + * attribute. + * We first query IAS to know if the object exist, and then + * create the right attribute... + */ + if (optlen != sizeof(struct irda_ias_set)) return -EINVAL; @@ -1639,9 +1781,11 @@ static int irda_setsockopt(struct socket switch(ias_opt.irda_attrib_type) { case IAS_INTEGER: /* Add an integer attribute */ - irias_add_integer_attrib(ias_obj, - ias_opt.irda_attrib_name, - ias_opt.attribute.irda_attrib_int); + irias_add_integer_attrib( + ias_obj, + ias_opt.irda_attrib_name, + ias_opt.attribute.irda_attrib_int, + IAS_USER_ATTR); break; case IAS_OCT_SEQ: /* Check length */ @@ -1653,7 +1797,8 @@ static int irda_setsockopt(struct socket ias_obj, ias_opt.irda_attrib_name, ias_opt.attribute.irda_attrib_octet_seq.octet_seq, - ias_opt.attribute.irda_attrib_octet_seq.len); + ias_opt.attribute.irda_attrib_octet_seq.len, + IAS_USER_ATTR); break; case IAS_STRING: /* Should check charset & co */ @@ -1667,16 +1812,49 @@ static int irda_setsockopt(struct socket irias_add_string_attrib( ias_obj, ias_opt.irda_attrib_name, - ias_opt.attribute.irda_attrib_string.string); + ias_opt.attribute.irda_attrib_string.string, + IAS_USER_ATTR); break; default : return -EINVAL; } irias_insert_object(ias_obj); break; + case IRLMP_IAS_DEL: + /* The user want to delete an object from our local IAS + * database. We just need to query the IAS, check is the + * object is not owned by the kernel and delete it. + */ - IRDA_DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n"); - return -ENOPROTOOPT; + if (optlen != sizeof(struct irda_ias_set)) + return -EINVAL; + + /* Copy query to the driver. */ + if (copy_from_user(&ias_opt, (char *)optval, optlen)) + return -EFAULT; + + /* Find the object we target */ + ias_obj = irias_find_object(ias_opt.irda_class_name); + if(ias_obj == (struct ias_object *) NULL) + return -EINVAL; + + /* Find the attribute (in the object) we target */ + ias_attr = irias_find_attrib(ias_obj, + ias_opt.irda_attrib_name); + if(ias_attr == (struct ias_attrib *) NULL) + return -EINVAL; + + /* Check is the user space own the object */ + if(ias_attr->value->owner != IAS_USER_ATTR) { + IRDA_DEBUG(1, __FUNCTION__ + "(), attempting to delete a kernel attribute\n"); + return -EPERM; + } + + /* Remove the attribute (and maybe the object) */ + irias_delete_attrib(ias_obj, ias_attr); + + break; case IRLMP_MAX_SDU_SIZE: if (optlen < sizeof(int)) return -EINVAL; @@ -1709,60 +1887,31 @@ static int irda_setsockopt(struct socket self->skey = irlmp_register_service((__u16) opt); break; - default: - return -ENOPROTOOPT; - } - return 0; -} - - /* - * Function irda_simple_getvalue_confirm (obj_id, value, priv) - * - * Got answer from remote LM-IAS, just copy object to requester... - * - * Note : duplicate from above, but we need our own version that - * doesn't touch the dtsap_sel and save the full value structure... - */ -static void irda_simple_getvalue_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv) -{ - struct irda_sock *self; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - - ASSERT(priv != NULL, return;); - self = (struct irda_sock *) priv; + case IRLMP_HINT_MASK_SET: + /* As opposed to the previous case which set the hint bits + * that we advertise, this one set the filter we use when + * making a discovery (nodes which don't match any hint + * bit in the mask are not reported). + */ + if (optlen < sizeof(int)) + return -EINVAL; - if (!self) { - WARNING(__FUNCTION__ "(), lost myself!\n"); - return; - } - - /* We probably don't need to make any more queries */ - iriap_close(self->iriap); - self->iriap = NULL; - - /* Check if request succeeded */ - if (result != IAS_SUCCESS) { - IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n"); - - self->errno = -EHOSTUNREACH; + if (get_user(opt, (int *)optval)) + return -EFAULT; - /* Wake up any processes waiting for result */ - wake_up_interruptible(&self->ias_wait); + /* Set the new hint mask */ + self->mask = (__u16) opt; + /* Mask out extension bits */ + self->mask &= 0x7f7f; + /* Check if no bits */ + if(!self->mask) + self->mask = 0xFFFF; - return; + break; + default: + return -ENOPROTOOPT; } - - /* Clone the object (so the requester can free it) */ - self->ias_result = kmalloc(sizeof(struct ias_value), GFP_ATOMIC); - memcpy(self->ias_result, value, sizeof(struct ias_value)); - irias_delete_value(value); - - self->errno = 0; - - /* Wake up any processes waiting for result */ - wake_up_interruptible(&self->ias_wait); + return 0; } /* @@ -1803,6 +1952,7 @@ static int irda_extract_ias_value(struct /* NULL terminate the string (avoid troubles) */ ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0'; break; + case IAS_MISSING: default : return -EINVAL; } @@ -1825,11 +1975,11 @@ static int irda_getsockopt(struct socket struct sock *sk = sock->sk; struct irda_sock *self; struct irda_device_list list; - struct irda_device_info *info; - discovery_t *discovery; + struct irda_device_info *discoveries; struct irda_ias_set ias_opt; /* IAS get/query params */ struct ias_object * ias_obj; /* Object in IAS */ struct ias_attrib * ias_attr; /* Attribute in IAS object */ + int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */ int val = 0; int len = 0; int err; @@ -1845,67 +1995,38 @@ static int irda_getsockopt(struct socket switch (optname) { case IRLMP_ENUMDEVICES: - /* Tell IrLMP we want to be notified */ - irlmp_update_client(self->ckey, self->mask, NULL, - irda_discovery_indication); - - /* Do some discovery */ - irlmp_discovery_request(self->nslots); - + /* Ask lmp for the current discovery log */ + discoveries = irlmp_get_discoveries(&list.len, self->mask); /* Check if the we got some results */ - if (!cachelog) - return -EAGAIN; + if (discoveries == NULL) + return -EAGAIN; /* Didn't find any devices */ + err = 0; - info = &list.dev[0]; + /* Write total list length back to client */ + if (copy_to_user(optval, &list, + sizeof(struct irda_device_list) - + sizeof(struct irda_device_info))) + err = -EFAULT; /* Offset to first device entry */ offset = sizeof(struct irda_device_list) - sizeof(struct irda_device_info); - total = offset; /* Initialized to size of the device list */ - list.len = 0; /* Initialize lenght of list */ - - /* - * Now, check all discovered devices (if any), and notify - * client only about the services that the client is - * interested in - */ - discovery = (discovery_t *) hashbin_get_first(cachelog); - while (discovery != NULL) { - /* Mask out the ones we don't want */ - if (discovery->hints.word & self->mask) { - /* Check if room for this device entry */ - if (len-totalsaddr = discovery->saddr; - info->daddr = discovery->daddr; - info->charset = discovery->charset; - info->hints[0] = discovery->hints.byte[0]; - info->hints[1] = discovery->hints.byte[1]; - strncpy(info->info, discovery->nickname, - NICKNAME_MAX_LEN); - - if (copy_to_user(optval+total, info, - sizeof(struct irda_device_info))) - return -EFAULT; - list.len++; - total += sizeof(struct irda_device_info); - } - discovery = (discovery_t *) hashbin_get_next(cachelog); - } - cachelog = NULL; + /* Copy the list itself */ + total = offset + (list.len * sizeof(struct irda_device_info)); + if (total > len) + total = len; + if (copy_to_user(optval+offset, discoveries, total - offset)) + err = -EFAULT; /* Write total number of bytes used back to client */ if (put_user(total, optlen)) - return -EFAULT; + err = -EFAULT; - /* Write total list length back to client */ - if (copy_to_user(optval, &list, - sizeof(struct irda_device_list) - - sizeof(struct irda_device_info))) - return -EFAULT; + /* Free up our buffer */ + kfree(discoveries); + if (err) + return err; break; case IRLMP_MAX_SDU_SIZE: val = self->max_data_size; @@ -1964,6 +2085,26 @@ static int irda_getsockopt(struct socket if (copy_from_user((char *) &ias_opt, (char *)optval, len)) return -EFAULT; + /* At this point, there are two cases... + * 1) the socket is connected - that's the easy case, we + * just query the device we are connected to... + * 2) the socket is not connected - the user doesn't want + * to connect and/or may not have a valid service name + * (so can't create a fake connection). In this case, + * we assume that the user pass us a valid destination + * address in the requesting structure... + */ + if(self->daddr != DEV_ADDR_ANY) { + /* We are connected - reuse known daddr */ + daddr = self->daddr; + } else { + /* We are not connected, we must specify a valid + * destination address */ + daddr = ias_opt.daddr; + if((!daddr) || (daddr == DEV_ADDR_ANY)) + return -EINVAL; + } + /* Check that we can proceed with IAP */ if (self->iriap) { WARNING(__FUNCTION__ @@ -1972,26 +2113,34 @@ static int irda_getsockopt(struct socket } self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - irda_simple_getvalue_confirm); + irda_getvalue_confirm); /* Treat unexpected signals as disconnect */ self->errno = -EHOSTUNREACH; /* Query remote LM-IAS */ - iriap_getvaluebyclass_request(self->iriap, - self->saddr, self->daddr, + iriap_getvaluebyclass_request(self->iriap, + self->saddr, daddr, ias_opt.irda_class_name, ias_opt.irda_attrib_name); - /* Wait for answer */ - interruptible_sleep_on(&self->ias_wait); + /* Wait for answer (if not already failed) */ + if(self->iriap != NULL) + interruptible_sleep_on(&self->query_wait); /* Check what happened */ if (self->errno) - return (self->errno); + { + /* Requested object/attribute doesn't exist */ + if((self->errno == IAS_CLASS_UNKNOWN) || + (self->errno == IAS_ATTRIB_UNKNOWN)) + return (-EADDRNOTAVAIL); + else + return (-EHOSTUNREACH); + } /* Translate from internal to user structure */ err = irda_extract_ias_value(&ias_opt, self->ias_result); if (self->ias_result) - kfree(self->ias_result); + irias_delete_value(self->ias_result); if (err) return err; @@ -2001,6 +2150,76 @@ static int irda_getsockopt(struct socket return -EFAULT; /* Note : don't need to put optlen, we checked it */ break; + case IRLMP_WAITDEVICE: + /* This function is just another way of seeing life ;-) + * IRLMP_ENUMDEVICES assumes that you have a static network, + * and that you just want to pick one of the devices present. + * On the other hand, in here we assume that no device is + * present and that at some point in the future a device will + * come into range. When this device arrive, we just wake + * up the caller, so that he has time to connect to it before + * the device goes away... + * Note : once the node has been discovered for more than a + * few second, it won't trigger this function, unless it + * goes away and come back changes its hint bits (so we + * might call it IRLMP_WAITNEWDEVICE). + */ + + /* Check that the user is passing us an int */ + if (len != sizeof(int)) + return -EINVAL; + /* Get timeout in ms (max time we block the caller) */ + if (get_user(val, (int *)optval)) + return -EFAULT; + + /* Tell IrLMP we want to be notified */ + irlmp_update_client(self->ckey, self->mask, + irda_selective_discovery_indication, NULL, + (void *) self); + + /* Do some discovery (and also return cached results) */ + irlmp_discovery_request(self->nslots); + + /* Wait until a node is discovered */ + if (!self->cachediscovery) { + IRDA_DEBUG(1, __FUNCTION__ + "(), nothing discovered yet, going to sleep...\n"); + + /* Set watchdog timer to expire in ms. */ + self->watchdog.function = irda_discovery_timeout; + self->watchdog.data = (unsigned long) self; + self->watchdog.expires = jiffies + (val * HZ/1000); + add_timer(&(self->watchdog)); + + /* Wait for IR-LMP to call us back */ + interruptible_sleep_on(&self->query_wait); + + /* If watchdog is still activated, kill it! */ + if(timer_pending(&(self->watchdog))) + del_timer(&(self->watchdog)); + + IRDA_DEBUG(1, __FUNCTION__ + "(), ...waking up !\n"); + } + else + IRDA_DEBUG(1, __FUNCTION__ + "(), found immediately !\n"); + + /* Tell IrLMP that we have been notified */ + irlmp_update_client(self->ckey, self->mask, NULL, NULL, NULL); + + /* Check if the we got some results */ + if (!self->cachediscovery) + return -EAGAIN; /* Didn't find any devices */ + /* Cleanup */ + self->cachediscovery = NULL; + + /* Note : We don't return anything to the user. + * We could return the device that triggered the wake up, + * but it's probably better to force the user to query + * the whole discovery log and let him pick one device... + */ + break; default: return -ENOPROTOOPT; } @@ -2157,14 +2376,14 @@ static struct notifier_block irda_dev_no */ void __init irda_proto_init(struct net_proto *pro) { + MESSAGE("IrDA (tm) Protocols for Linux-2.4 (Dag Brattli)\n"); + sock_register(&irda_family_ops); irda_packet_type.type = htons(ETH_P_IRDA); - dev_add_pack(&irda_packet_type); + dev_add_pack(&irda_packet_type); register_netdevice_notifier(&irda_dev_notifier); - - irda_init(); } /* @@ -2173,17 +2392,12 @@ void __init irda_proto_init(struct net_p * Remove IrDA protocol layer * */ -#ifdef MODULE -void irda_proto_cleanup(void) +void __exit irda_proto_cleanup(void) { irda_packet_type.type = htons(ETH_P_IRDA); - dev_remove_pack(&irda_packet_type); + dev_remove_pack(&irda_packet_type); + + unregister_netdevice_notifier(&irda_dev_notifier); - unregister_netdevice_notifier(&irda_dev_notifier); - sock_unregister(PF_IRDA); - irda_cleanup(); - - return; } -#endif /* MODULE */ diff -urpN linux-2.4.0-test6/net/irda/compressors/irda_deflate.c linux-2.4.0-test6-irda-patch/net/irda/compressors/irda_deflate.c --- linux-2.4.0-test6/net/irda/compressors/irda_deflate.c Tue Aug 31 20:23:03 1999 +++ linux-2.4.0-test6-irda-patch/net/irda/compressors/irda_deflate.c Sun Aug 20 22:03:12 2000 @@ -561,37 +561,37 @@ extern void irda_unregister_compressor ( * Procedures exported to if_ppp.c. */ static struct compressor irda_deflate = { - CI_DEFLATE, /* compress_proto */ - z_comp_alloc, /* comp_alloc */ - z_comp_free, /* comp_free */ - z_comp_init, /* comp_init */ - z_comp_reset, /* comp_reset */ - z_compress, /* compress */ - z_comp_stats, /* comp_stat */ - z_decomp_alloc, /* decomp_alloc */ - z_decomp_free, /* decomp_free */ - z_decomp_init, /* decomp_init */ - z_decomp_reset, /* decomp_reset */ - z_decompress, /* decompress */ - z_incomp, /* incomp */ - z_comp_stats, /* decomp_stat */ +compress_proto: CI_DEFLATE, +comp_alloc: z_comp_alloc, +comp_free: z_comp_free, +comp_init: z_comp_init, +comp_reset: z_comp_reset, +compress: z_compress, +comp_stat: z_comp_stats, +decomp_alloc: z_decomp_alloc, +decomp_free: z_decomp_free, +decomp_init: z_decomp_init, +decomp_reset: z_decomp_reset, +decompress: z_decompress, +incomp: z_incomp, +decomp_stat: z_comp_stats }; static struct compressor irda_deflate_draft = { - CI_DEFLATE_DRAFT, /* compress_proto */ - z_comp_alloc, /* comp_alloc */ - z_comp_free, /* comp_free */ - z_comp_init, /* comp_init */ - z_comp_reset, /* comp_reset */ - z_compress, /* compress */ - z_comp_stats, /* comp_stat */ - z_decomp_alloc, /* decomp_alloc */ - z_decomp_free, /* decomp_free */ - z_decomp_init, /* decomp_init */ - z_decomp_reset, /* decomp_reset */ - z_decompress, /* decompress */ - z_incomp, /* incomp */ - z_comp_stats, /* decomp_stat */ +compress_proto: CI_DEFLATE_DRAFT, +comp_alloc: z_comp_alloc, +comp_free: z_comp_free, +comp_init: z_comp_init, +comp_reset: z_comp_reset, +compress: z_compress, +comp_stat: z_comp_stats, +decomp_alloc: z_decomp_alloc, +decomp_free: z_decomp_free, +decomp_init: z_decomp_init, +decomp_reset: z_decomp_reset, +decompress: z_decompress, +incomp: z_incomp, +decomp_stat: z_comp_stats }; int __init irda_deflate_init(void) diff -urpN linux-2.4.0-test6/net/irda/discovery.c linux-2.4.0-test6-irda-patch/net/irda/discovery.c --- linux-2.4.0-test6/net/irda/discovery.c Tue Dec 21 19:17:58 1999 +++ linux-2.4.0-test6-irda-patch/net/irda/discovery.c Sun Aug 20 22:03:12 2000 @@ -43,13 +43,25 @@ * * Add a new discovery to the cachelog, and remove any old discoveries * from the same device + * + * Note : we try to preserve the time this device was *first* discovered + * (as opposed to the time of last discovery used for cleanup). This is + * used by clients waiting for discovery events to tell if the device + * discovered is "new" or just the same old one. They can't rely there + * on a binary flag (new/old), because not all discovery events are + * propagated to them, and they might not always listen, so they would + * miss some new devices popping up... + * Jean II */ void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new) { discovery_t *discovery, *node; unsigned long flags; - spin_lock_irqsave(&irlmp->lock, flags); + /* Set time of first discovery if node is new (see below) */ + new->first_timestamp = new->timestamp; + + spin_lock_irqsave(&irlmp->log_lock, flags); /* * Remove all discoveries of devices that has previously been @@ -59,27 +71,30 @@ void irlmp_add_discovery(hashbin_t *cach */ discovery = (discovery_t *) hashbin_get_first(cachelog); while (discovery != NULL ) { - node = discovery; + node = discovery; - /* Be sure to stay one item ahead */ - discovery = (discovery_t *) hashbin_get_next(cachelog); + /* Be sure to stay one item ahead */ + discovery = (discovery_t *) hashbin_get_next(cachelog); - if ((node->daddr == new->daddr) || - (strcmp(node->nickname, new->nickname) == 0)) - { - /* This discovery is a previous discovery - * from the same device, so just remove it - */ - hashbin_remove(cachelog, node->daddr, NULL); - kfree(node); - } + if ((node->daddr == new->daddr) || + (strcmp(node->nickname, new->nickname) == 0)) + { + /* This discovery is a previous discovery + * from the same device, so just remove it + */ + hashbin_remove(cachelog, node->daddr, NULL); + /* Check if hints bits have changed */ + if(node->hints.word == new->hints.word) + /* Set time of first discovery for this node */ + new->first_timestamp = node->first_timestamp; + kfree(node); } - + } /* Insert the new and updated version */ - hashbin_insert(cachelog, (queue_t *) new, new->daddr, NULL); + hashbin_insert(cachelog, (irda_queue_t *) new, new->daddr, NULL); - spin_unlock_irqrestore(&irlmp->lock, flags); + spin_unlock_irqrestore(&irlmp->log_lock, flags); } /* @@ -124,9 +139,12 @@ void irlmp_add_discovery_log(hashbin_t * void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force) { discovery_t *discovery, *curr; + unsigned long flags; IRDA_DEBUG(4, __FUNCTION__ "()\n"); + spin_lock_irqsave(&irlmp->log_lock, flags); + discovery = (discovery_t *) hashbin_get_first(log); while (discovery != NULL) { curr = discovery; @@ -143,6 +161,8 @@ void irlmp_expire_discoveries(hashbin_t kfree(curr); } } + + spin_unlock_irqrestore(&irlmp->log_lock, flags); } /* @@ -169,6 +189,75 @@ void irlmp_dump_discoveries(hashbin_t *l } /* + * Function irlmp_copy_discoveries (log, pn, mask) + * + * Copy all discoveries in a buffer + * + * This function implement a safe way for lmp clients to access the + * discovery log. The basic problem is that we don't want the log + * to change (add/remove) while the client is reading it. If the + * lmp client manipulate directly the hashbin, he is sure to get + * into troubles... + * The idea is that we copy all the current discovery log in a buffer + * which is specific to the client and pass this copy to him. As we + * do this operation with the spinlock grabbed, we are safe... + * Note : we don't want those clients to grab the spinlock, because + * we have no control on how long they will hold it... + * Note : we choose to copy the log in "struct irda_device_info" to + * save space... + * Note : the client must kfree himself() the log... + * Jean II + */ +struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, __u16 mask) +{ + discovery_t * discovery; + unsigned long flags; + struct irda_device_info * buffer; + int i = 0; + int n; + + ASSERT(pn != NULL, return NULL;); + + /* Check if log is empty */ + if(log == NULL) + return NULL; + + /* Save spin lock - spinlock should be discovery specific */ + spin_lock_irqsave(&irlmp->log_lock, flags); + + /* Create the client specific buffer */ + n = HASHBIN_GET_SIZE(log); + buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); + if (buffer == NULL) { + spin_unlock_irqrestore(&irlmp->log_lock, flags); + return NULL; + } + + discovery = (discovery_t *) hashbin_get_first(log); + while ((discovery != NULL) && (i < n)) { + /* Mask out the ones we don't want */ + if (discovery->hints.word & mask) { + /* Copy discovery information */ + buffer[i].saddr = discovery->saddr; + buffer[i].daddr = discovery->daddr; + buffer[i].charset = discovery->charset; + buffer[i].hints[0] = discovery->hints.byte[0]; + buffer[i].hints[1] = discovery->hints.byte[1]; + strncpy(buffer[i].info, discovery->nickname, + NICKNAME_MAX_LEN); + i++; + } + discovery = (discovery_t *) hashbin_get_next(log); + } + + spin_unlock_irqrestore(&irlmp->log_lock, flags); + + /* Get the actual number of device in the buffer and return */ + *pn = i; + return(buffer); +} + +/* * Function irlmp_find_device (name, saddr) * * Look through the discovery log at each of the links and try to find @@ -180,7 +269,7 @@ __u32 irlmp_find_device(hashbin_t *cache unsigned long flags; discovery_t *d; - spin_lock_irqsave(&irlmp->lock, flags); + spin_lock_irqsave(&irlmp->log_lock, flags); /* Look at all discoveries for that link */ d = (discovery_t *) hashbin_get_first(cachelog); @@ -192,13 +281,13 @@ __u32 irlmp_find_device(hashbin_t *cache if (strcmp(name, d->nickname) == 0) { *saddr = d->saddr; - spin_unlock_irqrestore(&irlmp->lock, flags); + spin_unlock_irqrestore(&irlmp->log_lock, flags); return d->daddr; } d = (discovery_t *) hashbin_get_next(cachelog); } - spin_unlock_irqrestore(&irlmp->lock, flags); + spin_unlock_irqrestore(&irlmp->log_lock, flags); return 0; } diff -urpN linux-2.4.0-test6/net/irda/ircomm/ircomm_core.c linux-2.4.0-test6-irda-patch/net/irda/ircomm/ircomm_core.c --- linux-2.4.0-test6/net/irda/ircomm/ircomm_core.c Thu Jan 6 23:46:18 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/ircomm/ircomm_core.c Sun Aug 20 22:03:12 2000 @@ -127,7 +127,7 @@ struct ircomm_cb *ircomm_open(notify_t * self->service_type = service_type; self->line = line; - hashbin_insert(ircomm, (queue_t *) self, line, NULL); + hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL); ircomm_next_state(self, IRCOMM_IDLE); @@ -512,6 +512,9 @@ int ircomm_proc_read(char *buf, char **s #endif /* CONFIG_PROC_FS */ #ifdef MODULE +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("IrCOMM protocol"); + int init_module(void) { return ircomm_init(); diff -urpN linux-2.4.0-test6/net/irda/ircomm/ircomm_tty.c linux-2.4.0-test6-irda-patch/net/irda/ircomm/ircomm_tty.c --- linux-2.4.0-test6/net/irda/ircomm/ircomm_tty.c Sat Apr 22 00:17:57 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/ircomm/ircomm_tty.c Sun Aug 20 22:03:12 2000 @@ -69,9 +69,10 @@ static int ircomm_tty_control_indication struct sk_buff *skb); static void ircomm_tty_flow_indication(void *instance, void *sap, LOCAL_FLOW cmd); +#ifdef CONFIG_PROC_FS static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused); - +#endif /* CONFIG_PROC_FS */ static struct tty_driver driver; static int ircomm_tty_refcount; /* If we manage several devices */ @@ -126,8 +127,9 @@ int __init ircomm_tty_init(void) driver.start = ircomm_tty_start; driver.hangup = ircomm_tty_hangup; driver.wait_until_sent = ircomm_tty_wait_until_sent; +#ifdef CONFIG_PROC_FS driver.read_proc = ircomm_tty_read_proc; - +#endif /* CONFIG_PROC_FS */ if (tty_register_driver(&driver)) { ERROR(__FUNCTION__ "Couldn't register serial driver\n"); return -1; @@ -429,7 +431,7 @@ static int ircomm_tty_open(struct tty_st tty->termios->c_oflag = 0; /* Insert into hash */ - hashbin_insert(ircomm_tty, (queue_t *) self, line, NULL); + hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); } self->open_count++; @@ -1319,6 +1321,7 @@ static int ircomm_tty_line_info(struct i * * */ +#ifdef CONFIG_PROC_FS static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused) { @@ -1349,9 +1352,12 @@ done: *start = buf + (offset-begin); return ((len < begin+count-offset) ? len : begin+count-offset); } - +#endif /* CONFIG_PROC_FS */ #ifdef MODULE +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("IrCOMM serial TTY driver"); + int init_module(void) { return ircomm_tty_init(); diff -urpN linux-2.4.0-test6/net/irda/ircomm/ircomm_tty_attach.c linux-2.4.0-test6-irda-patch/net/irda/ircomm/ircomm_tty_attach.c --- linux-2.4.0-test6/net/irda/ircomm/ircomm_tty_attach.c Thu Jan 6 23:46:18 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/ircomm/ircomm_tty_attach.c Sun Aug 20 22:03:12 2000 @@ -46,7 +46,8 @@ #include static void ircomm_tty_ias_register(struct ircomm_tty_cb *self); -static void ircomm_tty_discovery_indication(discovery_t *discovery); +static void ircomm_tty_discovery_indication(discovery_t *discovery, + void *priv); static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, struct ias_value *value, void *priv); void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout); @@ -213,7 +214,7 @@ static void ircomm_tty_ias_register(stru /* Register IrLPT with LM-IAS */ self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID); irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", - self->slsap_sel); + self->slsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->obj); } else { hints = irlmp_service_to_hint(S_COMM); @@ -221,7 +222,7 @@ static void ircomm_tty_ias_register(stru /* Register IrCOMM with LM-IAS */ self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID); irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", - self->slsap_sel); + self->slsap_sel, IAS_KERNEL_ATTR); /* Code the parameters into the buffer */ irda_param_pack(oct_seq, "bbbbbb", @@ -229,12 +230,13 @@ static void ircomm_tty_ias_register(stru IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL); /* Register parameters with LM-IAS */ - irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6); + irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6, + IAS_KERNEL_ATTR); irias_insert_object(self->obj); } self->skey = irlmp_register_service(hints); self->ckey = irlmp_register_client( - hints, ircomm_tty_discovery_indication, NULL); + hints, ircomm_tty_discovery_indication, NULL, (void *) self); } /* @@ -302,7 +304,8 @@ int ircomm_tty_send_initial_parameters(s * device it is, and which services it has. * */ -static void ircomm_tty_discovery_indication(discovery_t *discovery) +static void ircomm_tty_discovery_indication(discovery_t *discovery, + void *priv) { struct ircomm_tty_cb *self; struct ircomm_tty_info info; diff -urpN linux-2.4.0-test6/net/irda/irda_device.c linux-2.4.0-test6-irda-patch/net/irda/irda_device.c --- linux-2.4.0-test6/net/irda/irda_device.c Tue Mar 21 20:17:28 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/irda_device.c Sun Aug 20 22:03:12 2000 @@ -58,6 +58,8 @@ extern int irtty_init(void); extern int nsc_ircc_init(void); extern int ircc_init(void); +extern int toshoboe_init(void); +extern int litelink_init(void); extern int w83977af_init(void); extern int esi_init(void); extern int tekram_init(void); @@ -379,7 +381,7 @@ struct irda_task *irda_task_execute(void init_timer(&task->timer); /* Register task */ - hashbin_insert(tasks, (queue_t *) task, (int) task, NULL); + hashbin_insert(tasks, (irda_queue_t *) task, (int) task, NULL); /* No time to waste, so lets get going! */ ret = irda_task_kick(task); @@ -518,7 +520,7 @@ int irda_device_register_dongle(struct d } /* Insert IrDA dongle into hashbin */ - hashbin_insert(dongles, (queue_t *) new, new->type, NULL); + hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL); return 0; } diff -urpN linux-2.4.0-test6/net/irda/iriap.c linux-2.4.0-test6-irda-patch/net/irda/iriap.c --- linux-2.4.0-test6/net/irda/iriap.c Thu Jan 6 23:46:18 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/iriap.c Sun Aug 20 22:03:12 2000 @@ -107,7 +107,7 @@ int __init iriap_init(void) /* Register the Device object with LM-IAS */ obj = irias_new_object("Device", IAS_DEVICE_ID); - irias_add_string_attrib(obj, "DeviceName", "Linux"); + irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR); oct_seq[0] = 0x01; /* Version 1 */ oct_seq[1] = 0x00; /* IAS support bits */ @@ -115,7 +115,8 @@ int __init iriap_init(void) #ifdef CONFIG_IRDA_ULTRA oct_seq[2] |= 0x04; /* Connectionless Data support */ #endif - irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3); + irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3, + IAS_KERNEL_ATTR); irias_insert_object(obj); /* @@ -179,7 +180,7 @@ struct iriap_cb *iriap_open(__u8 slsap_s init_timer(&self->watchdog_timer); - hashbin_insert(iriap, (queue_t *) self, (int) self, NULL); + hashbin_insert(iriap, (irda_queue_t *) self, (int) self, NULL); /* Initialize state machines */ iriap_next_client_state(self, S_DISCONNECT); @@ -866,7 +867,7 @@ static int iriap_data_indication(void *i iriap_getvaluebyclass_confirm(self, skb); break; case IAS_CLASS_UNKNOWN: - WARNING(__FUNCTION__ "(), No such class!\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), No such class!\n"); /* Finished, close connection! */ iriap_disconnect_request(self); @@ -880,7 +881,7 @@ static int iriap_data_indication(void *i dev_kfree_skb(skb); break; case IAS_ATTRIB_UNKNOWN: - WARNING(__FUNCTION__ "(), No such attribute!\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), No such attribute!\n"); /* Finished, close connection! */ iriap_disconnect_request(self); @@ -889,7 +890,7 @@ static int iriap_data_indication(void *i * no to use self anymore after calling confirm */ if (self->confirm) - self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, + self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, self->priv); dev_kfree_skb(skb); break; diff -urpN linux-2.4.0-test6/net/irda/irias_object.c linux-2.4.0-test6-irda-patch/net/irda/irias_object.c --- linux-2.4.0-test6/net/irda/irias_object.c Tue Dec 21 19:17:58 1999 +++ linux-2.4.0-test6-irda-patch/net/irda/irias_object.c Sun Aug 20 22:03:12 2000 @@ -148,6 +148,37 @@ int irias_delete_object(struct ias_objec } /* + * Function irias_delete_attrib (obj) + * + * Remove attribute from hashbin and, if it was the last attribute of + * the object, remove the object as well. + * + */ +int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib) +{ + struct ias_attrib *node; + + ASSERT(obj != NULL, return -1;); + ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); + ASSERT(attrib != NULL, return -1;); + + /* Remove atribute from object */ + node = hashbin_remove(obj->attribs, 0, attrib->name); + if (!node) + return 0; /* Already removed or non-existent */ + + /* Deallocate attribute */ + __irias_delete_attrib(node); + + /* Check if object has still some attributes */ + node = (struct ias_attrib *) hashbin_get_first(obj->attribs); + if (!node) + irias_delete_object(obj); + + return 0; +} + +/* * Function irias_insert_object (obj) * * Insert an object into the LM-IAS database @@ -158,7 +189,7 @@ void irias_insert_object(struct ias_obje ASSERT(obj != NULL, return;); ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - hashbin_insert(objects, (queue_t *) obj, 0, obj->name); + hashbin_insert(objects, (irda_queue_t *) obj, 0, obj->name); } /* @@ -201,7 +232,8 @@ struct ias_attrib *irias_find_attrib(str * Add attribute to object * */ -void irias_add_attrib( struct ias_object *obj, struct ias_attrib *attrib) +void irias_add_attrib( struct ias_object *obj, struct ias_attrib *attrib, + int owner) { ASSERT(obj != NULL, return;); ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); @@ -209,7 +241,10 @@ void irias_add_attrib( struct ias_object ASSERT(attrib != NULL, return;); ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); - hashbin_insert(obj->attribs, (queue_t *) attrib, 0, attrib->name); + /* Set if attrib is owned by kernel or user space */ + attrib->value->owner = owner; + + hashbin_insert(obj->attribs, (irda_queue_t *) attrib, 0, attrib->name); } /* @@ -262,7 +297,8 @@ int irias_object_change_attribute(char * * Add an integer attribute to an LM-IAS object * */ -void irias_add_integer_attrib(struct ias_object *obj, char *name, int value) +void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, + int owner) { struct ias_attrib *attrib; @@ -284,7 +320,7 @@ void irias_add_integer_attrib(struct ias /* Insert value */ attrib->value = irias_new_integer_value(value); - irias_add_attrib(obj, attrib); + irias_add_attrib(obj, attrib, owner); } /* @@ -295,7 +331,7 @@ void irias_add_integer_attrib(struct ias */ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, - int len) + int len, int owner) { struct ias_attrib *attrib; @@ -319,7 +355,7 @@ void irias_add_octseq_attrib(struct ias_ attrib->value = irias_new_octseq_value( octets, len); - irias_add_attrib(obj, attrib); + irias_add_attrib(obj, attrib, owner); } /* @@ -328,7 +364,8 @@ void irias_add_octseq_attrib(struct ias_ * Add a string attribute to an LM-IAS object * */ -void irias_add_string_attrib(struct ias_object *obj, char *name, char *value) +void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, + int owner) { struct ias_attrib *attrib; @@ -351,7 +388,7 @@ void irias_add_string_attrib(struct ias_ attrib->value = irias_new_string_value(value); - irias_add_attrib(obj, attrib); + irias_add_attrib(obj, attrib, owner); } /* diff -urpN linux-2.4.0-test6/net/irda/irlan/irlan_client.c linux-2.4.0-test6-irda-patch/net/irda/irlan/irlan_client.c --- linux-2.4.0-test6/net/irda/irlan/irlan_client.c Thu May 4 20:31:22 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/irlan/irlan_client.c Sun Aug 20 22:03:12 2000 @@ -104,8 +104,6 @@ void irlan_client_start_kick_timer(struc */ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) { - struct irmanager_event mgr_event; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); @@ -117,41 +115,24 @@ void irlan_client_wakeup(struct irlan_cb */ if ((self->client.state != IRLAN_IDLE) || (self->provider.access_type == ACCESS_DIRECT)) - return; + { + IRDA_DEBUG(0, __FUNCTION__ "(), already awake!\n"); + return; + } - /* saddr may have changed! */ + /* Address may have changed! */ self->saddr = saddr; - - /* Before we try to connect, we check if network device is up. If it - * is up, that means that the "user" really wants to connect. If not - * we notify the user about the possibility of an IrLAN connection - */ - if (netif_running(&self->dev)) { - /* Open TSAPs */ - irlan_client_open_ctrl_tsap(self); - irlan_open_data_tsap(self); - - irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL); - } else if (self->notify_irmanager) { - /* - * Tell irmanager that the device can now be - * configured but only if the device was not taken - * down by the user - */ - mgr_event.event = EVENT_IRLAN_START; - strcpy(mgr_event.devname, self->dev.name); - irmanager_notify(&mgr_event); - - /* - * We set this so that we only notify once, since if - * configuration of the network device fails, the user - * will have to sort it out first anyway. No need to - * try again. - */ - self->notify_irmanager = FALSE; + + if (self->disconnect_reason == LM_USER_REQUEST) { + IRDA_DEBUG(0, __FUNCTION__ "(), still stopped by user\n"); + return; } - /* Restart watchdog timer */ - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); + + /* Open TSAPs */ + irlan_client_open_ctrl_tsap(self); + irlan_open_data_tsap(self); + + irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL); /* Start kick timer */ irlan_client_start_kick_timer(self, 2*HZ); @@ -163,7 +144,7 @@ void irlan_client_wakeup(struct irlan_cb * Remote device with IrLAN server support discovered * */ -void irlan_client_discovery_indication(discovery_t *discovery) +void irlan_client_discovery_indication(discovery_t *discovery, void *priv) { struct irlan_cb *self; __u32 saddr, daddr; @@ -176,29 +157,16 @@ void irlan_client_discovery_indication(d saddr = discovery->saddr; daddr = discovery->daddr; - /* - * Check if we already dealing with this provider. - */ - self = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL); - if (self) { + /* Find instance */ + self = (struct irlan_cb *) hashbin_get_first(irlan); + if (self) { ASSERT(self->magic == IRLAN_MAGIC, return;); IRDA_DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n", daddr); irlan_client_wakeup(self, saddr, daddr); - - return; } - - /* - * We have no instance for daddr, so start a new one - */ - IRDA_DEBUG(1, __FUNCTION__ "(), starting new instance!\n"); - self = irlan_open(saddr, daddr, TRUE); - - /* Restart watchdog timer */ - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); } /* @@ -449,9 +417,7 @@ static void irlan_check_response_param(s ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); - /* - * Media type - */ + /* Media type */ if (strcmp(param, "MEDIA") == 0) { if (strcmp(value, "802.3") == 0) self->media = MEDIA_802_3; @@ -487,9 +453,7 @@ static void irlan_check_response_param(s IRDA_DEBUG(2, __FUNCTION__ "(), unknown access type!\n"); } } - /* - * IRLAN version - */ + /* IRLAN version */ if (strcmp(param, "IRLAN_VER") == 0) { IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0], (__u8) value[1]); @@ -498,9 +462,7 @@ static void irlan_check_response_param(s self->version[1] = value[1]; return; } - /* - * Which remote TSAP to use for data channel - */ + /* Which remote TSAP to use for data channel */ if (strcmp(param, "DATA_CHAN") == 0) { self->dtsap_sel_data = value[0]; IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data); @@ -521,9 +483,7 @@ static void irlan_check_response_param(s self->client.max_frame); } - /* - * RECONNECT_KEY, in case the link goes down! - */ + /* RECONNECT_KEY, in case the link goes down! */ if (strcmp(param, "RECONNECT_KEY") == 0) { IRDA_DEBUG(4, "Got reconnect key: "); /* for (i = 0; i < val_len; i++) */ @@ -532,9 +492,7 @@ static void irlan_check_response_param(s self->client.key_len = val_len; IRDA_DEBUG(4, "\n"); } - /* - * FILTER_ENTRY, have we got an ethernet address? - */ + /* FILTER_ENTRY, have we got an ethernet address? */ if (strcmp(param, "FILTER_ENTRY") == 0) { bytes = value; IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n", diff -urpN linux-2.4.0-test6/net/irda/irlan/irlan_common.c linux-2.4.0-test6-irda-patch/net/irda/irlan/irlan_common.c --- linux-2.4.0-test6/net/irda/irlan/irlan_common.c Thu May 4 20:31:22 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/irlan/irlan_common.c Sun Aug 20 22:03:12 2000 @@ -50,6 +50,14 @@ #include #include + +/* + * Send gratuitous ARP when connected to a new AP or not. May be a clever + * thing to do, but for some reason the machine crashes if you use DHCP. So + * lets not use it by default. + */ +#undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP + /* extern char sysctl_devname[]; */ /* @@ -62,6 +70,7 @@ static __u32 ckey, skey; static int eth = 0; /* Use "eth" or "irlan" name for devices */ static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */ +#ifdef CONFIG_PROC_FS static char *irlan_state[] = { "IRLAN_IDLE", "IRLAN_QUERY", @@ -88,6 +97,7 @@ static char *irlan_media[] = { "802.3", "802.5" }; +#endif /* CONFIG_PROC_FS */ static void __irlan_close(struct irlan_cb *self); static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, @@ -102,59 +112,6 @@ extern struct proc_dir_entry *proc_irda; #endif /* CONFIG_PROC_FS */ /* - * Function irlan_watchdog_timer_expired (data) - * - * Something has gone wrong during the connection establishment - * - */ -void irlan_watchdog_timer_expired(void *data) -{ - struct irmanager_event mgr_event; - struct irlan_cb *self; - - IRDA_DEBUG(0, __FUNCTION__ "()\n"); - - self = (struct irlan_cb *) data; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Check if device still configured */ - if (netif_running(&self->dev)) { - IRDA_DEBUG(0, __FUNCTION__ - "(), notifying irmanager to stop irlan!\n"); - mgr_event.event = EVENT_IRLAN_STOP; - sprintf(mgr_event.devname, "%s", self->dev.name); - irmanager_notify(&mgr_event); - - /* - * We set this to false, so that irlan_dev_close known that - * notify_irmanager should actually be set to TRUE again - * instead of FALSE, since this close has not been initiated - * by the user. - */ - self->notify_irmanager = FALSE; - } else { - IRDA_DEBUG(0, __FUNCTION__ "(), closing instance!\n"); - /*irlan_close(self);*/ - } -} - -/* - * Function irlan_start_watchdog_timer (self, timeout) - * - * - * - */ -void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout) -{ - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - irda_start_timer(&self->watchdog_timer, timeout, (void *) self, - irlan_watchdog_timer_expired); -} - -/* * Function irlan_init (void) * * Initialize IrLAN layer @@ -165,8 +122,6 @@ int __init irlan_init(void) struct irlan_cb *new; __u16 hints; - IRDA_DEBUG(4, __FUNCTION__"()\n"); - /* Allocate master structure */ irlan = hashbin_new(HB_LOCAL); if (irlan == NULL) { @@ -178,22 +133,20 @@ int __init irlan_init(void) #endif /* CONFIG_PROC_FS */ IRDA_DEBUG(4, __FUNCTION__ "()\n"); - hints = irlmp_service_to_hint(S_LAN); /* Register with IrLMP as a client */ ckey = irlmp_register_client(hints, irlan_client_discovery_indication, - NULL); + NULL, NULL); /* Register with IrLMP as a service */ skey = irlmp_register_service(hints); - /* Start the master IrLAN instance */ - new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE); + /* Start the master IrLAN instance (the only one for now) */ + new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY); /* The master will only open its (listen) control TSAP */ irlan_provider_open_ctrl_tsap(new); - new->master = TRUE; /* Do some fast discovery! */ irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); @@ -206,7 +159,6 @@ void irlan_cleanup(void) IRDA_DEBUG(4, __FUNCTION__ "()\n"); irlmp_unregister_client(ckey); - irlmp_unregister_service(skey); #ifdef CONFIG_PROC_FS @@ -242,8 +194,6 @@ int irlan_register_netdev(struct irlan_c IRDA_DEBUG(2, __FUNCTION__ "(), register_netdev() failed!\n"); return -1; } - self->netdev_registered = TRUE; - return 0; } @@ -253,7 +203,7 @@ int irlan_register_netdev(struct irlan_c * Open new instance of a client/provider, we should only register the * network device if this instance is ment for a particular client/provider */ -struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev) +struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr) { struct irlan_cb *self; @@ -287,32 +237,28 @@ struct irlan_cb *irlan_open(__u32 saddr, /* Provider access can only be PEER, DIRECT, or HOSTED */ self->provider.access_type = access; self->media = MEDIA_802_3; - - self->notify_irmanager = TRUE; - + self->disconnect_reason = LM_USER_REQUEST; init_timer(&self->watchdog_timer); init_timer(&self->client.kick_timer); + init_waitqueue_head(&self->open_wait); - hashbin_insert(irlan, (queue_t *) self, daddr, NULL); + hashbin_insert(irlan, (irda_queue_t *) self, daddr, NULL); skb_queue_head_init(&self->client.txq); irlan_next_client_state(self, IRLAN_IDLE); irlan_next_provider_state(self, IRLAN_IDLE); - /* Register network device now, or wait until some later time? */ - if (netdev) - irlan_register_netdev(self); + irlan_register_netdev(self); return self; } /* - * Function irlan_close (self) + * Function __irlan_close (self) * * This function closes and deallocates the IrLAN client instances. Be * aware that other functions which calles client_close() must call * hashbin_remove() first!!! - * */ static void __irlan_close(struct irlan_cb *self) { @@ -333,49 +279,13 @@ static void __irlan_close(struct irlan_c iriap_close(self->client.iriap); /* Remove frames queued on the control channel */ - while ((skb = skb_dequeue(&self->client.txq))) { + while ((skb = skb_dequeue(&self->client.txq))) dev_kfree_skb(skb); - } - if (self->netdev_registered) { - unregister_netdev(&self->dev); - self->netdev_registered = FALSE; - } + unregister_netdev(&self->dev); self->magic = 0; - kfree(self); -} - -/* - * Function irlan_close (self) - * - * Close instance - * - */ -void irlan_close(struct irlan_cb *self) -{ - struct irlan_cb *entry; - - IRDA_DEBUG(0, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Check if device is still configured */ - if (netif_running(&self->dev)) { - IRDA_DEBUG(0, __FUNCTION__ - "(), Device still configured, closing later!\n"); - - /* Give it a chance to reconnect */ - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); - return; - } - IRDA_DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr); - entry = hashbin_remove(irlan, self->daddr, NULL); - - ASSERT(entry == self, return;); - - __irlan_close(self); + kfree(self); } /* @@ -419,7 +329,7 @@ void irlan_connect_indication(void *inst irlan_open_unicast_addr(self); } /* Ready to transfer Ethernet frames (at last) */ - netif_start_queue(&self->dev); + netif_start_queue(&self->dev); /* Clear reason */ } void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos, @@ -454,7 +364,11 @@ void irlan_connect_confirm(void *instanc /* Ready to transfer Ethernet frames */ netif_start_queue(&self->dev); + self->disconnect_reason = 0; /* Clear reason */ +#ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP irlan_eth_send_gratuitous_arp(&self->dev); +#endif + wake_up_interruptible(&self->open_wait); } /* @@ -483,28 +397,34 @@ void irlan_disconnect_indication(void *i IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n"); - switch(reason) { + /* Save reason so we know if we should try to reconnect or not */ + self->disconnect_reason = reason; + + switch (reason) { case LM_USER_REQUEST: /* User request */ - irlan_close(self); + IRDA_DEBUG(2, __FUNCTION__ "(), User requested\n"); break; case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */ - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); + IRDA_DEBUG(2, __FUNCTION__ "(), Unexpected IrLAP disconnect\n"); break; case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */ - IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n"); + IRDA_DEBUG(2, __FUNCTION__ "(), IrLAP connect failed\n"); break; case LM_LAP_RESET: /* IrLAP reset */ - IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n"); + IRDA_DEBUG(2, __FUNCTION__ "(), IrLAP reset\n"); break; case LM_INIT_DISCONNECT: - IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n"); + IRDA_DEBUG(2, __FUNCTION__ "(), IrLMP connect failed\n"); break; default: + ERROR(__FUNCTION__ "(), Unknown disconnect reason\n"); break; } irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); + + wake_up_interruptible(&self->open_wait); } void irlan_open_data_tsap(struct irlan_cb *self) @@ -553,9 +473,7 @@ void irlan_close_tsaps(struct irlan_cb * ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); - /* - * Disconnect and close all open TSAP connections - */ + /* Disconnect and close all open TSAP connections */ if (self->tsap_data) { irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL); irttp_close_tsap(self->tsap_data); @@ -573,6 +491,7 @@ void irlan_close_tsaps(struct irlan_cb * irttp_close_tsap(self->provider.tsap_ctrl); self->provider.tsap_ctrl = NULL; } + self->disconnect_reason = LM_USER_REQUEST; } /* @@ -595,7 +514,8 @@ void irlan_ias_register(struct irlan_cb */ if (!irias_find_object("IrLAN")) { obj = irias_new_object("IrLAN", IAS_IRLAN_ID); - irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel); + irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel, + IAS_KERNEL_ATTR); irias_insert_object(obj); } else { new_value = irias_new_integer_value(tsap_sel); @@ -607,18 +527,23 @@ void irlan_ias_register(struct irlan_cb if (!irias_find_object("PnP")) { obj = irias_new_object("PnP", IAS_PNP_ID); #if 0 - irias_add_string_attrib(obj, "Name", sysctl_devname); + irias_add_string_attrib(obj, "Name", sysctl_devname, + IAS_KERNEL_ATTR); #else - irias_add_string_attrib(obj, "Name", "Linux"); + irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR); #endif - irias_add_string_attrib(obj, "DeviceID", "HWP19F0"); - irias_add_integer_attrib(obj, "CompCnt", 1); + irias_add_string_attrib(obj, "DeviceID", "HWP19F0", + IAS_KERNEL_ATTR); + irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR); if (self->provider.access_type == ACCESS_PEER) - irias_add_string_attrib(obj, "Comp#01", "PNP8389"); + irias_add_string_attrib(obj, "Comp#01", "PNP8389", + IAS_KERNEL_ATTR); else - irias_add_string_attrib(obj, "Comp#01", "PNP8294"); + irias_add_string_attrib(obj, "Comp#01", "PNP8294", + IAS_KERNEL_ATTR); - irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project"); + irias_add_string_attrib(obj, "Manufacturer", + "Linux-IrDA Project", IAS_KERNEL_ATTR); irias_insert_object(obj); } } @@ -633,7 +558,7 @@ int irlan_run_ctrl_tx_queue(struct irlan { struct sk_buff *skb; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, __FUNCTION__ "()\n"); if (irda_lock(&self->client.tx_busy) == FALSE) return -EBUSY; @@ -652,7 +577,7 @@ int irlan_run_ctrl_tx_queue(struct irlan dev_kfree_skb(skb); return -1; } - IRDA_DEBUG(3, __FUNCTION__ "(), sending ...\n"); + IRDA_DEBUG(2, __FUNCTION__ "(), sending ...\n"); return irttp_data_request(self->client.tsap_ctrl, skb); } @@ -741,7 +666,6 @@ void irlan_open_data_channel(struct irla /* self->use_udata = TRUE; */ - /* irttp_data_request(self->client.tsap_ctrl, skb); */ irlan_ctrl_data_request(self, skb); } @@ -810,7 +734,6 @@ void irlan_open_unicast_addr(struct irla irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); - /* irttp_data_request(self->client.tsap_ctrl, skb); */ irlan_ctrl_data_request(self, skb); } @@ -852,7 +775,6 @@ void irlan_set_broadcast_filter(struct i else irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); - /* irttp_data_request(self->client.tsap_ctrl, skb); */ irlan_ctrl_data_request(self, skb); } @@ -892,7 +814,6 @@ void irlan_set_multicast_filter(struct i else irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); - /* irttp_data_request(self->client.tsap_ctrl, skb); */ irlan_ctrl_data_request(self, skb); } @@ -930,7 +851,6 @@ void irlan_get_unicast_addr(struct irlan irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); - /* irttp_data_request(self->client.tsap_ctrl, skb); */ irlan_ctrl_data_request(self, skb); } @@ -965,8 +885,6 @@ void irlan_get_media_char(struct irlan_c frame[1] = 0x01; /* One parameter */ irlan_insert_string_param(skb, "MEDIA", "802.3"); - - /* irttp_data_request(self->client.tsap_ctrl, skb); */ irlan_ctrl_data_request(self, skb); } @@ -1169,35 +1087,32 @@ static int irlan_proc_read(char *buf, ch while (self != NULL) { ASSERT(self->magic == IRLAN_MAGIC, return len;); - /* Don't display the master server */ - if (self->master == 0) { - len += sprintf(buf+len, "ifname: %s,\n", - self->dev.name); - len += sprintf(buf+len, "client state: %s, ", - irlan_state[ self->client.state]); - len += sprintf(buf+len, "provider state: %s,\n", - irlan_state[ self->provider.state]); - len += sprintf(buf+len, "saddr: %#08x, ", - self->saddr); - len += sprintf(buf+len, "daddr: %#08x\n", - self->daddr); - len += sprintf(buf+len, "version: %d.%d,\n", - self->version[1], self->version[0]); - len += sprintf(buf+len, "access type: %s\n", - irlan_access[self->client.access_type]); - len += sprintf(buf+len, "media: %s\n", - irlan_media[self->media]); - - len += sprintf(buf+len, "local filter:\n"); - len += sprintf(buf+len, "remote filter: "); - len += irlan_print_filter(self->client.filter_type, - buf+len); + len += sprintf(buf+len, "ifname: %s,\n", + self->dev.name); + len += sprintf(buf+len, "client state: %s, ", + irlan_state[ self->client.state]); + len += sprintf(buf+len, "provider state: %s,\n", + irlan_state[ self->provider.state]); + len += sprintf(buf+len, "saddr: %#08x, ", + self->saddr); + len += sprintf(buf+len, "daddr: %#08x\n", + self->daddr); + len += sprintf(buf+len, "version: %d.%d,\n", + self->version[1], self->version[0]); + len += sprintf(buf+len, "access type: %s\n", + irlan_access[self->client.access_type]); + len += sprintf(buf+len, "media: %s\n", + irlan_media[self->media]); + + len += sprintf(buf+len, "local filter:\n"); + len += sprintf(buf+len, "remote filter: "); + len += irlan_print_filter(self->client.filter_type, + buf+len); - len += sprintf(buf+len, "tx busy: %s\n", - netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE"); + len += sprintf(buf+len, "tx busy: %s\n", + netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE"); - len += sprintf(buf+len, "\n"); - } + len += sprintf(buf+len, "\n"); self = (struct irlan_cb *) hashbin_get_next(irlan); } @@ -1272,8 +1187,9 @@ MODULE_AUTHOR("Dag Brattli dev_addr+5, 1); } - /* - * Network device has now been registered, so tell irmanager about - * it, so it can be configured with network parameters - */ - mgr_event.event = EVENT_IRLAN_START; - sprintf(mgr_event.devname, "%s", self->dev.name); - irmanager_notify(&mgr_event); - - /* - * We set this so that we only notify once, since if - * configuration of the network device fails, the user - * will have to sort it out first anyway. No need to - * try again. - */ - self->notify_irmanager = FALSE; - return 0; } @@ -123,14 +106,16 @@ int irlan_eth_open(struct net_device *de ASSERT(self != NULL, return -1;); /* Ready to play! */ -/* netif_start_queue(dev) */ /* Wait until data link is ready */ - - self->notify_irmanager = TRUE; + netif_stop_queue(dev); /* Wait until data link is ready */ /* We are now open, so time to do some work */ + self->disconnect_reason = 0; irlan_client_wakeup(self, self->saddr, self->daddr); irlan_mod_inc_use_count(); + + /* Make sure we have a hardware address before we return, so DHCP clients gets happy */ + interruptible_sleep_on(&self->open_wait); return 0; } @@ -146,7 +131,8 @@ int irlan_eth_open(struct net_device *de int irlan_eth_close(struct net_device *dev) { struct irlan_cb *self = (struct irlan_cb *) dev->priv; - + struct sk_buff *skb; + IRDA_DEBUG(2, __FUNCTION__ "()\n"); /* Stop device */ @@ -155,20 +141,17 @@ int irlan_eth_close(struct net_device *d irlan_mod_dec_use_count(); irlan_close_data_channel(self); - irlan_close_tsaps(self); irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); - - /* Device closed by user! */ - if (self->notify_irmanager) - self->notify_irmanager = FALSE; - else - self->notify_irmanager = TRUE; + /* Remove frames queued on the control channel */ + while ((skb = skb_dequeue(&self->client.txq))) + dev_kfree_skb(skb); + self->client.tx_busy = 0; + return 0; } diff -urpN linux-2.4.0-test6/net/irda/irlan/irlan_provider.c linux-2.4.0-test6-irda-patch/net/irda/irlan/irlan_provider.c --- linux-2.4.0-test6/net/irda/irlan/irlan_provider.c Wed Nov 3 02:07:55 1999 +++ linux-2.4.0-test6-irda-patch/net/irda/irlan/irlan_provider.c Sun Aug 20 22:03:12 2000 @@ -116,16 +116,16 @@ static int irlan_provider_data_indicatio /* * Function irlan_provider_connect_indication (handle, skb, priv) * - * Got connection from peer IrLAN layer + * Got connection from peer IrLAN client * */ static void irlan_provider_connect_indication(void *instance, void *sap, struct qos_info *qos, __u32 max_sdu_size, __u8 max_header_size, - struct sk_buff *skb) + struct sk_buff *skb) { - struct irlan_cb *self, *new; + struct irlan_cb *self; struct tsap_cb *tsap; __u32 saddr, daddr; @@ -137,82 +137,24 @@ static void irlan_provider_connect_indic ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); - self->provider.max_sdu_size = max_sdu_size; - self->provider.max_header_size = max_header_size; - ASSERT(tsap == self->provider.tsap_ctrl,return;); ASSERT(self->provider.state == IRLAN_IDLE, return;); daddr = irttp_get_daddr(tsap); saddr = irttp_get_saddr(tsap); + self->provider.max_sdu_size = max_sdu_size; + self->provider.max_header_size = max_header_size; - /* Check if we already dealing with this client or peer */ - new = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL); - if (new) { - ASSERT(new->magic == IRLAN_MAGIC, return;); - IRDA_DEBUG(0, __FUNCTION__ "(), found instance!\n"); - - /* Update saddr, since client may have moved to a new link */ - new->saddr = saddr; - IRDA_DEBUG(2, __FUNCTION__ "(), saddr=%08x\n", new->saddr); - - /* Make sure that any old provider control TSAP is removed */ - if ((new != self) && new->provider.tsap_ctrl) { - irttp_disconnect_request(new->provider.tsap_ctrl, - NULL, P_NORMAL); - irttp_close_tsap(new->provider.tsap_ctrl); - new->provider.tsap_ctrl = NULL; - } - } else { - /* This must be the master instance, so start a new instance */ - IRDA_DEBUG(0, __FUNCTION__ "(), starting new provider!\n"); - - new = irlan_open(saddr, daddr, TRUE); - } - - /* - * Check if the connection came in on the master server, or the - * slave server. If it came on the slave, then everything is - * really, OK (reconnect), if not we need to dup the connection and - * hand it over to the slave. - */ - if (new != self) { - - /* Now attach up the new "socket" */ - new->provider.tsap_ctrl = irttp_dup(self->provider.tsap_ctrl, - new); - if (!new->provider.tsap_ctrl) { - IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n"); - return; - } - - /* new->stsap_sel = new->tsap->stsap_sel; */ - new->dtsap_sel_ctrl = new->provider.tsap_ctrl->dtsap_sel; - - /* Clean up the original one to keep it in listen state */ - self->provider.tsap_ctrl->dtsap_sel = LSAP_ANY; - self->provider.tsap_ctrl->lsap->dlsap_sel = LSAP_ANY; - self->provider.tsap_ctrl->lsap->lsap_state = LSAP_DISCONNECTED; - - /* - * Use the new instance from here instead of the master - * struct! - */ - self = new; - } - /* Check if network device has been registered */ - if (!self->netdev_registered) - irlan_register_netdev(self); - irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL); /* * If we are in peer mode, the client may not have got the discovery * indication it needs to make progress. If the client is still in - * IDLE state, we must kick it to + * IDLE state, we must kick it. */ if ((self->provider.access_type == ACCESS_PEER) && - (self->client.state == IRLAN_IDLE)) { + (self->client.state == IRLAN_IDLE)) + { irlan_client_wakeup(self, self->saddr, self->daddr); } } @@ -231,11 +173,6 @@ void irlan_provider_connect_response(str /* Just accept */ irttp_connect_response(tsap, IRLAN_MTU, NULL); - - /* Check if network device has been registered */ - if (!self->netdev_registered) - irlan_register_netdev(self); - } void irlan_provider_disconnect_indication(void *instance, void *sap, diff -urpN linux-2.4.0-test6/net/irda/irlap.c linux-2.4.0-test6-irda-patch/net/irda/irlap.c --- linux-2.4.0-test6/net/irda/irlap.c Thu Jan 6 23:46:18 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/irlap.c Sun Aug 20 22:03:12 2000 @@ -154,7 +154,7 @@ struct irlap_cb *irlap_open(struct net_d irlap_next_state(self, LAP_NDM); - hashbin_insert(irlap, (queue_t *) self, self->saddr, NULL); + hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL); irlmp_register_link(self, self->saddr, &self->notify); @@ -232,7 +232,8 @@ void irlap_connect_indication(struct irl ASSERT(self->magic == LAP_MAGIC, return;); irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ - + + skb_get(skb); /*LEVEL4*/ irlmp_link_connect_indication(self->notify.instance, self->saddr, self->daddr, &self->qos_tx, skb); } @@ -248,6 +249,7 @@ void irlap_connect_response(struct irlap IRDA_DEBUG(4, __FUNCTION__ "()\n"); irlap_do_event(self, CONNECT_RESPONSE, skb, NULL); + kfree_skb(skb); } /* @@ -292,6 +294,7 @@ void irlap_connect_confirm(struct irlap_ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); + skb_get(skb); /*LEVEL4*/ irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb); } @@ -310,6 +313,7 @@ void irlap_data_indication(struct irlap_ #ifdef CONFIG_IRDA_COMPRESSION if (self->qos_tx.compression.value) { + skb_get(skb); /*LEVEL4*/ skb = irlap_decompress_frame(self, skb); if (!skb) { IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n"); @@ -317,6 +321,7 @@ void irlap_data_indication(struct irlap_ } } #endif + skb_get(skb); /*LEVEL4*/ irlmp_link_data_indication(self->notify.instance, skb, unreliable); } @@ -373,6 +378,7 @@ void irlap_data_request(struct irlap_cb ASSERT(skb != NULL, return;); } irlap_do_event(self, SEND_I_CMD, skb, NULL); + kfree_skb(skb); } else skb_queue_tail(&self->txq, skb); } @@ -422,6 +428,7 @@ void irlap_unitdata_indication(struct ir /* Hide LAP header from IrLMP layer */ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); + skb_get(skb); /*LEVEL4*/ irlmp_link_unitdata_indication(self->notify.instance, skb); } #endif /* CONFIG_IRDA_ULTRA */ @@ -664,11 +671,16 @@ void irlap_reset_confirm(void) */ int irlap_generate_rand_time_slot(int S, int s) { + static int rand; int slot; ASSERT((S - s) > 0, return 0;); - slot = s + jiffies % (S-s); + rand += jiffies; + rand ^= (rand << 12); + rand ^= (rand >> 20); + + slot = s + rand % (S-s); ASSERT((slot >= s) || (slot < S), return 0;); diff -urpN linux-2.4.0-test6/net/irda/irlap_comp.c linux-2.4.0-test6-irda-patch/net/irda/irlap_comp.c --- linux-2.4.0-test6/net/irda/irlap_comp.c Tue Oct 26 05:49:42 1999 +++ linux-2.4.0-test6-irda-patch/net/irda/irlap_comp.c Sun Aug 20 22:03:12 2000 @@ -63,7 +63,7 @@ int irda_register_compressor( struct com new->cp = cp; /* Insert IrDA compressor into hashbin */ - hashbin_insert( irlap_compressors, (queue_t *) new, cp->compress_proto, + hashbin_insert( irlap_compressors, (irda_queue_t *) new, cp->compress_proto, NULL); return 0; diff -urpN linux-2.4.0-test6/net/irda/irlap_event.c linux-2.4.0-test6-irda-patch/net/irda/irlap_event.c --- linux-2.4.0-test6/net/irda/irlap_event.c Thu Jan 6 23:46:18 2000 +++ linux-2.4.0-test6-irda-patch/net/irda/irlap_event.c Sun Aug 20 22:03:12 2000 @@ -9,8 +9,8 @@ * Modified at: Sat Dec 25 21:07:57 1999 * Modified by: Dag Brattli * - * Copyright (c) 1998-1999 Dag Brattli , - * Thomas Davis + * Copyright (c) 1998-2000 Dag Brattli , + * Copyright (c) 1998 Thomas Davis * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -230,7 +230,7 @@ void irlap_do_event(struct irlap_cb *sel if (!self || self->magic != LAP_MAGIC) return; - + IRDA_DEBUG(3, __FUNCTION__ "(), event = %s, state = %s\n", irlap_event[event], irlap_state[self->state]); @@ -252,6 +252,7 @@ void irlap_do_event(struct irlap_cb *sel while ((skb = skb_dequeue(&self->txq)) != NULL) { ret = (*state[self->state])(self, SEND_I_CMD, skb, NULL); + kfree_skb(skb); if (ret == -EPROTO) break; /* Try again later! */ } @@ -351,12 +352,11 @@ static int irlap_state_ndm(struct irlap_ self->caddr = info->caddr; irlap_next_state(self, LAP_CONN); - + irlap_connect_indication(self, skb); } else { IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame does not " "contain an I field!\n"); - dev_kfree_skb(skb); } break; case DISCOVERY_REQUEST: @@ -375,6 +375,7 @@ static int irlap_state_ndm(struct irlap_ self->s = info->s; irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE, info->discovery); + self->frame_sent = FALSE; self->s++; irlap_start_slot_timer(self, self->slot_timeout); @@ -385,12 +386,8 @@ static int irlap_state_ndm(struct irlap_ /* Assert that this is not the final slot */ if (info->s <= info->S) { - /* self->daddr = info->daddr; */ self->slot = irlap_generate_rand_time_slot(info->S, info->s); - IRDA_DEBUG(4, "XID_CMD: S=%d, s=%d, slot %d\n", info->S, - info->s, self->slot); - if (self->slot == info->s) { discovery_rsp = irlmp_get_discovery_response(); discovery_rsp->daddr = info->daddr; @@ -410,14 +407,13 @@ static int irlap_state_ndm(struct irlap_ irlap_start_query_timer(self, QUERY_TIMEOUT*info->S); irlap_next_state(self, LAP_REPLY); } - dev_kfree_skb(skb); break; #ifdef CONFIG_IRDA_ULTRA case SEND_UI_FRAME: /* Only allowed to repeat an operation twice */ for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) { skb = skb_dequeue(&self->txq_ultra); - if (skb) + if (skb) irlap_send_ui_frame(self, skb, CBROADCAST, CMD_FRAME); else @@ -433,7 +429,6 @@ static int irlap_state_ndm(struct irlap_ if (info->caddr != CBROADCAST) { IRDA_DEBUG(0, __FUNCTION__ "(), not a broadcast frame!\n"); - dev_kfree_skb(skb); } else irlap_unitdata_indication(self, skb); break; @@ -447,19 +442,14 @@ static int irlap_state_ndm(struct irlap_ * will only be used to send out the same info as the cmd */ irlap_send_test_frame(self, CBROADCAST, info->daddr, skb); - dev_kfree_skb(skb); break; case RECV_TEST_RSP: IRDA_DEBUG(0, __FUNCTION__ "() not implemented!\n"); - dev_kfree_skb(skb); break; default: IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); - ret = -1; break; } @@ -492,19 +482,31 @@ static int irlap_state_query(struct irla WARNING(__FUNCTION__ "(), discovery log is gone! " "maybe the discovery timeout has been set to " "short?\n"); - dev_kfree_skb(skb); break; } hashbin_insert(self->discovery_log, - (queue_t *) info->discovery, + (irda_queue_t *) info->discovery, info->discovery->daddr, NULL); /* Keep state */ /* irlap_next_state(self, LAP_QUERY); */ - dev_kfree_skb(skb); break; case SLOT_TIMER_EXPIRED: + /* + * Wait a little longer if we detect an incomming frame. This + * is not mentioned in the spec, but is a good thing to do, + * since we want to work even with devices that violate the + * timing requirements. + */ + if (irda_device_is_receiving(self->netdev)) { + IRDA_DEBUG(1, __FUNCTION__ + "(), device is slow to answer, " + "waiting some more!\n"); + irlap_start_slot_timer(self, MSECS_TO_JIFFIES(10)); + return ret; + } + if (self->s < self->S) { irlap_send_discovery_xid_frame(self, self->S, self->s, TRUE, @@ -537,9 +539,6 @@ static int irlap_state_query(struct irla IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); - ret = -1; break; } @@ -572,9 +571,7 @@ static int irlap_state_reply(struct irla break; case RECV_DISCOVERY_XID_CMD: ASSERT(info != NULL, return -1;); - /* - * Last frame? - */ + /* Last frame? */ if (info->s == 0xff) { del_timer(&self->query_timer); @@ -595,15 +592,11 @@ static int irlap_state_reply(struct irla self->frame_sent = TRUE; irlap_next_state(self, LAP_REPLY); } - dev_kfree_skb(skb); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event, irlap_event[event]); - if (skb) - dev_kfree_skb(skb); - ret = -1; break; } @@ -665,14 +658,12 @@ static int irlap_state_conn(struct irlap irlap_start_wd_timer(self, self->wd_timeout); irlap_next_state(self, LAP_NRM_S); - dev_kfree_skb(skb); break; case RECV_DISCOVERY_XID_CMD: IRDA_DEBUG(3, __FUNCTION__ "(), event RECV_DISCOVER_XID_CMD!\n"); irlap_next_state(self, LAP_NDM); - dev_kfree_skb(skb); break; case DISCONNECT_REQUEST: irlap_send_dm_frame(self); @@ -682,9 +673,6 @@ static int irlap_state_conn(struct irlap IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event, irlap_event[event]); - if (skb) - dev_kfree_skb(skb); - ret = -1; break; } @@ -766,7 +754,6 @@ static int irlap_state_setup(struct irla irlap_start_wd_timer(self, self->wd_timeout); } else { /* We just ignore the other device! */ - dev_kfree_skb(skb); irlap_next_state(self, LAP_SETUP); } break; @@ -803,14 +790,11 @@ static int irlap_state_setup(struct irla irlap_next_state(self, LAP_NDM); irlap_disconnect_indication(self, LAP_DISC_INDICATION); - dev_kfree_skb(skb); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event, irlap_event[event]); - if (skb) - dev_kfree_skb(skb); - + ret = -1; break; } @@ -860,14 +844,13 @@ static int irlap_state_xmit_p(struct irl IRDA_DEBUG(4, __FUNCTION__ "(), Not allowed to transmit more " "bytes!\n"); - skb_queue_head(&self->txq, skb); - + skb_queue_head(&self->txq, skb_get(skb)); /* * We should switch state to LAP_NRM_P, but * that is not possible since we must be sure * that we poll the other side. Since we have * used up our time, the poll timer should - * trigger anyway now,so we just wait for it + * trigger anyway now, so we just wait for it * DB */ return -EPROTO; @@ -900,7 +883,7 @@ static int irlap_state_xmit_p(struct irl } else { IRDA_DEBUG(4, __FUNCTION__ "(), Unable to send! remote busy?\n"); - skb_queue_head(&self->txq, skb); + skb_queue_head(&self->txq, skb_get(skb)); /* * The next ret is important, because it tells @@ -929,9 +912,6 @@ static int irlap_state_xmit_p(struct irl IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); - ret = -EINVAL; break; } @@ -964,7 +944,6 @@ static int irlap_state_pclose(struct irl irlap_next_state(self, LAP_NDM); irlap_disconnect_indication(self, LAP_DISC_INDICATION); - dev_kfree_skb(skb); break; case FINAL_TIMER_EXPIRED: if (self->retry_count < self->N3) { @@ -985,9 +964,6 @@ static int irlap_state_pclose(struct irl default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d\n", event); - if (skb) - dev_kfree_skb(skb); - ret = -1; break; } @@ -1041,7 +1017,7 @@ static int irlap_state_nrm_p(struct irla /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_P); - + irlap_data_indication(self, skb, FALSE); } else { del_timer(&self->final_timer); @@ -1065,7 +1041,7 @@ static int irlap_state_nrm_p(struct irla * upper layers */ irlap_next_state(self, LAP_XMIT_P); - + irlap_data_indication(self, skb, FALSE); /* This is the last frame */ @@ -1102,7 +1078,6 @@ static int irlap_state_nrm_p(struct irla irlap_start_final_timer(self, self->final_timeout); irlap_next_state(self, LAP_NRM_P); } - dev_kfree_skb(skb); break; } /* @@ -1124,7 +1099,7 @@ static int irlap_state_nrm_p(struct irla /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_P); - + irlap_data_indication(self, skb, FALSE); } else { /* @@ -1142,7 +1117,7 @@ static int irlap_state_nrm_p(struct irla /* Keep state, do not move this line!*/ irlap_next_state(self, LAP_NRM_P); - + irlap_data_indication(self, skb, FALSE); } break; @@ -1171,7 +1146,6 @@ static int irlap_state_nrm_p(struct irla self->ack_required = FALSE; } - dev_kfree_skb(skb); break; } @@ -1193,7 +1167,6 @@ static int irlap_state_nrm_p(struct irla self->xmitflag = FALSE; } - dev_kfree_skb(skb); break; } IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented!\n"); @@ -1209,6 +1182,7 @@ static int irlap_state_nrm_p(struct irla } else { del_timer(&self->final_timer); irlap_data_indication(self, skb, TRUE); + printk(__FUNCTION__ "(): RECV_UI_FRAME: next state %s\n", irlap_state[self->state]); irlap_start_poll_timer(self, self->poll_timeout); } break; @@ -1270,7 +1244,6 @@ static int irlap_state_nrm_p(struct irla irlap_disconnect_indication(self, LAP_RESET_INDICATION); self->xmitflag = TRUE; } - dev_kfree_skb(skb); break; case RECV_RNR_RSP: ASSERT(info != NULL, return -1;); @@ -1285,14 +1258,12 @@ static int irlap_state_nrm_p(struct irla /* Start poll timer */ irlap_start_poll_timer(self, self->poll_timeout); - dev_kfree_skb(skb); break; case RECV_FRMR_RSP: del_timer(&self->final_timer); self->xmitflag = TRUE; irlap_next_state(self, LAP_RESET_WAIT); irlap_reset_indication(self); - dev_kfree_skb(skb); break; case FINAL_TIMER_EXPIRED: /* @@ -1357,7 +1328,6 @@ static int irlap_state_nrm_p(struct irla } else irlap_resend_rejected_frames(self, CMD_FRAME); irlap_start_final_timer(self, self->final_timeout); - dev_kfree_skb(skb); break; case RECV_SREJ_RSP: irlap_update_nr_received(self, info->nr); @@ -1367,7 +1337,6 @@ static int irlap_state_nrm_p(struct irla } else irlap_resend_rejected_frame(self, CMD_FRAME); irlap_start_final_timer(self, self->final_timeout); - dev_kfree_skb(skb); break; case RECV_RD_RSP: IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n"); @@ -1381,8 +1350,6 @@ static int irlap_state_nrm_p(struct irla default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -1; break; @@ -1428,10 +1395,8 @@ static int irlap_state_reset_wait(struct irlap_next_state( self, LAP_PCLOSE); break; default: - IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", + IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -1; break; @@ -1467,7 +1432,6 @@ static int irlap_state_reset(struct irla irlap_disconnect_indication(self, LAP_NO_RESPONSE); - dev_kfree_skb(skb); break; case RECV_UA_RSP: del_timer(&self->final_timer); @@ -1483,7 +1447,6 @@ static int irlap_state_reset(struct irla irlap_start_poll_timer(self, self->poll_timeout); - dev_kfree_skb(skb); break; case FINAL_TIMER_EXPIRED: if (self->retry_count < 3) { @@ -1522,13 +1485,10 @@ static int irlap_state_reset(struct irla IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame contained an I field!\n"); } - dev_kfree_skb(skb); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -1; break; @@ -1566,7 +1526,7 @@ static int irlap_state_xmit_s(struct irl * speed and turn-around-time. */ if (skb->len > self->bytes_left) { - skb_queue_head(&self->txq, skb); + skb_queue_head(&self->txq, skb_get(skb)); /* * Switch to NRM_S, this is only possible * when we are in secondary mode, since we @@ -1600,7 +1560,7 @@ static int irlap_state_xmit_s(struct irl } } else { IRDA_DEBUG(2, __FUNCTION__ "(), Unable to send!\n"); - skb_queue_head(&self->txq, skb); + skb_queue_head(&self->txq, skb_get(skb)); ret = -EPROTO; } break; @@ -1613,8 +1573,6 @@ static int irlap_state_xmit_s(struct irl default: IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", irlap_event[event]); - if (skb) - dev_kfree_skb(skb); ret = -EINVAL; break; @@ -1676,7 +1634,7 @@ static int irlap_state_nrm_s(struct irla #endif /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_S); - + irlap_data_indication(self, skb, FALSE); break; } else { @@ -1739,7 +1697,6 @@ static int irlap_state_nrm_s(struct irla irlap_start_wd_timer(self, self->wd_timeout); } - dev_kfree_skb(skb); break; } @@ -1778,7 +1735,7 @@ static int irlap_state_nrm_s(struct irla /* Keep state, do not move this line */ irlap_next_state(self, LAP_NRM_S); - + irlap_data_indication(self, skb, FALSE); irlap_start_wd_timer(self, self->wd_timeout); } @@ -1787,11 +1744,9 @@ static int irlap_state_nrm_s(struct irla if (ret == NR_INVALID) { IRDA_DEBUG(0, "NRM_S, NR_INVALID not implemented!\n"); - dev_kfree_skb(skb); } if (ret == NS_INVALID) { IRDA_DEBUG(0, "NRM_S, NS_INVALID not implemented!\n"); - dev_kfree_skb(skb); } break; case RECV_UI_FRAME: @@ -1870,7 +1825,6 @@ static int irlap_state_nrm_s(struct irla IRDA_DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n"); } - dev_kfree_skb(skb); break; case RECV_SNRM_CMD: /* SNRM frame is not allowed to contain an I-field */ @@ -1885,7 +1839,6 @@ static int irlap_state_nrm_s(struct irla "(), SNRM frame contained an I-field!\n"); } - dev_kfree_skb(skb); break; case RECV_REJ_CMD: irlap_update_nr_received(self, info->nr); @@ -1895,7 +1848,6 @@ static int irlap_state_nrm_s(struct irla } else irlap_resend_rejected_frames(self, CMD_FRAME); irlap_start_wd_timer(self, self->wd_timeout); - dev_kfree_skb(skb); break; case RECV_SREJ_CMD: irlap_update_nr_received(self, info->nr); @@ -1905,7 +1857,6 @@ static int irlap_state_nrm_s(struct irla } else irlap_resend_rejected_frame(self, CMD_FRAME); irlap_start_wd_timer(self, self->wd_timeout); - dev_kfree_skb(skb); break; case WD_TIMER_EXPIRED: /* @@ -1944,7 +1895,6 @@ static int irlap_state_nrm_s(struct irla irlap_apply_default_connection_parameters(self); irlap_disconnect_indication(self, LAP_DISC_INDICATION); - dev_kfree_skb(skb); break; case RECV_DISCOVERY_XID_CMD: irlap_wait_min_turn_around(self, &self->qos_tx); @@ -1953,24 +1903,20 @@ static int irlap_state_nrm_s(struct irla irlap_start_wd_timer(self, self->wd_timeout); irlap_next_state(self, LAP_NRM_S); - dev_kfree_skb(skb); break; case RECV_TEST_CMD: - /* Remove test frame header */ - skb_pull(skb, sizeof(struct test_frame)); + /* Remove test frame header (only LAP header in NRM) */ + skb_pull(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_start_wd_timer(self, self->wd_timeout);