📄 af_irda.c
字号:
* of the failure. Most of them are visible in the function, others may come* from subroutines called and are listed here :* o EBUSY : already processing a connect* o EHOSTUNREACH : bad addr->sir_addr argument* o EADDRNOTAVAIL : bad addr->sir_name argument* o ENOTUNIQ : more than one node has addr->sir_name (auto-connect)* o ENETUNREACH : no node found on the network (auto-connect)*/int iriap_connect( struct addr_irda *addr){ struct irda_cb *self = irda_self; IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); /* Check if user supplied any destination device address */ if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) { /* Try to find one suitable */ IRDA_ERROR("NO ADDR %s()\n", __FUNCTION__); } else { /* Use the one provided by the user */ self->daddr = addr->sir_addr; IRDA_DEBUG(1, "%s(), daddr = %08x\n", __FUNCTION__, self->daddr); /* If we don't have a valid service name, we assume the * user want to connect on a specific LSAP. Prevent * the use of invalid LSAPs (IrLMP 1.1 p10). Jean II */ if((addr->sir_name[0] != '\0') || (addr->sir_lsap_sel >= 0x70)) { /* Query remote LM-IAS using service name */ irda_find_lsap_sel(self, addr->sir_name); } else { /* Directly connect to the remote LSAP * specified by the sir_lsap field. * Please use with caution, in IrDA LSAPs are * dynamic and there is no "well-known" LSAP. */ self->dtsap_sel = addr->sir_lsap_sel; } } return 0; }int irda_ttp_connect(struct addr_irda *addr){ struct irda_cb *self = irda_self; int err; /* Check if we have opened a local TSAP */ if (!self->tsap) irda_open_tsap(self, LSAP_ANY, addr->sir_name); /* Connect to remote device */ err = irttp_connect_request(self->tsap, self->dtsap_sel, self->saddr, self->daddr, NULL, self->max_sdu_size_rx, NULL); if (err) { IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__); return err; } self->saddr = irttp_get_saddr(self->tsap); return 0;}/** Function irda_create (sock, protocol)** Create IrDA socket**/int irda_create(void){ struct irda_cb *self; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* Allocate networking socket */ irda_self = (struct irda_cb*)malloc(sizeof(struct irda_cb)); if (irda_self == NULL) { IRDA_ERROR("%s() can not allocate memory\n",__FUNCTION__); return -ENOMEM; } memset(irda_self,0,sizeof(struct irda_cb)); self = irda_self; IRDA_DEBUG(2, "%s() : self is %p\n", __FUNCTION__, self); self->max_sdu_size_rx = TTP_SAR_DISABLE; /* Register as a client with IrLMP */ self->ckey = irlmp_register_client(0, NULL, NULL, NULL); self->mask.word = 0xffff; self->rx_flow = self->tx_flow = FLOW_START; self->nslots = DISCOVERY_DEFAULT_SLOTS; self->daddr = DEV_ADDR_ANY; /* Until we get connected */ self->saddr = 0x0; /* so IrLMP assign us any link */ return 0;}/** Function irda_destroy_socket (self)** Destroy socket**/static void irda_destroy(struct irda_cb *self){ IRDA_DEBUG(4, "%s(%p)\n", __FUNCTION__, self); /* Unregister with IrLMP */ irlmp_unregister_client(self->ckey); irlmp_unregister_service(self->skey); pthread_mutex_destroy(&obex_rec_mutex); pthread_cond_destroy(&obex_rec_cond); /* Unregister with LM-IAS */ if (self->ias_obj) { irias_delete_object(self->ias_obj); self->ias_obj = NULL; } if (self->iriap) { iriap_close(self->iriap); self->iriap = NULL; } if (self->tsap) { irttp_disconnect_request(self->tsap, NULL, P_NORMAL); irttp_close_tsap(self->tsap); self->tsap = NULL; } }/** Function irda_release (sock)*/int irda_release(void){ struct irda_cb *self = irda_self; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); if (self == NULL) return 0; /* Destroy IrDA socket */ irda_destroy(self); /* Purge queues (see sock_init_data()) */ skb_queue_purge(); if (self != NULL) { free(self); } /* Destroy networking socket if we are the last reference on it, * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */ /* Notes on socket locking and deallocation... - Jean II * In theory we should put pairs of sock_hold() / sock_put() to * prevent the socket to be destroyed whenever there is an * outstanding request or outstanding incoming packet or event. * * 1) This may include IAS request, both in connect and getsockopt. * Unfortunately, the situation is a bit more messy than it looks, * because we close iriap and kfree(self) above. * * 2) This may include selective discovery in getsockopt. * Same stuff as above, irlmp registration and self are gone. * * Probably 1 and 2 may not matter, because it's all triggered * by a process and the socket layer already prevent the * socket to go away while a process is holding it, through * sockfd_put() and fput()... * * 3) This may include deferred TSAP closure. In particular, * we may receive a late irda_disconnect_indication() * Fortunately, (tsap_cb *)->close_pend should protect us * from that. * * I did some testing on SMP, and it looks solid. And the socket * memory leak is now gone... - Jean II */ return 0;}/** Function irda_sendmsg (iocb, sock, msg, len)** Send message down to TinyTP. This function is used for both STREAM and* SEQPACK services. This is possible since it forces the client to* fragment the message if necessary*/int irda_sendmsg(char *obex_msg, size_t len){ struct irda_cb *self = irda_self; struct sk_buff *skb; int err; IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len); /* Check if IrTTP is wants us to slow down */ /* Check that we don't send out too big frames */ if (len > self->max_data_size) { IRDA_DEBUG(4, "%s(), Chopping frame from %zd to %d bytes!\n", __FUNCTION__, len, self->max_data_size); len = self->max_data_size; } skb = skb_alloc(self->max_header_size + 16+len); if (!skb) return -ENOBUFS; skb_reserve(skb, self->max_header_size + 16); skb_reset_transport_header(skb); skb_put(skb, len); memcpy(skb->data,(unsigned char*)obex_msg,len); /* * Just send the message to TinyTP, and let it deal with possible * errors. No need to duplicate all that here */ err = irttp_data_request(self->tsap, skb); if (err) { IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); return err; } /* Tell client how much data we actually sent */ return len;}/** Function irda_recvmsg_stream (iocb, sock, msg, size, flags)*/int irda_recvmsg_stream(char *obex_msg, size_t size){ struct irda_cb *self = irda_self; struct sk_buff* sk_peek; size_t copied = 0; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); do { int chunk; while(1) { sk_peek = skb_peek(&self->sk_receive_queue); if (sk_peek == NULL) { pthread_mutex_lock(&obex_rec_mutex); pthread_cond_wait(&obex_rec_cond,&obex_rec_mutex); pthread_mutex_unlock(&obex_rec_mutex); } else { break; } } struct sk_buff *skb = skb_dequeue(&self->sk_receive_queue); if (skb == NULL) { return 0; } chunk = skb->len> size?size:skb->len; memcpy(obex_msg+copied, skb->data, chunk); copied += chunk; size -= chunk; if (chunk < skb->len) { skb_pull(skb, chunk); /* put the skb back if we didn't use it up.. */ if (skb->len) { IRDA_DEBUG(1, "%s(), back on q!\n", __FUNCTION__); skb_queue_head(&self->sk_receive_queue, skb); break; } } else { kfree_skb(skb); } } while (size); return copied;}/** Function irda_shutdown (sk, how)*/int irda_shutdown( int how){ struct irda_cb *self = irda_self; IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self); if (self->iriap) { iriap_close(self->iriap); self->iriap = NULL; } if (self->tsap) { irttp_disconnect_request(self->tsap, NULL, P_NORMAL); irttp_close_tsap(self->tsap); self->tsap = NULL; } self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ self->saddr = 0x0; /* so IrLMP assign us any link */ return 0;}/** Function irda_setsockopt (sock, level, optname, optval, optlen)** Set some options for the socket**/int irda_setopt( int level, int optname, char *optval, int optlen){ struct irda_cb *self = irda_self; int opt=0; IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); if (level != SOL_IRLMP) return -ENOPROTOOPT; switch (optname) { case IRLMP_HINTS_SET: if (optlen < sizeof(int)) return -EINVAL; /* Unregister any old registration */ if (self->skey) irlmp_unregister_service(self->skey); self->skey = irlmp_register_service(*((__u16*) optval)); break; case IRLMP_HINT_MASK_SET: /* As opposed to the previous case which set the hint bits * that we advertise, this one set the filter we use when * making a discovery (nodes which don't match any hint * bit in the mask are not reported). */ if (optlen < sizeof(int)) return -EINVAL; self->mask.word = *((__u16*)optval); /* Mask out extension bits */ self->mask.word &= 0x7f7f; /* Check if no bits */ if(!self->mask.word) self->mask.word = 0xFFFF; break; default: return -EINVAL; } return 0;}/** Function irda_getsockopt (sock, level, optname, optval, optlen)*/int irda_getopt( int optname, void *optval, int *len){ struct irda_cb *self; struct irda_device_list list; struct irda_device_info *discoveries; int val = 0; int err = 0; int offset, total; self = irda_self; IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self); switch (optname) { case IRLMP_ENUMDEVICES: /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&list.len, self->mask.word, self->nslots); /* Check if the we got some results */ if (discoveries == NULL) { return -EAGAIN; } /* Didn't find any devices */ if (list.len > 2048) { err = -EINVAL; goto bed; } *((__u32*)(optval)) = list.len; offset = sizeof(struct irda_device_list) - sizeof(struct irda_device_info); total = offset + (list.len * sizeof(struct irda_device_info)); if (total > len) { total = len; } memcpy(optval+offset,discoveries,total-offset); *len = total;bed: free(discoveries); if (err) { return err; } break; case IRLMP_MAX_SDU_SIZE: *((int*)optval )= self->max_data_size; *len = sizeof(int); break; default: return -ENOPROTOOPT; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -