📄 af_irda.c
字号:
ias_value->t.string, ias_value->len); /* NULL terminate the string (avoid troubles) */ ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0'; break; case IAS_MISSING: default : return -EINVAL; } /* Copy type over */ ias_opt->irda_attrib_type = ias_value->type; return 0;}/* * Function irda_getsockopt (sock, level, optname, optval, optlen) * * * */static int irda_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){ struct sock *sk = sock->sk; struct irda_sock *self; struct irda_device_list list; struct irda_device_info *discoveries; struct irda_ias_set ias_opt; /* IAS get/query params */ struct ias_object * ias_obj; /* Object in IAS */ struct ias_attrib * ias_attr; /* Attribute in IAS object */ int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */ int val = 0; int len = 0; int err; int offset, total; self = sk->protinfo.irda; if (level != SOL_IRLMP) return -ENOPROTOOPT; if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IRLMP_ENUMDEVICES: /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&list.len, self->mask); /* Check if the we got some results */ if (discoveries == NULL) return -EAGAIN; /* Didn't find any devices */ err = 0; /* Write total list length back to client */ if (copy_to_user(optval, &list, sizeof(struct irda_device_list) - sizeof(struct irda_device_info))) err = -EFAULT; /* Offset to first device entry */ offset = sizeof(struct irda_device_list) - sizeof(struct irda_device_info); /* Copy the list itself */ total = offset + (list.len * sizeof(struct irda_device_info)); if (total > len) total = len; if (copy_to_user(optval+offset, discoveries, total - offset)) err = -EFAULT; /* Write total number of bytes used back to client */ if (put_user(total, optlen)) err = -EFAULT; /* Free up our buffer */ kfree(discoveries); if (err) return err; break; case IRLMP_MAX_SDU_SIZE: val = self->max_data_size; len = sizeof(int); if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &val, len)) return -EFAULT; break; case IRLMP_IAS_GET: /* The user want an object from our local IAS database. * We just need to query the IAS and return the value * that we found */ /* Check that the user has allocated the right space for us */ if (len != sizeof(ias_opt)) return -EINVAL; /* Copy query to the driver. */ if (copy_from_user((char *) &ias_opt, (char *)optval, len)) return -EFAULT; /* Find the object we target */ ias_obj = irias_find_object(ias_opt.irda_class_name); if(ias_obj == (struct ias_object *) NULL) return -EINVAL; /* Find the attribute (in the object) we target */ ias_attr = irias_find_attrib(ias_obj, ias_opt.irda_attrib_name); if(ias_attr == (struct ias_attrib *) NULL) return -EINVAL; /* Translate from internal to user structure */ err = irda_extract_ias_value(&ias_opt, ias_attr->value); if(err) return err; /* Copy reply to the user */ if (copy_to_user((char *)optval, (char *) &ias_opt, sizeof(ias_opt))) return -EFAULT; /* Note : don't need to put optlen, we checked it */ break; case IRLMP_IAS_QUERY: /* The user want an object from a remote IAS database. * We need to use IAP to query the remote database and * then wait for the answer to come back. */ /* Check that the user has allocated the right space for us */ if (len != sizeof(ias_opt)) return -EINVAL; /* Copy query to the driver. */ if (copy_from_user((char *) &ias_opt, (char *)optval, len)) return -EFAULT; /* At this point, there are two cases... * 1) the socket is connected - that's the easy case, we * just query the device we are connected to... * 2) the socket is not connected - the user doesn't want * to connect and/or may not have a valid service name * (so can't create a fake connection). In this case, * we assume that the user pass us a valid destination * address in the requesting structure... */ if(self->daddr != DEV_ADDR_ANY) { /* We are connected - reuse known daddr */ daddr = self->daddr; } else { /* We are not connected, we must specify a valid * destination address */ daddr = ias_opt.daddr; if((!daddr) || (daddr == DEV_ADDR_ANY)) return -EINVAL; } /* Check that we can proceed with IAP */ if (self->iriap) { WARNING(__FUNCTION__ "(), busy with a previous query\n"); return -EBUSY; } self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, irda_getvalue_confirm); /* Treat unexpected signals as disconnect */ self->errno = -EHOSTUNREACH; /* Query remote LM-IAS */ iriap_getvaluebyclass_request(self->iriap, self->saddr, daddr, ias_opt.irda_class_name, ias_opt.irda_attrib_name); /* Wait for answer (if not already failed) */ if(self->iriap != NULL) interruptible_sleep_on(&self->query_wait); /* Check what happened */ if (self->errno) { /* Requested object/attribute doesn't exist */ if((self->errno == IAS_CLASS_UNKNOWN) || (self->errno == IAS_ATTRIB_UNKNOWN)) return (-EADDRNOTAVAIL); else return (-EHOSTUNREACH); } /* Translate from internal to user structure */ err = irda_extract_ias_value(&ias_opt, self->ias_result); if (self->ias_result) irias_delete_value(self->ias_result); if (err) return err; /* Copy reply to the user */ if (copy_to_user((char *)optval, (char *) &ias_opt, sizeof(ias_opt))) return -EFAULT; /* Note : don't need to put optlen, we checked it */ break; case IRLMP_WAITDEVICE: /* This function is just another way of seeing life ;-) * IRLMP_ENUMDEVICES assumes that you have a static network, * and that you just want to pick one of the devices present. * On the other hand, in here we assume that no device is * present and that at some point in the future a device will * come into range. When this device arrive, we just wake * up the caller, so that he has time to connect to it before * the device goes away... * Note : once the node has been discovered for more than a * few second, it won't trigger this function, unless it * goes away and come back changes its hint bits (so we * might call it IRLMP_WAITNEWDEVICE). */ /* Check that the user is passing us an int */ if (len != sizeof(int)) return -EINVAL; /* Get timeout in ms (max time we block the caller) */ if (get_user(val, (int *)optval)) return -EFAULT; /* Tell IrLMP we want to be notified */ irlmp_update_client(self->ckey, self->mask, irda_selective_discovery_indication, NULL, (void *) self); /* Do some discovery (and also return cached results) */ irlmp_discovery_request(self->nslots); /* Wait until a node is discovered */ if (!self->cachediscovery) { IRDA_DEBUG(1, __FUNCTION__ "(), nothing discovered yet, going to sleep...\n"); /* Set watchdog timer to expire in <val> ms. */ self->watchdog.function = irda_discovery_timeout; self->watchdog.data = (unsigned long) self; self->watchdog.expires = jiffies + (val * HZ/1000); add_timer(&(self->watchdog)); /* Wait for IR-LMP to call us back */ interruptible_sleep_on(&self->query_wait); /* If watchdog is still activated, kill it! */ if(timer_pending(&(self->watchdog))) del_timer(&(self->watchdog)); IRDA_DEBUG(1, __FUNCTION__ "(), ...waking up !\n"); } else IRDA_DEBUG(1, __FUNCTION__ "(), found immediately !\n"); /* Tell IrLMP that we have been notified */ irlmp_update_client(self->ckey, self->mask, NULL, NULL, NULL); /* Check if the we got some results */ if (!self->cachediscovery) return -EAGAIN; /* Didn't find any devices */ /* Cleanup */ self->cachediscovery = NULL; /* Note : We don't return anything to the user. * We could return the device that triggered the wake up, * but it's probably better to force the user to query * the whole discovery log and let him pick one device... */ break; default: return -ENOPROTOOPT; } return 0;}static struct net_proto_family irda_family_ops ={ PF_IRDA, irda_create};static struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = { family: PF_IRDA, release: irda_release, bind: irda_bind, connect: irda_connect, socketpair: sock_no_socketpair, accept: irda_accept, getname: irda_getname, poll: irda_poll, ioctl: irda_ioctl, listen: irda_listen, shutdown: irda_shutdown, setsockopt: irda_setsockopt, getsockopt: irda_getsockopt, sendmsg: irda_sendmsg, recvmsg: irda_recvmsg_stream, mmap: sock_no_mmap,};static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = { family: PF_IRDA, release: irda_release, bind: irda_bind, connect: irda_connect, socketpair: sock_no_socketpair, accept: irda_accept, getname: irda_getname, poll: datagram_poll, ioctl: irda_ioctl, listen: irda_listen, shutdown: irda_shutdown, setsockopt: irda_setsockopt, getsockopt: irda_getsockopt, sendmsg: irda_sendmsg, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap,};static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { family: PF_IRDA, release: irda_release, bind: irda_bind, connect: irda_connect, socketpair: sock_no_socketpair, accept: irda_accept, getname: irda_getname, poll: datagram_poll, ioctl: irda_ioctl, listen: irda_listen, shutdown: irda_shutdown, setsockopt: irda_setsockopt, getsockopt: irda_getsockopt, sendmsg: irda_sendmsg_dgram, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap,};#ifdef CONFIG_IRDA_ULTRAstatic struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = { family: PF_IRDA, release: irda_release, bind: irda_bind, connect: sock_no_connect, socketpair: sock_no_socketpair, accept: sock_no_accept, getname: irda_getname, poll: datagram_poll, ioctl: irda_ioctl, listen: sock_no_listen, shutdown: irda_shutdown, setsockopt: irda_setsockopt, getsockopt: irda_getsockopt, sendmsg: irda_sendmsg_ultra, recvmsg: irda_recvmsg_dgram, mmap: sock_no_mmap,};#endif /* CONFIG_IRDA_ULTRA */#include <linux/smp_lock.h>SOCKOPS_WRAP(irda_stream, PF_IRDA);SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);SOCKOPS_WRAP(irda_dgram, PF_IRDA);/* * Function irda_device_event (this, event, ptr) * * Called when a device is taken up or down * */static int irda_device_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = (struct net_device *) ptr; /* Reject non IrDA devices */ if (dev->type != ARPHRD_IRDA) return NOTIFY_DONE; switch (event) { case NETDEV_UP: IRDA_DEBUG(3, __FUNCTION__ "(), NETDEV_UP\n"); /* irda_dev_device_up(dev); */ break; case NETDEV_DOWN: IRDA_DEBUG(3, __FUNCTION__ "(), NETDEV_DOWN\n"); /* irda_kill_by_device(dev); */ /* irda_rt_device_down(dev); */ /* irda_dev_device_down(dev); */ break; default: break; } return NOTIFY_DONE;}static struct packet_type irda_packet_type = { 0, /* MUTTER ntohs(ETH_P_IRDA),*/ NULL, irlap_driver_rcv, NULL, NULL,};static struct notifier_block irda_dev_notifier = { irda_device_event, NULL, 0};/* * Function irda_proc_modcount (inode, fill) * * Use by the proc file system functions to prevent the irda module * being removed while the use is standing in the net/irda directory */void irda_proc_modcount(struct inode *inode, int fill){#ifdef MODULE#ifdef CONFIG_PROC_FS if (fill) MOD_INC_USE_COUNT; else MOD_DEC_USE_COUNT;#endif /* CONFIG_PROC_FS */#endif /* MODULE */}/* * Function irda_proto_init (pro) * * Initialize IrDA protocol layer * */int __init irda_proto_init(void){ sock_register(&irda_family_ops); irda_packet_type.type = htons(ETH_P_IRDA); dev_add_pack(&irda_packet_type); register_netdevice_notifier(&irda_dev_notifier); irda_init();#ifdef MODULE irda_device_init(); /* Called by init/main.c when non-modular */#endif return 0;}/* * Function irda_proto_cleanup (void) * * Remove IrDA protocol layer * */#ifdef MODULEvoid irda_proto_cleanup(void){ irda_packet_type.type = htons(ETH_P_IRDA); dev_remove_pack(&irda_packet_type); unregister_netdevice_notifier(&irda_dev_notifier); sock_unregister(PF_IRDA); irda_cleanup(); return;}module_init(irda_proto_init);module_exit(irda_proto_cleanup); MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); MODULE_PARM(irda_debug, "1l");#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -