📄 irnet_irda.c
字号:
/* How much header space do we need to reserve */ self->max_header_size = max_header_size; /* IrTTP max SDU size in transmit direction */ self->max_sdu_size_tx = max_sdu_size; self->max_data_size = max_sdu_size;#ifdef STREAM_COMPAT if(max_sdu_size == 0) self->max_data_size = irttp_get_max_seg_size(self->tsap);#endif STREAM_COMPAT /* At this point, IrLMP has assigned our source address */ self->saddr = irttp_get_saddr(self->tsap); /* Allow higher layer to access IrTTP */ self->ttp_open = 1; /* Give a kick in the ass of ppp_generic so that he sends us some data */ ppp_output_wakeup(&self->chan); /* 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(instance, sap, 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); /* Notify the control channel */ irnet_post_event(self, IRNET_CONNECT_TO, self->daddr, self->rname); DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_flow_indication (instance, sap, flow) * * Used by TinyTP to tell us if it can accept more data or not * */static voidirnet_flow_indication(void * instance, void * sap, LOCAL_FLOW flow) { irnet_socket * self = (irnet_socket *) instance; DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow); /* Update our state */ self->tx_flow = flow; /* Check what IrTTP want us to do... */ switch(flow) { case FLOW_START: DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); ppp_output_wakeup(&self->chan); break; case FLOW_STOP: DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); break; default: DEBUG(IRDA_CB_INFO, "Unknown flow command!\n"); break; } DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_status_indication (instance, sap, reason, skb) * * Link (IrLAP) status report. * */static voidirnet_status_indication(void * instance, LINK_STATUS link, LOCK_STATUS lock){ irnet_socket * self = (irnet_socket *) instance; DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); /* We can only get this event if we are connected */ switch(link) { case STATUS_NO_ACTIVITY: irnet_post_event(self, IRNET_BLOCKED_LINK, self->daddr, self->rname); break; default: DEBUG(IRDA_CB_INFO, "Unknown status...\n"); } DEXIT(IRDA_TCB_TRACE, "\n");}/*------------------------------------------------------------------*//* * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) * * Incomming connection * * In theory, this function is called only on the server socket. * Some other node is attempting to connect to the IrNET service, and has * sent a connection request on our server socket. * We just redirect the connection to the relevant IrNET socket. * * Note : we also make sure that between 2 irnet nodes, there can * exist only one irnet connection. */static voidirnet_connect_indication(void * instance, void * sap, struct qos_info *qos, __u32 max_sdu_size, __u8 max_header_size, struct sk_buff *skb){ irnet_socket * self = &irnet_server.s; irnet_socket * new = (irnet_socket *) NULL; DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, "Invalid instance (0x%X) !!!\n", (unsigned int) instance); DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); /* Try to find the most appropriate IrNET socket */ new = irnet_find_socket(self); /* After all this hard work, do we have an socket ? */ if(new == (irnet_socket *) NULL) { DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n"); irnet_disconnect_server(self, skb); return; } /* Is the socket already busy ? */ if(new->ttp_open) { DEXIT(IRDA_CB_INFO, ": Socket already connected.\n"); irnet_disconnect_server(self, skb); return; } /* Socket connecting */ if(new->tsap != NULL) { /* The socket has sent a IrTTP connection request and is waiting for * a connection response (that may never come). * Now, the pain is that the socket has open a tsap and is waiting on it, * while the other end is trying to connect to it on another tsap. * Argh ! We will deal with that later... */ DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");#ifdef ALLOW_SIMULT_CONNECT /* Close the connection the new socket was attempting. * WARNING : This need more testing ! */ irttp_close_tsap(new->tsap); /* Note : no return, fall through... */#else ALLOW_SIMULT_CONNECT irnet_disconnect_server(self, skb); return;#endif ALLOW_SIMULT_CONNECT } /* So : at this point, we have a socket, and it is idle. Good ! */ irnet_connect_socket(self, 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 (obj_id, value, priv) * * Got answer from remote LM-IAS, just pass object to requester... * */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_CB_ERROR, "Self is NULL !!!\n"); /* 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) { DEBUG(IRDA_CB_INFO, "IAS query failed! (%d)\n", result); self->errno = result; /* We really need it later */ } else { /* 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->query_wait); 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, void * priv){ irnet_socket * self = &irnet_server.s; DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(priv == &irnet_server, , IRDA_CB_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_CB_INFO, "Discovered new IrNET/IrLAN node %s...\n", discovery->nickname); /* Notify the control channel */ irnet_post_event(NULL, IRNET_DISCOVER, 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, void * priv){ irnet_socket * self = &irnet_server.s; DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(priv == &irnet_server, , IRDA_CB_ERROR, "Invalid instance (0x%X) !!!\n", (unsigned int) priv); DEBUG(IRDA_CB_INFO, "IrNET/IrLAN node %s expired...\n", expiry->nickname); /* Notify the control channel */ irnet_post_event(NULL, IRNET_EXPIRE, 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, "addr: %08x\n", self->raddr); /* 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 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_LOCAL); 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 + -