📄 irlmp.c
字号:
IRDA_DEBUG(3, "%s()\n", __FUNCTION__); IRDA_ASSERT(log != NULL, return;); if (!(HASHBIN_GET_SIZE(log))) return; /* For each client - notify callback may touch client list */ client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, (void *) &client_next) ) { /* Check if we should notify client */ irlmp_notify_client(client, log, mode); client = client_next; }}/* * Function irlmp_discovery_expiry (expiry) * * This device is no longer been discovered, and therefore it is being * purged from the discovery log. Inform all clients who have * registered for this event... * * Note : called exclusively from discovery.c * Note : this is no longer called under discovery spinlock, so the * client can do whatever he wants in the callback. */void irlmp_discovery_expiry(discinfo_t *expiries, int number){ irlmp_client_t *client; irlmp_client_t *client_next; int i; IRDA_DEBUG(3, "%s()\n", __FUNCTION__); IRDA_ASSERT(expiries != NULL, return;); /* For each client - notify callback may touch client list */ client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, (void *) &client_next) ) { /* Pass all entries to the listener */ for(i = 0; i < number; i++) { /* Check if we should notify client */ if ((client->expir_callback) && (client->hint_mask.word & u16ho(expiries[i].hints) & 0x7f7f) ) client->expir_callback(&(expiries[i]), EXPIRY_TIMEOUT, client->priv); } /* Next client */ client = client_next; }}/* * Function irlmp_get_discovery_response () * * Used by IrLAP to get the discovery info it needs when answering * discovery requests by other devices. */discovery_t *irlmp_get_discovery_response(void){ IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(irlmp != NULL, return NULL;); u16ho(irlmp->discovery_rsp.data.hints) = irlmp->hints.word; /* * Set character set for device name (we use ASCII), and * copy device name. Remember to make room for a \0 at the * end */ irlmp->discovery_rsp.data.charset = CS_ASCII; strncpy(irlmp->discovery_rsp.data.info, sysctl_devname, NICKNAME_MAX_LEN); irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info); return &irlmp->discovery_rsp;}/* * Function irlmp_data_request (self, skb) * * Send some data to peer device * * Note on skb management : * After calling the lower layers of the IrDA stack, we always * kfree() the skb, which drop the reference count (and potentially * destroy it). * IrLMP and IrLAP may queue the packet, and in those cases will need * to use skb_get() to keep it around. * Jean II */int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata){ int ret; IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); /* Make room for MUX header */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); skb_push(userdata, LMP_HEADER); ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(userdata); return ret;}EXPORT_SYMBOL(irlmp_data_request);/* * Function irlmp_data_indication (handle, skb) * * Got data from LAP layer so pass it up to upper layer * */void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb){ /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); if (self->notify.data_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.data_indication(self->notify.instance, self, skb); }}/* * Function irlmp_udata_request (self, skb) */int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata){ int ret; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(userdata != NULL, return -1;); /* Make room for MUX header */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); skb_push(userdata, LMP_HEADER); ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(userdata); return ret;}/* * Function irlmp_udata_indication (self, skb) * * Send unreliable data (but still within the connection) * */void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb){ IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); if (self->notify.udata_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.udata_indication(self->notify.instance, self, skb); }}/* * Function irlmp_connless_data_request (self, skb) */#ifdef CONFIG_IRDA_ULTRAint irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata, __u8 pid){ struct sk_buff *clone_skb; struct lap_cb *lap; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(userdata != NULL, return -1;); /* Make room for MUX and PID header */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER, return -1;); /* Insert protocol identifier */ skb_push(userdata, LMP_PID_HEADER); if(self != NULL) userdata->data[0] = self->pid; else userdata->data[0] = pid; /* Connectionless sockets must use 0x70 */ skb_push(userdata, LMP_HEADER); userdata->data[0] = userdata->data[1] = LSAP_CONNLESS; /* Try to send Connectionless packets out on all links */ lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;); clone_skb = skb_clone(userdata, GFP_ATOMIC); if (!clone_skb) { dev_kfree_skb(userdata); return -ENOMEM; } irlap_unitdata_request(lap->irlap, clone_skb); /* irlap_unitdata_request() don't increase refcount, * so no dev_kfree_skb() - Jean II */ lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } dev_kfree_skb(userdata); return 0;}#endif /* CONFIG_IRDA_ULTRA *//* * Function irlmp_connless_data_indication (self, skb) * * Receive unreliable data outside any connection. Mostly used by Ultra * */#ifdef CONFIG_IRDA_ULTRAvoid irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb){ IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); /* Hide LMP and PID header from layer above */ skb_pull(skb, LMP_HEADER+LMP_PID_HEADER); if (self->notify.udata_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.udata_indication(self->notify.instance, self, skb); }}#endif /* CONFIG_IRDA_ULTRA *//* * Propagate status indication from LAP to LSAPs (via LMP) * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb, * and the event is stateless, therefore we can bypass both state machines * and send the event direct to the LSAP user. * Jean II */void irlmp_status_indication(struct lap_cb *self, LINK_STATUS link, LOCK_STATUS lock){ struct lsap_cb *next; struct lsap_cb *curr; /* Send status_indication to all LSAPs using this link */ curr = (struct lsap_cb *) hashbin_get_first( self->lsaps); while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL, (void *) &next) ) { IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;); /* * Inform service user if he has requested it */ if (curr->notify.status_indication != NULL) curr->notify.status_indication(curr->notify.instance, link, lock); else IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__); curr = next; }}/* * Receive flow control indication from LAP. * LAP want us to send it one more frame. We implement a simple round * robin scheduler between the active sockets so that we get a bit of * fairness. Note that the round robin is far from perfect, but it's * better than nothing. * We then poll the selected socket so that we can do synchronous * refilling of IrLAP (which allow to minimise the number of buffers). * Jean II */void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow){ struct lsap_cb *next; struct lsap_cb *curr; int lsap_todo; IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); IRDA_ASSERT(flow == FLOW_START, return;); /* Get the number of lsap. That's the only safe way to know * that we have looped around... - Jean II */ lsap_todo = HASHBIN_GET_SIZE(self->lsaps); IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __FUNCTION__, lsap_todo); /* Poll lsap in order until the queue is full or until we * tried them all. * Most often, the current LSAP will have something to send, * so we will go through this loop only once. - Jean II */ while((lsap_todo--) && (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) { /* Try to find the next lsap we should poll. */ next = self->flow_next; /* If we have no lsap, restart from first one */ if(next == NULL) next = (struct lsap_cb *) hashbin_get_first(self->lsaps); /* Verify current one and find the next one */ curr = hashbin_find_next(self->lsaps, (long) next, NULL, (void *) &self->flow_next); /* Uh-oh... Paranoia */ if(curr == NULL) break; IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __FUNCTION__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); /* Inform lsap user that it can send one more packet. */ if (curr->notify.flow_indication != NULL) curr->notify.flow_indication(curr->notify.instance, curr, flow); else IRDA_DEBUG(1, "%s(), no handler\n", __FUNCTION__); }}#if 0/* * Function irlmp_hint_to_service (hint) * * Returns a list of all servics contained in the given hint bits. This * function assumes that the hint bits have the size of two bytes only */__u8 *irlmp_hint_to_service(__u8 *hint){ __u8 *service; int i = 0; /* * Allocate array to store services in. 16 entries should be safe * since we currently only support 2 hint bytes */ service = kmalloc(16, GFP_ATOMIC); if (!service) { IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); return NULL; } if (!hint[0]) { IRDA_DEBUG(1, "<None>\n"); kfree(service); return NULL; } if (hint[0] & HINT_PNP) IRDA_DEBUG(1, "PnP Compatible "); if (hint[0] & HINT_PDA) IRDA_DEBUG(1, "PDA/Palmtop "); if (hint[0] & HINT_COMPUTER) IRDA_DEBUG(1, "Computer "); if (hint[0] & HINT_PRINTER) { IRDA_DEBUG(1, "Printer "); service[i++] = S_PRINTER; } if (hint[0] & HINT_MODEM) IRDA_DEBUG(1, "Modem "); if (hint[0] & HINT_FAX) IRDA_DEBUG(1, "Fax "); if (hint[0] & HINT_LAN) { IRDA_DEBUG(1, "LAN Access "); service[i++] = S_LAN; } /* * Test if extension byte exists. This byte will usually be * there, but this is not really required by the standard. * (IrLMP p. 29) */ if (hint[0] & HINT_EXTENSION) { if (hint[1] & HINT_TELEPHONY) { IRDA_DEBUG(1, "Telephony "); service[i++] = S_TELEPHONY; } if (hint[1] & HINT_FILE_SERVER) IRDA_DEBUG(1, "File Server "); if (hint[1] & HINT_COMM) { IRDA_DEBUG(1, "IrCOMM "); service[i++] = S_COMM; } if (hint[1] & HINT_OBEX) { IRDA_DEBUG(1, "IrOBEX "); service[i++] = S_OBEX; } } IRDA_DEBUG(1, "\n"); /* So that client can be notified about any discovery */ service[i++] = S_ANY; service[i] = S_END; return service;}#endifstatic const __u16 service_hint_mapping[S_END][2] = { { HINT_PNP, 0 }, /* S_PNP */ { HINT_PDA, 0 }, /* S_PDA */ { HINT_COMPUTER, 0 }, /* S_COMPUTER */ { HINT_PRINTER, 0 }, /* S_PRINTER */ { HINT_MODEM, 0 }, /* S_MODEM */ { HINT_FAX, 0 }, /* S_FAX */ { HINT_LAN, 0 }, /* S_LAN */ { HINT_EXTENSION, HINT_TELEPHONY }, /* S_TELEPHONY */ { HINT_EXTENSION, HINT_COMM }, /* S_COMM */ { HINT_EXTENSION, HINT_OBEX }, /* S_OBEX */ { 0xFF, 0xFF }, /* S_ANY */};/* * Function irlmp_service_to_hint (service) * * Converts a service type, to a hint bit * * Returns: a 16 bit hint value, with the service bit set */__u16 irlmp_service_to_hint(int service){ __u16_host_order hint; hint.byte[0] = service_hint_mapping[service][0]; hint.byte[1] = service_hint_mapping[service][1]; return hint.word;}EXPORT_SYMBOL(irlmp_service_to_hint);/* * Function irlmp_register_service (service) * * Register local service with IrLMP * */void *irlmp_register_service(__u16 hints){ irlmp_service_t *service; IRDA_DEBUG(4, "%s(), hints = %04x\n", __FUNCTION__, hints); /* Make a new registration */ service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); if (!service) { IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); return NULL; } service->hints.word = hints; hashbin_insert(irlmp->services, (irda_queue_t *) service, (long) service, NULL); irlmp->hints.word |= hints; return (void *)service;}EXPORT_SYMBOL(irlmp_register_service);/* * Function irlmp_unregister_service (handle) * * Unregister service with IrLMP. * * Returns: 0 on success, -1 on error */int irlmp_unregister_service(void *handle){ irlmp_service_t *service; unsigned long flags; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); if (!handle) return -1; /* Caller may call with invalid handle (it's legal) - Jean II */ service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -