📄 irnet_irda.c
字号:
* ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1. * 3) we are half way in irnet_disconnect_indication(), and it's a * nice race condition... Fortunately, we can detect that by checking * if tsap is still alive. On the other hand, we can't be in * irda_irnet_destroy() otherwise we would not have found this * socket in the hashbin. * Jean II */ if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL)) { /* Don't mess this socket, somebody else in in charge... */ DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n"); irnet_disconnect_server(server, skb); return; } } /* So : at this point, we have a socket, and it is idle. Good ! */ irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size); /* Check size of received packet */ if(skb->len > 0) {#ifdef PASS_CONNECT_PACKETS DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); /* Try to pass it to PPP */ irnet_data_indication(new, new->tsap, skb);#else /* PASS_CONNECT_PACKETS */ DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); kfree_skb(skb); /* Note : will be optimised with other kfree... */#endif /* PASS_CONNECT_PACKETS */ } else kfree_skb(skb); DEXIT(IRDA_TCB_TRACE, "\n");}/********************** IRDA-IAS/LMP CALLBACKS **********************//* * These are the callbacks called by other layers of the IrDA stack, * mainly LMP for discovery and IAS for name queries. *//*------------------------------------------------------------------*//* * Function irnet_getvalue_confirm (result, obj_id, value, priv) * * Got answer from remote LM-IAS, just connect * * This is the reply to a IAS query we were doing to find the TSAP of * the device we want to connect to. * If we have found a valid TSAP, just initiate the TTP connection * on this TSAP. */static voidirnet_getvalue_confirm(int result, __u16 obj_id, struct ias_value *value, void * priv){ irnet_socket * self = (irnet_socket *) priv; DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); /* Check if already connected (via irnet_connect_socket()) * or socket is closing down (via irda_irnet_destroy()) */ if(! test_bit(0, &self->ttp_connect)) { DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); return; } /* We probably don't need to make any more queries */ iriap_close(self->iriap); self->iriap = NULL; /* Post process the IAS reply */ self->dtsap_sel = irnet_ias_to_tsap(self, result, value); /* If error, just go out */ if(self->errno) { clear_bit(0, &self->ttp_connect); DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno); return; } DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", self->daddr, self->dtsap_sel); /* Start up TTP - non blocking */ irnet_connect_tsap(self); DEXIT(IRDA_OCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_discovervalue_confirm (result, obj_id, value, priv) * * Handle the TSAP discovery procedure state machine. * Got answer from remote LM-IAS, try next device * * We are doing a TSAP discovery procedure, and we got an answer to * a IAS query we were doing to find the TSAP on one of the address * in the discovery log. * * If we have found a valid TSAP for the first time, save it. If it's * not the first time we found one, complain. * * If we have more addresses in the log, just initiate a new query. * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel()) * * Otherwise, wrap up the procedure (cleanup), check if we have found * any device and connect to it. */static voidirnet_discovervalue_confirm(int result, __u16 obj_id, struct ias_value *value, void * priv){ irnet_socket * self = (irnet_socket *) priv; __u8 dtsap_sel; /* TSAP we are looking for */ DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); /* Check if already connected (via irnet_connect_socket()) * or socket is closing down (via irda_irnet_destroy()) */ if(! test_bit(0, &self->ttp_connect)) { DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); return; } /* Post process the IAS reply */ dtsap_sel = irnet_ias_to_tsap(self, result, value); /* Have we got something ? */ if(self->errno == 0) { /* We found the requested service */ if(self->daddr != DEV_ADDR_ANY) { DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n"); } else { /* First time we found that one, save it ! */ self->daddr = self->discoveries[self->disco_index].daddr; self->dtsap_sel = dtsap_sel; } } /* If no failure */ if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0)) { int ret; /* Search the next node */ ret = irnet_discover_next_daddr(self); if(!ret) { /* In this case, the above request was non-blocking. * We will return here after a while... */ return; } /* In this case, we have processed the last discovery item */ } /* No more queries to be done (failure or last one) */ /* We probably don't need to make any more queries */ iriap_close(self->iriap); self->iriap = NULL; /* No more items : remove the log and signal termination */ DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%X)\n", (unsigned int) self->discoveries); if(self->discoveries != NULL) { /* Cleanup our copy of the discovery log */ kfree(self->discoveries); self->discoveries = NULL; } self->disco_number = -1; /* Check out what we found */ if(self->daddr == DEV_ADDR_ANY) { self->daddr = DEV_ADDR_ANY; clear_bit(0, &self->ttp_connect); DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n"); return; } /* We have a valid address - just connect */ DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", self->daddr, self->dtsap_sel); /* Start up TTP - non blocking */ irnet_connect_tsap(self); DEXIT(IRDA_OCB_TRACE, "\n");}#ifdef DISCOVERY_EVENTS/*------------------------------------------------------------------*//* * Function irnet_discovery_indication (discovery) * * Got a discovery indication from IrLMP, post an event * * Note : IrLMP take care of matching the hint mask for us, we only * check if it is a "new" node... * * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET * nodes, so it's only at connection time that we will know if the * node support IrNET, IrLAN or both. The other solution is to check * in IAS the PNP ids and service name. * Note : even if a node support IrNET (or IrLAN), it's no guarantee * that we will be able to connect to it, the node might already be * busy... * * One last thing : in some case, this function will trigger duplicate * discovery events. On the other hand, we should catch all * discoveries properly (i.e. not miss one). Filtering duplicate here * is to messy, so we leave that to user space... */static voidirnet_discovery_indication(discovery_t * discovery, DISCOVERY_MODE mode, void * priv){ irnet_socket * self = &irnet_server.s; DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, "Invalid instance (0x%X) !!!\n", (unsigned int) priv); /* 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). */ if((jiffies - discovery->first_timestamp) >= (sysctl_discovery_timeout * HZ)) { return; /* Too old, not interesting -> goodbye */ } DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", discovery->nickname); /* Notify the control channel */ irnet_post_event(NULL, IRNET_DISCOVER, discovery->saddr, discovery->daddr, discovery->nickname); DEXIT(IRDA_OCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_expiry_indication (expiry) * * Got a expiry indication from IrLMP, post an event * * Note : IrLMP take care of matching the hint mask for us, we only * check if it is a "new" node... */static voidirnet_expiry_indication(discovery_t * expiry, DISCOVERY_MODE mode, void * priv){ irnet_socket * self = &irnet_server.s; DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, "Invalid instance (0x%X) !!!\n", (unsigned int) priv); DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", expiry->nickname); /* Notify the control channel */ irnet_post_event(NULL, IRNET_EXPIRE, expiry->saddr, expiry->daddr, expiry->nickname); DEXIT(IRDA_OCB_TRACE, "\n");}#endif /* DISCOVERY_EVENTS *//*********************** PROC ENTRY CALLBACKS ***********************//* * We create a instance in the /proc filesystem, and here we take care * of that... */#ifdef CONFIG_PROC_FS/*------------------------------------------------------------------*//* * Function irnet_proc_read (buf, start, offset, len, unused) * * Give some info to the /proc file system */static intirnet_proc_read(char * buf, char ** start, off_t offset, int len){ irnet_socket * self; char * state; unsigned long flags; int i = 0; len = 0; /* Get the IrNET server information... */ len += sprintf(buf+len, "IrNET server - "); len += sprintf(buf+len, "IrDA state: %s, ", (irnet_server.running ? "running" : "dead")); len += sprintf(buf+len, "stsap_sel: %02x, ", irnet_server.s.stsap_sel); len += sprintf(buf+len, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel); /* Do we need to continue ? */ if(!irnet_server.running) return len; /* Protect access to the instance list */ spin_lock_irqsave(&irnet_server.spinlock, flags); /* Get the sockets one by one... */ self = (irnet_socket *) hashbin_get_first(irnet_server.list); while(self != NULL) { /* Start printing info about the socket. */ len += sprintf(buf+len, "\nIrNET socket %d - ", i++); /* First, get the requested configuration */ len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname); len += sprintf(buf+len, "daddr: %08x, ", self->rdaddr); len += sprintf(buf+len, "saddr: %08x\n", self->rsaddr); /* Second, get all the PPP info */ len += sprintf(buf+len, " PPP state: %s", (self->ppp_open ? "registered" : "unregistered")); if(self->ppp_open) { len += sprintf(buf+len, ", unit: ppp%d", ppp_unit_number(&self->chan)); len += sprintf(buf+len, ", channel: %d", ppp_channel_index(&self->chan)); len += sprintf(buf+len, ", mru: %d", self->mru); /* Maybe add self->flags ? Later... */ } /* Then, get all the IrDA specific info... */ if(self->ttp_open) state = "connected"; else if(self->tsap != NULL) state = "connecting"; else if(self->iriap != NULL) state = "searching"; else if(self->ttp_connect) state = "weird"; else state = "idle"; len += sprintf(buf+len, "\n IrDA state: %s, ", state); len += sprintf(buf+len, "daddr: %08x, ", self->daddr); len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel); len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel); /* Next socket, please... */ self = (irnet_socket *) hashbin_get_next(irnet_server.list); } /* Spin lock end */ spin_unlock_irqrestore(&irnet_server.spinlock, flags); return len;}#endif /* PROC_FS *//********************** CONFIGURATION/CLEANUP **********************//* * Initialisation and teardown of the IrDA part, called at module * insertion and removal... *//*------------------------------------------------------------------*//* * Prepare the IrNET layer for operation... */intirda_irnet_init(void){ int err = 0; DENTER(MODULE_TRACE, "()\n"); /* Pure paranoia - should be redundant */ memset(&irnet_server, 0, sizeof(struct irnet_root)); /* Setup start of irnet instance list */ irnet_server.list = hashbin_new(HB_NOLOCK); DABORT(irnet_server.list == NULL, -ENOMEM, MODULE_ERROR, "Can't allocate hashbin!\n"); /* Init spinlock for instance list */ spin_lock_init(&irnet_server.spinlock); /* Initialise control channel */ init_waitqueue_head(&irnet_events.rwait); irnet_events.index = 0; /* Init spinlock for event logging */ spin_lock_init(&irnet_events.spinlock);#ifdef CONFIG_PROC_FS /* Add a /proc file for irnet infos */ create_proc_info_entry("irnet", 0, proc_irda, irnet_proc_read);#endif /* CONFIG_PROC_FS */ /* Setup the IrNET server */ err = irnet_setup_server(); if(!err) /* We are no longer functional... */ irnet_server.running = 1; DEXIT(MODULE_TRACE, "\n"); return err;}/*------------------------------------------------------------------*//* * Cleanup at exit... */voidirda_irnet_cleanup(void){ DENTER(MODULE_TRACE, "()\n"); /* We are no longer there... */ irnet_server.running = 0;#ifdef CONFIG_PROC_FS /* Remove our /proc file */ remove_proc_entry("irnet", proc_irda);#endif /* CONFIG_PROC_FS */ /* Remove our IrNET server from existence */ irnet_destroy_server(); /* Remove all instances of IrNET socket still present */ hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy); DEXIT(MODULE_TRACE, "\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -