📄 af_irda.c
字号:
}/* * Function irda_sendmsg_dgram (iocb, sock, msg, len) * * Send message down to TinyTP for the unreliable sequenced * packet service... * */static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len){ struct sock *sk = sock->sk; struct irda_sock *self; struct sk_buff *skb; int err; IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len); if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) return -EINVAL; if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; self = irda_sk(sk); /* * Check that we don't send out too big frames. This is an unreliable * service, so we have no fragmentation and no coalescence */ if (len > self->max_data_size) { IRDA_DEBUG(0, "%s(), Warning to much data! " "Chopping frame from %zd to %d bytes!\n", __FUNCTION__, len, self->max_data_size); len = self->max_data_size; } skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; skb_reserve(skb, self->max_header_size); skb_reset_transport_header(skb); IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__); skb_put(skb, len); err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { kfree_skb(skb); return err; } /* * Just send the message to TinyTP, and let it deal with possible * errors. No need to duplicate all that here */ err = irttp_udata_request(self->tsap, skb); if (err) { IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); return err; } return len;}/* * Function irda_sendmsg_ultra (iocb, sock, msg, len) * * Send message down to IrLMP for the unreliable Ultra * packet service... */#ifdef CONFIG_IRDA_ULTRAstatic int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len){ struct sock *sk = sock->sk; struct irda_sock *self; __u8 pid = 0; int bound = 0; struct sk_buff *skb; int err; IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len); if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) return -EINVAL; if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } self = irda_sk(sk); /* Check if an address was specified with sendto. Jean II */ if (msg->msg_name) { struct sockaddr_irda *addr = (struct sockaddr_irda *) msg->msg_name; /* Check address, extract pid. Jean II */ if (msg->msg_namelen < sizeof(*addr)) return -EINVAL; if (addr->sir_family != AF_IRDA) return -EINVAL; pid = addr->sir_lsap_sel; if (pid & 0x80) { IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__); return -EOPNOTSUPP; } } else { /* Check that the socket is properly bound to an Ultra * port. Jean II */ if ((self->lsap == NULL) || (sk->sk_state != TCP_ESTABLISHED)) { IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n", __FUNCTION__); return -ENOTCONN; } /* Use PID from socket */ bound = 1; } /* * Check that we don't send out too big frames. This is an unreliable * service, so we have no fragmentation and no coalescence */ if (len > self->max_data_size) { IRDA_DEBUG(0, "%s(), Warning to much data! " "Chopping frame from %zd to %d bytes!\n", __FUNCTION__, len, self->max_data_size); len = self->max_data_size; } skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; skb_reserve(skb, self->max_header_size); skb_reset_transport_header(skb); IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__); skb_put(skb, len); err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { kfree_skb(skb); return err; } err = irlmp_connless_data_request((bound ? self->lsap : NULL), skb, pid); if (err) { IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); return err; } return len;}#endif /* CONFIG_IRDA_ULTRA *//* * Function irda_shutdown (sk, how) */static int irda_shutdown(struct socket *sock, int how){ struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self); sk->sk_state = TCP_CLOSE; sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_state_change(sk); 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; } /* A few cleanup so the socket look as good as new... */ self->rx_flow = self->tx_flow = FLOW_START; /* needed ??? */ self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ self->saddr = 0x0; /* so IrLMP assign us any link */ return 0;}/* * Function irda_poll (file, sock, wait) */static unsigned int irda_poll(struct file * file, struct socket *sock, poll_table *wait){ struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); unsigned int mask; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); poll_wait(file, sk->sk_sleep, wait); mask = 0; /* Exceptional events? */ if (sk->sk_err) mask |= POLLERR; if (sk->sk_shutdown & RCV_SHUTDOWN) { IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__); mask |= POLLHUP; } /* Readable? */ if (!skb_queue_empty(&sk->sk_receive_queue)) { IRDA_DEBUG(4, "Socket is readable\n"); mask |= POLLIN | POLLRDNORM; } /* Connection-based need to check for termination and startup */ switch (sk->sk_type) { case SOCK_STREAM: if (sk->sk_state == TCP_CLOSE) { IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__); mask |= POLLHUP; } if (sk->sk_state == TCP_ESTABLISHED) { if ((self->tx_flow == FLOW_START) && sock_writeable(sk)) { mask |= POLLOUT | POLLWRNORM | POLLWRBAND; } } break; case SOCK_SEQPACKET: if ((self->tx_flow == FLOW_START) && sock_writeable(sk)) { mask |= POLLOUT | POLLWRNORM | POLLWRBAND; } break; case SOCK_DGRAM: if (sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; break; default: break; } return mask;}/* * Function irda_ioctl (sock, cmd, arg) */static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; IRDA_DEBUG(4, "%s(), cmd=%#x\n", __FUNCTION__, cmd); switch (cmd) { case TIOCOUTQ: { long amount; amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; if (put_user(amount, (unsigned int __user *)arg)) return -EFAULT; return 0; } case TIOCINQ: { struct sk_buff *skb; long amount = 0L; /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; if (put_user(amount, (unsigned int __user *)arg)) return -EFAULT; return 0; } case SIOCGSTAMP: if (sk != NULL) return sock_get_timestamp(sk, (struct timeval __user *)arg); return -EINVAL; case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: return -EINVAL; default: IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __FUNCTION__); return -ENOIOCTLCMD; } /*NOTREACHED*/ return 0;}#ifdef CONFIG_COMPAT/* * Function irda_ioctl (sock, cmd, arg) */static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ /* * All IRDA's ioctl are standard ones. */ return -ENOIOCTLCMD;}#endif/* * Function irda_setsockopt (sock, level, optname, optval, optlen) * * Set some options for the socket * */static int irda_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen){ struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); struct irda_ias_set *ias_opt; struct ias_object *ias_obj; struct ias_attrib * ias_attr; /* Attribute in IAS object */ int opt, free_ias = 0; IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); if (level != SOL_IRLMP) return -ENOPROTOOPT; switch (optname) { case IRLMP_IAS_SET: /* The user want to add an attribute to an existing IAS object * (in the IAS database) or to create a new object with this * attribute. * We first query IAS to know if the object exist, and then * create the right attribute... */ if (optlen != sizeof(struct irda_ias_set)) return -EINVAL; ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); if (ias_opt == NULL) return -ENOMEM; /* Copy query to the driver. */ if (copy_from_user(ias_opt, optval, optlen)) { kfree(ias_opt); return -EFAULT; } /* Find the object we target. * If the user gives us an empty string, we use the object * associated with this socket. This will workaround * duplicated class name - Jean II */ if(ias_opt->irda_class_name[0] == '\0') { if(self->ias_obj == NULL) { kfree(ias_opt); return -EINVAL; } ias_obj = self->ias_obj; } else ias_obj = irias_find_object(ias_opt->irda_class_name); /* Only ROOT can mess with the global IAS database. * Users can only add attributes to the object associated * with the socket they own - Jean II */ if((!capable(CAP_NET_ADMIN)) && ((ias_obj == NULL) || (ias_obj != self->ias_obj))) { kfree(ias_opt); return -EPERM; } /* If the object doesn't exist, create it */ if(ias_obj == (struct ias_object *) NULL) { /* Create a new object */ ias_obj = irias_new_object(ias_opt->irda_class_name, jiffies); if (ias_obj == NULL) { kfree(ias_opt); return -ENOMEM; } free_ias = 1; } /* Do we have the attribute already ? */ if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) { kfree(ias_opt); if (free_ias) { kfree(ias_obj->name); kfree(ias_obj); } return -EINVAL; } /* Look at the type */ switch(ias_opt->irda_attrib_type) { case IAS_INTEGER: /* Add an integer attribute */ irias_add_integer_attrib( ias_obj, ias_opt->irda_attrib_name, ias_opt->attribute.irda_attrib_int, IAS_USER_ATTR); break; case IAS_OCT_SEQ: /* Check length */ if(ias_opt->attribute.irda_attrib_octet_seq.len > IAS_MAX_OCTET_STRING) { kfree(ias_opt); if (free_ias) { kfree(ias_obj->name); kfree(ias_obj); } return -EINVAL; } /* Add an octet sequence attribute */ irias_add_octseq_attrib( ias_obj, ias_opt->irda_attrib_name, ias_opt->attribute.irda_attrib_octet_seq.octet_seq, ias_opt->attribute.irda_attrib_octet_seq.len, IAS_USER_ATTR); break; case IAS_STRING: /* Should check charset & co */ /* Check length */ /* The length is encoded in a __u8, and * IAS_MAX_STRING == 256, so there is no way * userspace can pass us a string too large. * Jean II */ /* NULL terminate the string (avoid troubles) */ ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0'; /* Add a string attribute */ irias_add_string_attrib( ias_obj, ias_opt->irda_attrib_name, ias_opt->attribute.irda_attrib_string.string, IAS_USER_ATTR); break; default : kfree(ias_opt); if (free_ias) { kfree(ias_obj->name); kfree(ias_obj); } return -EINVAL; } irias_insert_object(ias_obj); kfree(ias_opt); break; case IRLMP_IAS_DEL: /* The user want to delete an object from our local IAS * database. We just need to query the IAS, check is the * object is not owned by the kernel and delete it. */ if (optlen != sizeof(struct irda_ias_set)) return -EINVAL; ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); if (ias_opt == NULL) return -ENOMEM; /* Copy query to the driver. */ if (copy_from_user(ias_opt, optval, optlen)) { kfree(ias_opt); return -EFAULT; } /* Find the object we target. * If the user gives us an empty string, we use the object * associated with this socket. This will workaround * duplicated class name - Jean II */ if(ias_opt->irda_class_name[0] == '\0') ias_obj = self->ias_obj;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -