/*1* IrNET protocol module : Synchronous PPP over an IrDA socket.2*3* Jean II - HPL `00 - <[email protected]>4*5* This file implement the IRDA interface of IrNET.6* Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly,7* and exchange frames with IrTTP.8*/910#include "irnet_irda.h" /* Private header */11#include <linux/sched.h>12#include <linux/seq_file.h>13#include <linux/slab.h>14#include <asm/unaligned.h>1516/*17* PPP disconnect work: we need to make sure we're in18* process context when calling ppp_unregister_channel().19*/20static void irnet_ppp_disconnect(struct work_struct *work)21{22irnet_socket * self =23container_of(work, irnet_socket, disconnect_work);2425if (self == NULL)26return;27/*28* If we were connected, cleanup & close the PPP29* channel, which will kill pppd (hangup) and the rest.30*/31if (self->ppp_open && !self->ttp_open && !self->ttp_connect) {32ppp_unregister_channel(&self->chan);33self->ppp_open = 0;34}35}3637/************************* CONTROL CHANNEL *************************/38/*39* When ppp is not active, /dev/irnet act as a control channel.40* Writing allow to set up the IrDA destination of the IrNET channel,41* and any application may be read events happening on IrNET...42*/4344/*------------------------------------------------------------------*/45/*46* Post an event to the control channel...47* Put the event in the log, and then wait all process blocked on read48* so they can read the log...49*/50static void51irnet_post_event(irnet_socket * ap,52irnet_event event,53__u32 saddr,54__u32 daddr,55char * name,56__u16 hints)57{58int index; /* In the log */5960DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n",61ap, event, daddr, name);6263/* Protect this section via spinlock.64* Note : as we are the only event producer, we only need to exclude65* ourself when touching the log, which is nice and easy.66*/67spin_lock_bh(&irnet_events.spinlock);6869/* Copy the event in the log */70index = irnet_events.index;71irnet_events.log[index].event = event;72irnet_events.log[index].daddr = daddr;73irnet_events.log[index].saddr = saddr;74/* Try to copy IrDA nickname */75if(name)76strcpy(irnet_events.log[index].name, name);77else78irnet_events.log[index].name[0] = '\0';79/* Copy hints */80irnet_events.log[index].hints.word = hints;81/* Try to get ppp unit number */82if((ap != (irnet_socket *) NULL) && (ap->ppp_open))83irnet_events.log[index].unit = ppp_unit_number(&ap->chan);84else85irnet_events.log[index].unit = -1;8687/* Increment the index88* Note that we increment the index only after the event is written,89* to make sure that the readers don't get garbage... */90irnet_events.index = (index + 1) % IRNET_MAX_EVENTS;9192DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);9394/* Spin lock end */95spin_unlock_bh(&irnet_events.spinlock);9697/* Now : wake up everybody waiting for events... */98wake_up_interruptible_all(&irnet_events.rwait);99100DEXIT(CTRL_TRACE, "\n");101}102103/************************* IRDA SUBROUTINES *************************/104/*105* These are a bunch of subroutines called from other functions106* down there, mostly common code or to improve readability...107*108* Note : we duplicate quite heavily some routines of af_irda.c,109* because our input structure (self) is quite different110* (struct irnet instead of struct irda_sock), which make sharing111* the same code impossible (at least, without templates).112*/113114/*------------------------------------------------------------------*/115/*116* Function irda_open_tsap (self)117*118* Open local Transport Service Access Point (TSAP)119*120* Create a IrTTP instance for us and set all the IrTTP callbacks.121*/122static inline int123irnet_open_tsap(irnet_socket * self)124{125notify_t notify; /* Callback structure */126127DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);128129DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n");130131/* Initialize IrTTP callbacks to be used by the IrDA stack */132irda_notify_init(¬ify);133notify.connect_confirm = irnet_connect_confirm;134notify.connect_indication = irnet_connect_indication;135notify.disconnect_indication = irnet_disconnect_indication;136notify.data_indication = irnet_data_indication;137/*notify.udata_indication = NULL;*/138notify.flow_indication = irnet_flow_indication;139notify.status_indication = irnet_status_indication;140notify.instance = self;141strlcpy(notify.name, IRNET_NOTIFY_NAME, sizeof(notify.name));142143/* Open an IrTTP instance */144self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,145¬ify);146DABORT(self->tsap == NULL, -ENOMEM,147IRDA_SR_ERROR, "Unable to allocate TSAP !\n");148149/* Remember which TSAP selector we actually got */150self->stsap_sel = self->tsap->stsap_sel;151152DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n",153self->tsap, self->stsap_sel);154return 0;155}156157/*------------------------------------------------------------------*/158/*159* Function irnet_ias_to_tsap (self, result, value)160*161* Examine an IAS object and extract TSAP162*163* We do an IAP query to find the TSAP associated with the IrNET service.164* When IrIAP pass us the result of the query, this function look at165* the return values to check for failures and extract the TSAP if166* possible.167* Also deallocate value168* The failure is in self->errno169* Return TSAP or -1170*/171static inline __u8172irnet_ias_to_tsap(irnet_socket * self,173int result,174struct ias_value * value)175{176__u8 dtsap_sel = 0; /* TSAP we are looking for */177178DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);179180/* By default, no error */181self->errno = 0;182183/* Check if request succeeded */184switch(result)185{186/* Standard errors : service not available */187case IAS_CLASS_UNKNOWN:188case IAS_ATTRIB_UNKNOWN:189DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result);190self->errno = -EADDRNOTAVAIL;191break;192193/* Other errors, most likely IrDA stack failure */194default :195DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result);196self->errno = -EHOSTUNREACH;197break;198199/* Success : we got what we wanted */200case IAS_SUCCESS:201break;202}203204/* Check what was returned to us */205if(value != NULL)206{207/* What type of argument have we got ? */208switch(value->type)209{210case IAS_INTEGER:211DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer);212if(value->t.integer != -1)213/* Get the remote TSAP selector */214dtsap_sel = value->t.integer;215else216self->errno = -EADDRNOTAVAIL;217break;218default:219self->errno = -EADDRNOTAVAIL;220DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type);221break;222}223224/* Cleanup */225irias_delete_value(value);226}227else /* value == NULL */228{229/* Nothing returned to us - usually result != SUCCESS */230if(!(self->errno))231{232DERROR(IRDA_SR_ERROR,233"IrDA bug : result == SUCCESS && value == NULL\n");234self->errno = -EHOSTUNREACH;235}236}237DEXIT(IRDA_SR_TRACE, "\n");238239/* Return the TSAP */240return dtsap_sel;241}242243/*------------------------------------------------------------------*/244/*245* Function irnet_find_lsap_sel (self)246*247* Try to lookup LSAP selector in remote LM-IAS248*249* Basically, we start a IAP query, and then go to sleep. When the query250* return, irnet_getvalue_confirm will wake us up, and we can examine the251* result of the query...252* Note that in some case, the query fail even before we go to sleep,253* creating some races...254*/255static inline int256irnet_find_lsap_sel(irnet_socket * self)257{258DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);259260/* This should not happen */261DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n");262263/* Create an IAP instance, will be closed in irnet_getvalue_confirm() */264self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,265irnet_getvalue_confirm);266267/* Treat unexpected signals as disconnect */268self->errno = -EHOSTUNREACH;269270/* Query remote LM-IAS */271iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr,272IRNET_SERVICE_NAME, IRNET_IAS_VALUE);273274/* The above request is non-blocking.275* After a while, IrDA will call us back in irnet_getvalue_confirm()276* We will then call irnet_ias_to_tsap() and finish the277* connection procedure */278279DEXIT(IRDA_SR_TRACE, "\n");280return 0;281}282283/*------------------------------------------------------------------*/284/*285* Function irnet_connect_tsap (self)286*287* Initialise the TTP socket and initiate TTP connection288*289*/290static inline int291irnet_connect_tsap(irnet_socket * self)292{293int err;294295DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);296297/* Open a local TSAP (an IrTTP instance) */298err = irnet_open_tsap(self);299if(err != 0)300{301clear_bit(0, &self->ttp_connect);302DERROR(IRDA_SR_ERROR, "connect aborted!\n");303return err;304}305306/* Connect to remote device */307err = irttp_connect_request(self->tsap, self->dtsap_sel,308self->rsaddr, self->daddr, NULL,309self->max_sdu_size_rx, NULL);310if(err != 0)311{312clear_bit(0, &self->ttp_connect);313DERROR(IRDA_SR_ERROR, "connect aborted!\n");314return err;315}316317/* The above call is non-blocking.318* After a while, the IrDA stack will either call us back in319* irnet_connect_confirm() or irnet_disconnect_indication()320* See you there ;-) */321322DEXIT(IRDA_SR_TRACE, "\n");323return err;324}325326/*------------------------------------------------------------------*/327/*328* Function irnet_discover_next_daddr (self)329*330* Query the IrNET TSAP of the next device in the log.331*332* Used in the TSAP discovery procedure.333*/334static inline int335irnet_discover_next_daddr(irnet_socket * self)336{337/* Close the last instance of IrIAP, and open a new one.338* We can't reuse the IrIAP instance in the IrIAP callback */339if(self->iriap)340{341iriap_close(self->iriap);342self->iriap = NULL;343}344/* Create a new IAP instance */345self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,346irnet_discovervalue_confirm);347if(self->iriap == NULL)348return -ENOMEM;349350/* Next discovery - before the call to avoid races */351self->disco_index++;352353/* Check if we have one more address to try */354if(self->disco_index < self->disco_number)355{356/* Query remote LM-IAS */357iriap_getvaluebyclass_request(self->iriap,358self->discoveries[self->disco_index].saddr,359self->discoveries[self->disco_index].daddr,360IRNET_SERVICE_NAME, IRNET_IAS_VALUE);361/* The above request is non-blocking.362* After a while, IrDA will call us back in irnet_discovervalue_confirm()363* We will then call irnet_ias_to_tsap() and come back here again... */364return 0;365}366else367return 1;368}369370/*------------------------------------------------------------------*/371/*372* Function irnet_discover_daddr_and_lsap_sel (self)373*374* This try to find a device with the requested service.375*376* Initiate a TSAP discovery procedure.377* It basically look into the discovery log. For each address in the list,378* it queries the LM-IAS of the device to find if this device offer379* the requested service.380* If there is more than one node supporting the service, we complain381* to the user (it should move devices around).382* If we find one node which have the requested TSAP, we connect to it.383*384* This function just start the whole procedure. It request the discovery385* log and submit the first IAS query.386* The bulk of the job is handled in irnet_discovervalue_confirm()387*388* Note : this procedure fails if there is more than one device in range389* on the same dongle, because IrLMP doesn't disconnect the LAP when the390* last LSAP is closed. Moreover, we would need to wait the LAP391* disconnection...392*/393static inline int394irnet_discover_daddr_and_lsap_sel(irnet_socket * self)395{396int ret;397398DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);399400/* Ask lmp for the current discovery log */401self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask,402DISCOVERY_DEFAULT_SLOTS);403404/* Check if the we got some results */405if(self->discoveries == NULL)406{407self->disco_number = -1;408clear_bit(0, &self->ttp_connect);409DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n");410}411DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n",412self->discoveries, self->disco_number);413414/* Start with the first discovery */415self->disco_index = -1;416self->daddr = DEV_ADDR_ANY;417418/* This will fail if the log is empty - this is non-blocking */419ret = irnet_discover_next_daddr(self);420if(ret)421{422/* Close IAP */423if(self->iriap)424iriap_close(self->iriap);425self->iriap = NULL;426427/* Cleanup our copy of the discovery log */428kfree(self->discoveries);429self->discoveries = NULL;430431clear_bit(0, &self->ttp_connect);432DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");433}434435/* Follow me in irnet_discovervalue_confirm() */436437DEXIT(IRDA_SR_TRACE, "\n");438return 0;439}440441/*------------------------------------------------------------------*/442/*443* Function irnet_dname_to_daddr (self)444*445* Convert an IrDA nickname to a valid IrDA address446*447* It basically look into the discovery log until there is a match.448*/449static inline int450irnet_dname_to_daddr(irnet_socket * self)451{452struct irda_device_info *discoveries; /* Copy of the discovery log */453int number; /* Number of nodes in the log */454int i;455456DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);457458/* Ask lmp for the current discovery log */459discoveries = irlmp_get_discoveries(&number, 0xffff,460DISCOVERY_DEFAULT_SLOTS);461/* Check if the we got some results */462if(discoveries == NULL)463DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");464465/*466* Now, check all discovered devices (if any), and connect467* client only about the services that the client is468* interested in...469*/470for(i = 0; i < number; i++)471{472/* Does the name match ? */473if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN))474{475/* Yes !!! Get it.. */476self->daddr = discoveries[i].daddr;477DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n",478self->rname, self->daddr);479kfree(discoveries);480DEXIT(IRDA_SR_TRACE, "\n");481return 0;482}483}484/* No luck ! */485DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname);486kfree(discoveries);487return -EADDRNOTAVAIL;488}489490491/************************* SOCKET ROUTINES *************************/492/*493* This are the main operations on IrNET sockets, basically to create494* and destroy IrNET sockets. These are called from the PPP part...495*/496497/*------------------------------------------------------------------*/498/*499* Create a IrNET instance : just initialise some parameters...500*/501int502irda_irnet_create(irnet_socket * self)503{504DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self);505506self->magic = IRNET_MAGIC; /* Paranoia */507508self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */509self->ttp_connect = 0; /* Not connecting yet */510self->rname[0] = '\0'; /* May be set via control channel */511self->rdaddr = DEV_ADDR_ANY; /* May be set via control channel */512self->rsaddr = DEV_ADDR_ANY; /* May be set via control channel */513self->daddr = DEV_ADDR_ANY; /* Until we get connected */514self->saddr = DEV_ADDR_ANY; /* Until we get connected */515self->max_sdu_size_rx = TTP_SAR_UNBOUND;516517/* Register as a client with IrLMP */518self->ckey = irlmp_register_client(0, NULL, NULL, NULL);519#ifdef DISCOVERY_NOMASK520self->mask = 0xffff; /* For W2k compatibility */521#else /* DISCOVERY_NOMASK */522self->mask = irlmp_service_to_hint(S_LAN);523#endif /* DISCOVERY_NOMASK */524self->tx_flow = FLOW_START; /* Flow control from IrTTP */525526INIT_WORK(&self->disconnect_work, irnet_ppp_disconnect);527528DEXIT(IRDA_SOCK_TRACE, "\n");529return 0;530}531532/*------------------------------------------------------------------*/533/*534* Connect to the other side :535* o convert device name to an address536* o find the socket number (dlsap)537* o Establish the connection538*539* Note : We no longer mimic af_irda. The IAS query for finding the TSAP540* is done asynchronously, like the TTP connection. This allow us to541* call this function from any context (not only process).542* The downside is that following what's happening in there is tricky543* because it involve various functions all over the place...544*/545int546irda_irnet_connect(irnet_socket * self)547{548int err;549550DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self);551552/* Check if we are already trying to connect.553* Because irda_irnet_connect() can be called directly by pppd plus554* packet retries in ppp_generic and connect may take time, plus we may555* race with irnet_connect_indication(), we need to be careful there... */556if(test_and_set_bit(0, &self->ttp_connect))557DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n");558if((self->iriap != NULL) || (self->tsap != NULL))559DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n");560561/* Insert ourselves in the hashbin so that the IrNET server can find us.562* Notes : 4th arg is string of 32 char max and must be null terminated563* When 4th arg is used (string), 3rd arg isn't (int)564* Can't re-insert (MUST remove first) so check for that... */565if((irnet_server.running) && (self->q.q_next == NULL))566{567spin_lock_bh(&irnet_server.spinlock);568hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname);569spin_unlock_bh(&irnet_server.spinlock);570DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname);571}572573/* If we don't have anything (no address, no name) */574if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0'))575{576/* Try to find a suitable address */577if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0)578DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n");579/* In most cases, the call above is non-blocking */580}581else582{583/* If we have only the name (no address), try to get an address */584if(self->rdaddr == DEV_ADDR_ANY)585{586if((err = irnet_dname_to_daddr(self)) != 0)587DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n");588}589else590/* Use the requested destination address */591self->daddr = self->rdaddr;592593/* Query remote LM-IAS to find LSAP selector */594irnet_find_lsap_sel(self);595/* The above call is non blocking */596}597598/* At this point, we are waiting for the IrDA stack to call us back,599* or we have already failed.600* We will finish the connection procedure in irnet_connect_tsap().601*/602DEXIT(IRDA_SOCK_TRACE, "\n");603return 0;604}605606/*------------------------------------------------------------------*/607/*608* Function irda_irnet_destroy(self)609*610* Destroy irnet instance611*612* Note : this need to be called from a process context.613*/614void615irda_irnet_destroy(irnet_socket * self)616{617DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self);618if(self == NULL)619return;620621/* Remove ourselves from hashbin (if we are queued in hashbin)622* Note : `irnet_server.running' protect us from calls in hashbin_delete() */623if((irnet_server.running) && (self->q.q_next != NULL))624{625struct irnet_socket * entry;626DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n");627spin_lock_bh(&irnet_server.spinlock);628entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self);629self->q.q_next = NULL;630spin_unlock_bh(&irnet_server.spinlock);631DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");632}633634/* If we were connected, post a message */635if(test_bit(0, &self->ttp_open))636{637/* Note : as the disconnect comes from ppp_generic, the unit number638* doesn't exist anymore when we post the event, so we need to pass639* NULL as the first arg... */640irnet_post_event(NULL, IRNET_DISCONNECT_TO,641self->saddr, self->daddr, self->rname, 0);642}643644/* Prevent various IrDA callbacks from messing up things645* Need to be first */646clear_bit(0, &self->ttp_connect);647648/* Prevent higher layer from accessing IrTTP */649clear_bit(0, &self->ttp_open);650651/* Unregister with IrLMP */652irlmp_unregister_client(self->ckey);653654/* Unregister with LM-IAS */655if(self->iriap)656{657iriap_close(self->iriap);658self->iriap = NULL;659}660661/* Cleanup eventual discoveries from connection attempt or control channel */662if(self->discoveries != NULL)663{664/* Cleanup our copy of the discovery log */665kfree(self->discoveries);666self->discoveries = NULL;667}668669/* Close our IrTTP connection */670if(self->tsap)671{672DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n");673irttp_disconnect_request(self->tsap, NULL, P_NORMAL);674irttp_close_tsap(self->tsap);675self->tsap = NULL;676}677self->stsap_sel = 0;678679DEXIT(IRDA_SOCK_TRACE, "\n");680}681682683/************************** SERVER SOCKET **************************/684/*685* The IrNET service is composed of one server socket and a variable686* number of regular IrNET sockets. The server socket is supposed to687* handle incoming connections and redirect them to one IrNET sockets.688* It's a superset of the regular IrNET socket, but has a very distinct689* behaviour...690*/691692/*------------------------------------------------------------------*/693/*694* Function irnet_daddr_to_dname (self)695*696* Convert an IrDA address to a IrDA nickname697*698* It basically look into the discovery log until there is a match.699*/700static inline int701irnet_daddr_to_dname(irnet_socket * self)702{703struct irda_device_info *discoveries; /* Copy of the discovery log */704int number; /* Number of nodes in the log */705int i;706707DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self);708709/* Ask lmp for the current discovery log */710discoveries = irlmp_get_discoveries(&number, 0xffff,711DISCOVERY_DEFAULT_SLOTS);712/* Check if the we got some results */713if (discoveries == NULL)714DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n");715716/* Now, check all discovered devices (if any) */717for(i = 0; i < number; i++)718{719/* Does the name match ? */720if(discoveries[i].daddr == self->daddr)721{722/* Yes !!! Get it.. */723strlcpy(self->rname, discoveries[i].info, sizeof(self->rname));724self->rname[sizeof(self->rname) - 1] = '\0';725DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n",726self->daddr, self->rname);727kfree(discoveries);728DEXIT(IRDA_SERV_TRACE, "\n");729return 0;730}731}732/* No luck ! */733DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr);734kfree(discoveries);735return -EADDRNOTAVAIL;736}737738/*------------------------------------------------------------------*/739/*740* Function irda_find_socket (self)741*742* Find the correct IrNET socket743*744* Look into the list of IrNET sockets and finds one with the right745* properties...746*/747static inline irnet_socket *748irnet_find_socket(irnet_socket * self)749{750irnet_socket * new = (irnet_socket *) NULL;751int err;752753DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self);754755/* Get the addresses of the requester */756self->daddr = irttp_get_daddr(self->tsap);757self->saddr = irttp_get_saddr(self->tsap);758759/* Try to get the IrDA nickname of the requester */760err = irnet_daddr_to_dname(self);761762/* Protect access to the instance list */763spin_lock_bh(&irnet_server.spinlock);764765/* So now, try to get an socket having specifically766* requested that nickname */767if(err == 0)768{769new = (irnet_socket *) hashbin_find(irnet_server.list,7700, self->rname);771if(new)772DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n",773new, new->rname);774}775776/* If no name matches, try to find an socket by the destination address */777/* It can be either the requested destination address (set via the778* control channel), or the current destination address if the779* socket is in the middle of a connection request */780if(new == (irnet_socket *) NULL)781{782new = (irnet_socket *) hashbin_get_first(irnet_server.list);783while(new !=(irnet_socket *) NULL)784{785/* Does it have the same address ? */786if((new->rdaddr == self->daddr) || (new->daddr == self->daddr))787{788/* Yes !!! Get it.. */789DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n",790new, self->daddr);791break;792}793new = (irnet_socket *) hashbin_get_next(irnet_server.list);794}795}796797/* If we don't have any socket, get the first unconnected socket */798if(new == (irnet_socket *) NULL)799{800new = (irnet_socket *) hashbin_get_first(irnet_server.list);801while(new !=(irnet_socket *) NULL)802{803/* Is it available ? */804if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) &&805(new->rname[0] == '\0') && (new->ppp_open))806{807/* Yes !!! Get it.. */808DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n",809new);810break;811}812new = (irnet_socket *) hashbin_get_next(irnet_server.list);813}814}815816/* Spin lock end */817spin_unlock_bh(&irnet_server.spinlock);818819DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new);820return new;821}822823/*------------------------------------------------------------------*/824/*825* Function irda_connect_socket (self)826*827* Connect an incoming connection to the socket828*829*/830static inline int831irnet_connect_socket(irnet_socket * server,832irnet_socket * new,833struct qos_info * qos,834__u32 max_sdu_size,835__u8 max_header_size)836{837DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n",838server, new);839840/* Now attach up the new socket */841new->tsap = irttp_dup(server->tsap, new);842DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n");843844/* Set up all the relevant parameters on the new socket */845new->stsap_sel = new->tsap->stsap_sel;846new->dtsap_sel = new->tsap->dtsap_sel;847new->saddr = irttp_get_saddr(new->tsap);848new->daddr = irttp_get_daddr(new->tsap);849850new->max_header_size = max_header_size;851new->max_sdu_size_tx = max_sdu_size;852new->max_data_size = max_sdu_size;853#ifdef STREAM_COMPAT854/* If we want to receive "stream sockets" */855if(max_sdu_size == 0)856new->max_data_size = irttp_get_max_seg_size(new->tsap);857#endif /* STREAM_COMPAT */858859/* Clean up the original one to keep it in listen state */860irttp_listen(server->tsap);861862/* Send a connection response on the new socket */863irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);864865/* Allow PPP to send its junk over the new socket... */866set_bit(0, &new->ttp_open);867868/* Not connecting anymore, and clean up last possible remains869* of connection attempts on the socket */870clear_bit(0, &new->ttp_connect);871if(new->iriap)872{873iriap_close(new->iriap);874new->iriap = NULL;875}876if(new->discoveries != NULL)877{878kfree(new->discoveries);879new->discoveries = NULL;880}881882#ifdef CONNECT_INDIC_KICK883/* As currently we don't block packets in ppp_irnet_send() while passive,884* this is not really needed...885* Also, not doing it give IrDA a chance to finish the setup properly886* before being swamped with packets... */887ppp_output_wakeup(&new->chan);888#endif /* CONNECT_INDIC_KICK */889890/* Notify the control channel */891irnet_post_event(new, IRNET_CONNECT_FROM,892new->saddr, new->daddr, server->rname, 0);893894DEXIT(IRDA_SERV_TRACE, "\n");895return 0;896}897898/*------------------------------------------------------------------*/899/*900* Function irda_disconnect_server (self)901*902* Cleanup the server socket when the incoming connection abort903*904*/905static inline void906irnet_disconnect_server(irnet_socket * self,907struct sk_buff *skb)908{909DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self);910911/* Put the received packet in the black hole */912kfree_skb(skb);913914#ifdef FAIL_SEND_DISCONNECT915/* Tell the other party we don't want to be connected */916/* Hum... Is it the right thing to do ? And do we need to send917* a connect response before ? It looks ok without this... */918irttp_disconnect_request(self->tsap, NULL, P_NORMAL);919#endif /* FAIL_SEND_DISCONNECT */920921/* Notify the control channel (see irnet_find_socket()) */922irnet_post_event(NULL, IRNET_REQUEST_FROM,923self->saddr, self->daddr, self->rname, 0);924925/* Clean up the server to keep it in listen state */926irttp_listen(self->tsap);927928DEXIT(IRDA_SERV_TRACE, "\n");929}930931/*------------------------------------------------------------------*/932/*933* Function irda_setup_server (self)934*935* Create a IrTTP server and set it up...936*937* Register the IrLAN hint bit, create a IrTTP instance for us,938* set all the IrTTP callbacks and create an IrIAS entry...939*/940static inline int941irnet_setup_server(void)942{943__u16 hints;944945DENTER(IRDA_SERV_TRACE, "()\n");946947/* Initialise the regular socket part of the server */948irda_irnet_create(&irnet_server.s);949950/* Open a local TSAP (an IrTTP instance) for the server */951irnet_open_tsap(&irnet_server.s);952953/* PPP part setup */954irnet_server.s.ppp_open = 0;955irnet_server.s.chan.private = NULL;956irnet_server.s.file = NULL;957958/* Get the hint bit corresponding to IrLAN */959/* Note : we overload the IrLAN hint bit. As it is only a "hint", and as960* we provide roughly the same functionality as IrLAN, this is ok.961* In fact, the situation is similar as JetSend overloading the Obex hint962*/963hints = irlmp_service_to_hint(S_LAN);964965#ifdef ADVERTISE_HINT966/* Register with IrLMP as a service (advertise our hint bit) */967irnet_server.skey = irlmp_register_service(hints);968#endif /* ADVERTISE_HINT */969970/* Register with LM-IAS (so that people can connect to us) */971irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies);972irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE,973irnet_server.s.stsap_sel, IAS_KERNEL_ATTR);974irias_insert_object(irnet_server.ias_obj);975976#ifdef DISCOVERY_EVENTS977/* Tell IrLMP we want to be notified of newly discovered nodes */978irlmp_update_client(irnet_server.s.ckey, hints,979irnet_discovery_indication, irnet_expiry_indication,980(void *) &irnet_server.s);981#endif982983DEXIT(IRDA_SERV_TRACE, " - self=0x%p\n", &irnet_server.s);984return 0;985}986987/*------------------------------------------------------------------*/988/*989* Function irda_destroy_server (self)990*991* Destroy the IrTTP server...992*993* Reverse of the previous function...994*/995static inline void996irnet_destroy_server(void)997{998DENTER(IRDA_SERV_TRACE, "()\n");9991000#ifdef ADVERTISE_HINT1001/* Unregister with IrLMP */1002irlmp_unregister_service(irnet_server.skey);1003#endif /* ADVERTISE_HINT */10041005/* Unregister with LM-IAS */1006if(irnet_server.ias_obj)1007irias_delete_object(irnet_server.ias_obj);10081009/* Cleanup the socket part */1010irda_irnet_destroy(&irnet_server.s);10111012DEXIT(IRDA_SERV_TRACE, "\n");1013}101410151016/************************ IRDA-TTP CALLBACKS ************************/1017/*1018* When we create a IrTTP instance, we pass to it a set of callbacks1019* that IrTTP will call in case of various events.1020* We take care of those events here.1021*/10221023/*------------------------------------------------------------------*/1024/*1025* Function irnet_data_indication (instance, sap, skb)1026*1027* Received some data from TinyTP. Just queue it on the receive queue1028*1029*/1030static int1031irnet_data_indication(void * instance,1032void * sap,1033struct sk_buff *skb)1034{1035irnet_socket * ap = (irnet_socket *) instance;1036unsigned char * p;1037int code = 0;10381039DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n",1040ap, skb);1041DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n");10421043/* Check is ppp is ready to receive our packet */1044if(!ap->ppp_open)1045{1046DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n");1047/* When we return error, TTP will need to requeue the skb and1048* will stop the sender. IrTTP will stall until we send it a1049* flow control request... */1050return -ENOMEM;1051}10521053/* strip address/control field if present */1054p = skb->data;1055if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI))1056{1057/* chop off address/control */1058if(skb->len < 3)1059goto err_exit;1060p = skb_pull(skb, 2);1061}10621063/* decompress protocol field if compressed */1064if(p[0] & 1)1065{1066/* protocol is compressed */1067skb_push(skb, 1)[0] = 0;1068}1069else1070if(skb->len < 2)1071goto err_exit;10721073/* pass to generic ppp layer */1074/* Note : how do I know if ppp can accept or not the packet ? This is1075* essential if I want to manage flow control smoothly... */1076ppp_input(&ap->chan, skb);10771078DEXIT(IRDA_TCB_TRACE, "\n");1079return 0;10801081err_exit:1082DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n");1083kfree_skb(skb);1084ppp_input_error(&ap->chan, code);1085return 0; /* Don't return an error code, only for flow control... */1086}10871088/*------------------------------------------------------------------*/1089/*1090* Function irnet_disconnect_indication (instance, sap, reason, skb)1091*1092* Connection has been closed. Chech reason to find out why1093*1094* Note : there are many cases where we come here :1095* o attempted to connect, timeout1096* o connected, link is broken, LAP has timeout1097* o connected, other side close the link1098* o connection request on the server not handled1099*/1100static void1101irnet_disconnect_indication(void * instance,1102void * sap,1103LM_REASON reason,1104struct sk_buff *skb)1105{1106irnet_socket * self = (irnet_socket *) instance;1107int test_open;1108int test_connect;11091110DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self);1111DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");11121113/* Don't care about it, but let's not leak it */1114if(skb)1115dev_kfree_skb(skb);11161117/* Prevent higher layer from accessing IrTTP */1118test_open = test_and_clear_bit(0, &self->ttp_open);1119/* Not connecting anymore...1120* (note : TSAP is open, so IAP callbacks are no longer pending...) */1121test_connect = test_and_clear_bit(0, &self->ttp_connect);11221123/* If both self->ttp_open and self->ttp_connect are NULL, it mean that we1124* have a race condition with irda_irnet_destroy() or1125* irnet_connect_indication(), so don't mess up tsap...1126*/1127if(!(test_open || test_connect))1128{1129DERROR(IRDA_CB_ERROR, "Race condition detected...\n");1130return;1131}11321133/* If we were active, notify the control channel */1134if(test_open)1135irnet_post_event(self, IRNET_DISCONNECT_FROM,1136self->saddr, self->daddr, self->rname, 0);1137else1138/* If we were trying to connect, notify the control channel */1139if((self->tsap) && (self != &irnet_server.s))1140irnet_post_event(self, IRNET_NOANSWER_FROM,1141self->saddr, self->daddr, self->rname, 0);11421143/* Close our IrTTP connection, cleanup tsap */1144if((self->tsap) && (self != &irnet_server.s))1145{1146DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");1147irttp_close_tsap(self->tsap);1148self->tsap = NULL;1149}1150/* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */1151self->stsap_sel = 0;1152self->daddr = DEV_ADDR_ANY;1153self->tx_flow = FLOW_START;11541155/* Deal with the ppp instance if it's still alive */1156if(self->ppp_open)1157{1158if(test_open)1159{1160/* ppp_unregister_channel() wants a user context. */1161schedule_work(&self->disconnect_work);1162}1163else1164{1165/* If we were trying to connect, flush (drain) ppp_generic1166* Tx queue (most often we have blocked it), which will1167* trigger an other attempt to connect. If we are passive,1168* this will empty the Tx queue after last try. */1169ppp_output_wakeup(&self->chan);1170}1171}11721173DEXIT(IRDA_TCB_TRACE, "\n");1174}11751176/*------------------------------------------------------------------*/1177/*1178* Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb)1179*1180* Connections has been confirmed by the remote device1181*1182*/1183static void1184irnet_connect_confirm(void * instance,1185void * sap,1186struct qos_info *qos,1187__u32 max_sdu_size,1188__u8 max_header_size,1189struct sk_buff *skb)1190{1191irnet_socket * self = (irnet_socket *) instance;11921193DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self);11941195/* Check if socket is closing down (via irda_irnet_destroy()) */1196if(! test_bit(0, &self->ttp_connect))1197{1198DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n");1199return;1200}12011202/* How much header space do we need to reserve */1203self->max_header_size = max_header_size;12041205/* IrTTP max SDU size in transmit direction */1206self->max_sdu_size_tx = max_sdu_size;1207self->max_data_size = max_sdu_size;1208#ifdef STREAM_COMPAT1209if(max_sdu_size == 0)1210self->max_data_size = irttp_get_max_seg_size(self->tsap);1211#endif /* STREAM_COMPAT */12121213/* At this point, IrLMP has assigned our source address */1214self->saddr = irttp_get_saddr(self->tsap);12151216/* Allow higher layer to access IrTTP */1217set_bit(0, &self->ttp_open);1218clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */1219/* Give a kick in the ass of ppp_generic so that he sends us some data */1220ppp_output_wakeup(&self->chan);12211222/* Check size of received packet */1223if(skb->len > 0)1224{1225#ifdef PASS_CONNECT_PACKETS1226DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");1227/* Try to pass it to PPP */1228irnet_data_indication(instance, sap, skb);1229#else /* PASS_CONNECT_PACKETS */1230DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");1231kfree_skb(skb); /* Note : will be optimised with other kfree... */1232#endif /* PASS_CONNECT_PACKETS */1233}1234else1235kfree_skb(skb);12361237/* Notify the control channel */1238irnet_post_event(self, IRNET_CONNECT_TO,1239self->saddr, self->daddr, self->rname, 0);12401241DEXIT(IRDA_TCB_TRACE, "\n");1242}12431244/*------------------------------------------------------------------*/1245/*1246* Function irnet_flow_indication (instance, sap, flow)1247*1248* Used by TinyTP to tell us if it can accept more data or not1249*1250*/1251static void1252irnet_flow_indication(void * instance,1253void * sap,1254LOCAL_FLOW flow)1255{1256irnet_socket * self = (irnet_socket *) instance;1257LOCAL_FLOW oldflow = self->tx_flow;12581259DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow);12601261/* Update our state */1262self->tx_flow = flow;12631264/* Check what IrTTP want us to do... */1265switch(flow)1266{1267case FLOW_START:1268DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n");1269/* Check if we really need to wake up PPP */1270if(oldflow == FLOW_STOP)1271ppp_output_wakeup(&self->chan);1272else1273DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n");1274break;1275case FLOW_STOP:1276DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n");1277break;1278default:1279DEBUG(IRDA_CB_INFO, "Unknown flow command!\n");1280break;1281}12821283DEXIT(IRDA_TCB_TRACE, "\n");1284}12851286/*------------------------------------------------------------------*/1287/*1288* Function irnet_status_indication (instance, sap, reason, skb)1289*1290* Link (IrLAP) status report.1291*1292*/1293static void1294irnet_status_indication(void * instance,1295LINK_STATUS link,1296LOCK_STATUS lock)1297{1298irnet_socket * self = (irnet_socket *) instance;12991300DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self);1301DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");13021303/* We can only get this event if we are connected */1304switch(link)1305{1306case STATUS_NO_ACTIVITY:1307irnet_post_event(self, IRNET_BLOCKED_LINK,1308self->saddr, self->daddr, self->rname, 0);1309break;1310default:1311DEBUG(IRDA_CB_INFO, "Unknown status...\n");1312}13131314DEXIT(IRDA_TCB_TRACE, "\n");1315}13161317/*------------------------------------------------------------------*/1318/*1319* Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata)1320*1321* Incoming connection1322*1323* In theory, this function is called only on the server socket.1324* Some other node is attempting to connect to the IrNET service, and has1325* sent a connection request on our server socket.1326* We just redirect the connection to the relevant IrNET socket.1327*1328* Note : we also make sure that between 2 irnet nodes, there can1329* exist only one irnet connection.1330*/1331static void1332irnet_connect_indication(void * instance,1333void * sap,1334struct qos_info *qos,1335__u32 max_sdu_size,1336__u8 max_header_size,1337struct sk_buff *skb)1338{1339irnet_socket * server = &irnet_server.s;1340irnet_socket * new = (irnet_socket *) NULL;13411342DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server);1343DASSERT(instance == &irnet_server, , IRDA_CB_ERROR,1344"Invalid instance (0x%p) !!!\n", instance);1345DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n");13461347/* Try to find the most appropriate IrNET socket */1348new = irnet_find_socket(server);13491350/* After all this hard work, do we have an socket ? */1351if(new == (irnet_socket *) NULL)1352{1353DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n");1354irnet_disconnect_server(server, skb);1355return;1356}13571358/* Is the socket already busy ? */1359if(test_bit(0, &new->ttp_open))1360{1361DEXIT(IRDA_CB_INFO, ": Socket already connected.\n");1362irnet_disconnect_server(server, skb);1363return;1364}13651366/* The following code is a bit tricky, so need comments ;-)1367*/1368/* If ttp_connect is set, the socket is trying to connect to the other1369* end and may have sent a IrTTP connection request and is waiting for1370* a connection response (that may never come).1371* Now, the pain is that the socket may have opened a tsap and is1372* waiting on it, while the other end is trying to connect to it on1373* another tsap.1374* Because IrNET can be peer to peer, we need to workaround this.1375* Furthermore, the way the irnetd script is implemented, the1376* target will create a second IrNET connection back to the1377* originator and expect the originator to bind this new connection1378* to the original PPPD instance.1379* And of course, if we don't use irnetd, we can have a race when1380* both side try to connect simultaneously, which could leave both1381* connections half closed (yuck).1382* Conclusions :1383* 1) The "originator" must accept the new connection and get rid1384* of the old one so that irnetd works1385* 2) One side must deny the new connection to avoid races,1386* but both side must agree on which side it is...1387* Most often, the originator is primary at the LAP layer.1388* Jean II1389*/1390/* Now, let's look at the way I wrote the test...1391* We need to clear up the ttp_connect flag atomically to prevent1392* irnet_disconnect_indication() to mess up the tsap we are going to close.1393* We want to clear the ttp_connect flag only if we close the tsap,1394* otherwise we will never close it, so we need to check for primary1395* *before* doing the test on the flag.1396* And of course, ALLOW_SIMULT_CONNECT can disable this entirely...1397* Jean II1398*/13991400/* Socket already connecting ? On primary ? */1401if(01402#ifdef ALLOW_SIMULT_CONNECT1403|| ((irttp_is_primary(server->tsap) == 1) && /* primary */1404(test_and_clear_bit(0, &new->ttp_connect)))1405#endif /* ALLOW_SIMULT_CONNECT */1406)1407{1408DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n");14091410/* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */1411if(new->tsap != NULL)1412{1413/* Close the old connection the new socket was attempting,1414* so that we can hook it up to the new connection.1415* It's now safe to do it... */1416irttp_close_tsap(new->tsap);1417new->tsap = NULL;1418}1419}1420else1421{1422/* Three options :1423* 1) socket was not connecting or connected : ttp_connect should be 0.1424* 2) we don't want to connect the socket because we are secondary or1425* ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1.1426* 3) we are half way in irnet_disconnect_indication(), and it's a1427* nice race condition... Fortunately, we can detect that by checking1428* if tsap is still alive. On the other hand, we can't be in1429* irda_irnet_destroy() otherwise we would not have found this1430* socket in the hashbin.1431* Jean II */1432if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL))1433{1434/* Don't mess this socket, somebody else in in charge... */1435DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n");1436irnet_disconnect_server(server, skb);1437return;1438}1439}14401441/* So : at this point, we have a socket, and it is idle. Good ! */1442irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);14431444/* Check size of received packet */1445if(skb->len > 0)1446{1447#ifdef PASS_CONNECT_PACKETS1448DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");1449/* Try to pass it to PPP */1450irnet_data_indication(new, new->tsap, skb);1451#else /* PASS_CONNECT_PACKETS */1452DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");1453kfree_skb(skb); /* Note : will be optimised with other kfree... */1454#endif /* PASS_CONNECT_PACKETS */1455}1456else1457kfree_skb(skb);14581459DEXIT(IRDA_TCB_TRACE, "\n");1460}146114621463/********************** IRDA-IAS/LMP CALLBACKS **********************/1464/*1465* These are the callbacks called by other layers of the IrDA stack,1466* mainly LMP for discovery and IAS for name queries.1467*/14681469/*------------------------------------------------------------------*/1470/*1471* Function irnet_getvalue_confirm (result, obj_id, value, priv)1472*1473* Got answer from remote LM-IAS, just connect1474*1475* This is the reply to a IAS query we were doing to find the TSAP of1476* the device we want to connect to.1477* If we have found a valid TSAP, just initiate the TTP connection1478* on this TSAP.1479*/1480static void1481irnet_getvalue_confirm(int result,1482__u16 obj_id,1483struct ias_value *value,1484void * priv)1485{1486irnet_socket * self = (irnet_socket *) priv;14871488DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);1489DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");14901491/* Check if already connected (via irnet_connect_socket())1492* or socket is closing down (via irda_irnet_destroy()) */1493if(! test_bit(0, &self->ttp_connect))1494{1495DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n");1496return;1497}14981499/* We probably don't need to make any more queries */1500iriap_close(self->iriap);1501self->iriap = NULL;15021503/* Post process the IAS reply */1504self->dtsap_sel = irnet_ias_to_tsap(self, result, value);15051506/* If error, just go out */1507if(self->errno)1508{1509clear_bit(0, &self->ttp_connect);1510DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno);1511return;1512}15131514DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",1515self->daddr, self->dtsap_sel);15161517/* Start up TTP - non blocking */1518irnet_connect_tsap(self);15191520DEXIT(IRDA_OCB_TRACE, "\n");1521}15221523/*------------------------------------------------------------------*/1524/*1525* Function irnet_discovervalue_confirm (result, obj_id, value, priv)1526*1527* Handle the TSAP discovery procedure state machine.1528* Got answer from remote LM-IAS, try next device1529*1530* We are doing a TSAP discovery procedure, and we got an answer to1531* a IAS query we were doing to find the TSAP on one of the address1532* in the discovery log.1533*1534* If we have found a valid TSAP for the first time, save it. If it's1535* not the first time we found one, complain.1536*1537* If we have more addresses in the log, just initiate a new query.1538* Note that those query may fail (see irnet_discover_daddr_and_lsap_sel())1539*1540* Otherwise, wrap up the procedure (cleanup), check if we have found1541* any device and connect to it.1542*/1543static void1544irnet_discovervalue_confirm(int result,1545__u16 obj_id,1546struct ias_value *value,1547void * priv)1548{1549irnet_socket * self = (irnet_socket *) priv;1550__u8 dtsap_sel; /* TSAP we are looking for */15511552DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);1553DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");15541555/* Check if already connected (via irnet_connect_socket())1556* or socket is closing down (via irda_irnet_destroy()) */1557if(! test_bit(0, &self->ttp_connect))1558{1559DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n");1560return;1561}15621563/* Post process the IAS reply */1564dtsap_sel = irnet_ias_to_tsap(self, result, value);15651566/* Have we got something ? */1567if(self->errno == 0)1568{1569/* We found the requested service */1570if(self->daddr != DEV_ADDR_ANY)1571{1572DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n");1573}1574else1575{1576/* First time we found that one, save it ! */1577self->daddr = self->discoveries[self->disco_index].daddr;1578self->dtsap_sel = dtsap_sel;1579}1580}15811582/* If no failure */1583if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0))1584{1585int ret;15861587/* Search the next node */1588ret = irnet_discover_next_daddr(self);1589if(!ret)1590{1591/* In this case, the above request was non-blocking.1592* We will return here after a while... */1593return;1594}1595/* In this case, we have processed the last discovery item */1596}15971598/* No more queries to be done (failure or last one) */15991600/* We probably don't need to make any more queries */1601iriap_close(self->iriap);1602self->iriap = NULL;16031604/* No more items : remove the log and signal termination */1605DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n",1606self->discoveries);1607if(self->discoveries != NULL)1608{1609/* Cleanup our copy of the discovery log */1610kfree(self->discoveries);1611self->discoveries = NULL;1612}1613self->disco_number = -1;16141615/* Check out what we found */1616if(self->daddr == DEV_ADDR_ANY)1617{1618self->daddr = DEV_ADDR_ANY;1619clear_bit(0, &self->ttp_connect);1620DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n");1621return;1622}16231624/* We have a valid address - just connect */16251626DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",1627self->daddr, self->dtsap_sel);16281629/* Start up TTP - non blocking */1630irnet_connect_tsap(self);16311632DEXIT(IRDA_OCB_TRACE, "\n");1633}16341635#ifdef DISCOVERY_EVENTS1636/*------------------------------------------------------------------*/1637/*1638* Function irnet_discovery_indication (discovery)1639*1640* Got a discovery indication from IrLMP, post an event1641*1642* Note : IrLMP take care of matching the hint mask for us, and also1643* check if it is a "new" node for us...1644*1645* As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET1646* nodes, so it's only at connection time that we will know if the1647* node support IrNET, IrLAN or both. The other solution is to check1648* in IAS the PNP ids and service name.1649* Note : even if a node support IrNET (or IrLAN), it's no guarantee1650* that we will be able to connect to it, the node might already be1651* busy...1652*1653* One last thing : in some case, this function will trigger duplicate1654* discovery events. On the other hand, we should catch all1655* discoveries properly (i.e. not miss one). Filtering duplicate here1656* is to messy, so we leave that to user space...1657*/1658static void1659irnet_discovery_indication(discinfo_t * discovery,1660DISCOVERY_MODE mode,1661void * priv)1662{1663irnet_socket * self = &irnet_server.s;16641665DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);1666DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,1667"Invalid instance (0x%p) !!!\n", priv);16681669DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n",1670discovery->info);16711672/* Notify the control channel */1673irnet_post_event(NULL, IRNET_DISCOVER,1674discovery->saddr, discovery->daddr, discovery->info,1675get_unaligned((__u16 *)discovery->hints));16761677DEXIT(IRDA_OCB_TRACE, "\n");1678}16791680/*------------------------------------------------------------------*/1681/*1682* Function irnet_expiry_indication (expiry)1683*1684* Got a expiry indication from IrLMP, post an event1685*1686* Note : IrLMP take care of matching the hint mask for us, we only1687* check if it is a "new" node...1688*/1689static void1690irnet_expiry_indication(discinfo_t * expiry,1691DISCOVERY_MODE mode,1692void * priv)1693{1694irnet_socket * self = &irnet_server.s;16951696DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);1697DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,1698"Invalid instance (0x%p) !!!\n", priv);16991700DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n",1701expiry->info);17021703/* Notify the control channel */1704irnet_post_event(NULL, IRNET_EXPIRE,1705expiry->saddr, expiry->daddr, expiry->info,1706get_unaligned((__u16 *)expiry->hints));17071708DEXIT(IRDA_OCB_TRACE, "\n");1709}1710#endif /* DISCOVERY_EVENTS */171117121713/*********************** PROC ENTRY CALLBACKS ***********************/1714/*1715* We create a instance in the /proc filesystem, and here we take care1716* of that...1717*/17181719#ifdef CONFIG_PROC_FS1720static int1721irnet_proc_show(struct seq_file *m, void *v)1722{1723irnet_socket * self;1724char * state;1725int i = 0;17261727/* Get the IrNET server information... */1728seq_printf(m, "IrNET server - ");1729seq_printf(m, "IrDA state: %s, ",1730(irnet_server.running ? "running" : "dead"));1731seq_printf(m, "stsap_sel: %02x, ", irnet_server.s.stsap_sel);1732seq_printf(m, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel);17331734/* Do we need to continue ? */1735if(!irnet_server.running)1736return 0;17371738/* Protect access to the instance list */1739spin_lock_bh(&irnet_server.spinlock);17401741/* Get the sockets one by one... */1742self = (irnet_socket *) hashbin_get_first(irnet_server.list);1743while(self != NULL)1744{1745/* Start printing info about the socket. */1746seq_printf(m, "\nIrNET socket %d - ", i++);17471748/* First, get the requested configuration */1749seq_printf(m, "Requested IrDA name: \"%s\", ", self->rname);1750seq_printf(m, "daddr: %08x, ", self->rdaddr);1751seq_printf(m, "saddr: %08x\n", self->rsaddr);17521753/* Second, get all the PPP info */1754seq_printf(m, " PPP state: %s",1755(self->ppp_open ? "registered" : "unregistered"));1756if(self->ppp_open)1757{1758seq_printf(m, ", unit: ppp%d",1759ppp_unit_number(&self->chan));1760seq_printf(m, ", channel: %d",1761ppp_channel_index(&self->chan));1762seq_printf(m, ", mru: %d",1763self->mru);1764/* Maybe add self->flags ? Later... */1765}17661767/* Then, get all the IrDA specific info... */1768if(self->ttp_open)1769state = "connected";1770else1771if(self->tsap != NULL)1772state = "connecting";1773else1774if(self->iriap != NULL)1775state = "searching";1776else1777if(self->ttp_connect)1778state = "weird";1779else1780state = "idle";1781seq_printf(m, "\n IrDA state: %s, ", state);1782seq_printf(m, "daddr: %08x, ", self->daddr);1783seq_printf(m, "stsap_sel: %02x, ", self->stsap_sel);1784seq_printf(m, "dtsap_sel: %02x\n", self->dtsap_sel);17851786/* Next socket, please... */1787self = (irnet_socket *) hashbin_get_next(irnet_server.list);1788}17891790/* Spin lock end */1791spin_unlock_bh(&irnet_server.spinlock);17921793return 0;1794}17951796static int irnet_proc_open(struct inode *inode, struct file *file)1797{1798return single_open(file, irnet_proc_show, NULL);1799}18001801static const struct file_operations irnet_proc_fops = {1802.owner = THIS_MODULE,1803.open = irnet_proc_open,1804.read = seq_read,1805.llseek = seq_lseek,1806.release = single_release,1807};1808#endif /* PROC_FS */180918101811/********************** CONFIGURATION/CLEANUP **********************/1812/*1813* Initialisation and teardown of the IrDA part, called at module1814* insertion and removal...1815*/18161817/*------------------------------------------------------------------*/1818/*1819* Prepare the IrNET layer for operation...1820*/1821int __init1822irda_irnet_init(void)1823{1824int err = 0;18251826DENTER(MODULE_TRACE, "()\n");18271828/* Pure paranoia - should be redundant */1829memset(&irnet_server, 0, sizeof(struct irnet_root));18301831/* Setup start of irnet instance list */1832irnet_server.list = hashbin_new(HB_NOLOCK);1833DABORT(irnet_server.list == NULL, -ENOMEM,1834MODULE_ERROR, "Can't allocate hashbin!\n");1835/* Init spinlock for instance list */1836spin_lock_init(&irnet_server.spinlock);18371838/* Initialise control channel */1839init_waitqueue_head(&irnet_events.rwait);1840irnet_events.index = 0;1841/* Init spinlock for event logging */1842spin_lock_init(&irnet_events.spinlock);18431844#ifdef CONFIG_PROC_FS1845/* Add a /proc file for irnet infos */1846proc_create("irnet", 0, proc_irda, &irnet_proc_fops);1847#endif /* CONFIG_PROC_FS */18481849/* Setup the IrNET server */1850err = irnet_setup_server();18511852if(!err)1853/* We are no longer functional... */1854irnet_server.running = 1;18551856DEXIT(MODULE_TRACE, "\n");1857return err;1858}18591860/*------------------------------------------------------------------*/1861/*1862* Cleanup at exit...1863*/1864void __exit1865irda_irnet_cleanup(void)1866{1867DENTER(MODULE_TRACE, "()\n");18681869/* We are no longer there... */1870irnet_server.running = 0;18711872#ifdef CONFIG_PROC_FS1873/* Remove our /proc file */1874remove_proc_entry("irnet", proc_irda);1875#endif /* CONFIG_PROC_FS */18761877/* Remove our IrNET server from existence */1878irnet_destroy_server();18791880/* Remove all instances of IrNET socket still present */1881hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy);18821883DEXIT(MODULE_TRACE, "\n");1884}188518861887