static int connect(struct socket *sock, struct sockaddr *dest, int destlen, int flags) { struct sock *sk = sock->sk; struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; struct msghdr m = {NULL,}; struct sk_buff *buf; struct tipc_msg *msg; unsigned int timeout; int res; lock_sock(sk); /* For now, TIPC does not allow use of connect() with DGRAM/RDM types */ if (sock->state == SS_READY) { res = -EOPNOTSUPP; goto exit; } /* For now, TIPC does not support the non-blocking form of connect() */ if (flags & O_NONBLOCK) { res = -EOPNOTSUPP; goto exit; } /* Issue Posix-compliant error code if socket is in the wrong state */ if (sock->state == SS_LISTENING) { res = -EOPNOTSUPP; goto exit; } if (sock->state == SS_CONNECTING) { res = -EALREADY; goto exit; } if (sock->state != SS_UNCONNECTED) { res = -EISCONN; goto exit; } /* * Reject connection attempt using multicast address * * Note: send_msg() validates the rest of the address fields, * so there's no need to do it here */ if (dst->addrtype == TIPC_ADDR_MCAST) { res = -EINVAL; goto exit; } /* Reject any messages already in receive queue (very unlikely) */ reject_rx_queue(sk); /* Send a 'SYN-' to destination */ m.msg_name = dest; m.msg_namelen = destlen; res = send_msg(NULL, sock, &m, 0); if (res < 0) goto exit; /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ timeout = tipc_sk(sk)->conn_timeout; release_sock(sk); res = wait_event_interruptible_timeout(*sk_sleep(sk), (!skb_queue_empty(&sk->sk_receive_queue) || (sock->state != SS_CONNECTING)), timeout ? (long)msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT); lock_sock(sk); if (res > 0) { buf = skb_peek(&sk->sk_receive_queue); if (buf != NULL) { msg = buf_msg(buf); res = auto_connect(sock, msg); if (!res) { if (!msg_data_sz(msg)) advance_rx_queue(sk); } } else { if (sock->state == SS_CONNECTED) res = -EISCONN; else res = -ECONNREFUSED; } } else { if (res == 0) res = -ETIMEDOUT; else ; /* leave "res" unchanged */ sock->state = SS_DISCONNECTING; } exit: release_sock(sk); return res; }
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; struct bt_power pwr; struct bt_le_params le_params; struct l2cap_conn *conn; int len, err = 0; u32 opt; BT_DBG("sk %p", sk); if (level == SOL_L2CAP) return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; lock_sock(sk); switch (optname) { case BT_SECURITY: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } sec.level = BT_SECURITY_LOW; len = min_t(unsigned int, sizeof(sec), optlen); if (copy_from_user((char *) &sec, optval, len)) { err = -EFAULT; break; } if (sec.level < BT_SECURITY_LOW || sec.level > BT_SECURITY_HIGH) { err = -EINVAL; break; } l2cap_pi(sk)->sec_level = sec.level; conn = l2cap_pi(sk)->conn; if (conn && l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) { if (!conn->hcon->out) { err = -EINVAL; break; } if (smp_conn_security(conn, sec.level)) break; err = 0; sk->sk_state = BT_CONFIG; } break; case BT_DEFER_SETUP: if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { err = -EINVAL; break; } if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } bt_sk(sk)->defer_setup = opt; break; case BT_POWER: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } pwr.force_active = 1; len = min_t(unsigned int, sizeof(pwr), optlen); if (copy_from_user((char *) &pwr, optval, len)) { err = -EFAULT; break; } l2cap_pi(sk)->force_active = pwr.force_active; break; case BT_AMP_POLICY: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } if ((opt > BT_AMP_POLICY_PREFER_AMP) || ((l2cap_pi(sk)->mode != L2CAP_MODE_ERTM) && (l2cap_pi(sk)->mode != L2CAP_MODE_STREAMING))) { err = -EINVAL; break; } l2cap_pi(sk)->amp_pref = (u8) opt; BT_DBG("BT_AMP_POLICY now %d", opt); if ((sk->sk_state == BT_CONNECTED) && (l2cap_pi(sk)->amp_move_role == L2CAP_AMP_MOVE_NONE)) l2cap_amp_move_init(sk); break; case BT_FLUSHABLE: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } l2cap_pi(sk)->flushable = opt; break; case BT_LE_PARAMS: if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { err = -EINVAL; break; } if (copy_from_user((char *) &le_params, optval, sizeof(struct bt_le_params))) { err = -EFAULT; break; } conn = l2cap_pi(sk)->conn; if (!conn || !conn->hcon || l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); break; } if (!conn->hcon->out || !l2cap_sock_le_conn_update_params_valid( &le_params)) { err = -EINVAL; break; } memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); hci_le_conn_update(conn->hcon, le_params.interval_min, le_params.interval_max, le_params.latency, le_params.supervision_timeout); break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) { struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); int ifindex; int err = 0; int notify_enetdown = 0; if (len < sizeof(*addr)) return -EINVAL; lock_sock(sk); if (ro->bound && addr->can_ifindex == ro->ifindex) goto out; if (addr->can_ifindex) { struct net_device *dev; dev = dev_get_by_index(&init_net, addr->can_ifindex); if (!dev) { err = -ENODEV; goto out; } if (dev->type != ARPHRD_CAN) { dev_put(dev); err = -ENODEV; goto out; } if (!(dev->flags & IFF_UP)) notify_enetdown = 1; ifindex = dev->ifindex; /* filters set by default/setsockopt */ err = raw_enable_allfilters(dev, sk); dev_put(dev); } else { ifindex = 0; /* filters set by default/setsockopt */ err = raw_enable_allfilters(NULL, sk); } if (!err) { if (ro->bound) { /* unregister old filters */ if (ro->ifindex) { struct net_device *dev; dev = dev_get_by_index(&init_net, ro->ifindex); if (dev) { raw_disable_allfilters(dev, sk); dev_put(dev); } } else raw_disable_allfilters(NULL, sk); } ro->ifindex = ifindex; ro->bound = 1; } out: release_sock(sk); if (notify_enetdown) { sk->sk_err = ENETDOWN; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_error_report(sk); } return err; }
static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; struct sockaddr_l2 la; int len, err = 0; BT_DBG("sk %p type %d mode %d state %d", sk, sk->sk_type, l2cap_pi(sk)->mode, sk->sk_state); if (!addr || alen < sizeof(addr->sa_family) || addr->sa_family != AF_BLUETOOTH) return -EINVAL; memset(&la, 0, sizeof(la)); len = min_t(unsigned int, sizeof(la), alen); memcpy(&la, addr, len); if (la.l2_cid && la.l2_psm) return -EINVAL; lock_sock(sk); if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) && !(la.l2_psm || la.l2_cid || l2cap_pi(sk)->fixed_channel)) { err = -EINVAL; goto done; } switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: if (!disable_ertm) break; /* fall through */ default: err = -ENOTSUPP; goto done; } switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: /* Already connecting */ goto wait; case BT_CONNECTED: /* Already connected */ err = -EISCONN; goto done; case BT_OPEN: case BT_BOUND: /* Can connect */ break; default: err = -EBADFD; goto done; } /* PSM must be odd and lsb of upper byte must be 0 */ if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !l2cap_pi(sk)->fixed_channel && sk->sk_type != SOCK_RAW && !la.l2_cid) { BT_DBG("Bad PSM 0x%x", (int)__le16_to_cpu(la.l2_psm)); err = -EINVAL; goto done; } /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->dcid = la.l2_cid; err = l2cap_do_connect(sk); if (err) goto done; wait: err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: if (err) BT_ERR("failed %d", err); release_sock(sk); return err; }
static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct bt_security sec; struct bt_power pwr; int len, err = 0; BT_DBG("sk %p", sk); if (level == SOL_L2CAP) return l2cap_sock_getsockopt_old(sock, optname, optval, optlen); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; if (get_user(len, optlen)) return -EFAULT; lock_sock(sk); switch (optname) { case BT_SECURITY: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } memset(&sec, 0, sizeof(sec)); sec.level = l2cap_pi(sk)->sec_level; if (sk->sk_state == BT_CONNECTED) { sec.key_size = l2cap_pi(sk)->conn->hcon->enc_key_size; sec.level = l2cap_pi(sk)->conn->hcon->sec_level; } len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) err = -EFAULT; break; case BT_DEFER_SETUP: if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { err = -EINVAL; break; } if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) err = -EFAULT; break; case BT_POWER: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } pwr.force_active = l2cap_pi(sk)->force_active; len = min_t(unsigned int, len, sizeof(pwr)); if (copy_to_user(optval, (char *) &pwr, len)) err = -EFAULT; break; case BT_AMP_POLICY: if (put_user(l2cap_pi(sk)->amp_pref, (u32 __user *) optval)) err = -EFAULT; break; case BT_LE_PARAMS: if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { err = -EINVAL; break; } if (copy_to_user(optval, (char *) &bt_sk(sk)->le_params, sizeof(bt_sk(sk)->le_params))) err = -EFAULT; break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
void dccp_close(struct sock *sk, long timeout) { struct dccp_sock *dp = dccp_sk(sk); struct sk_buff *skb; u32 data_was_unread = 0; int state; lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; if (sk->sk_state == DCCP_LISTEN) { dccp_set_state(sk, DCCP_CLOSED); /* Special case. */ inet_csk_listen_stop(sk); goto adjudge_to_death; } sk_stop_timer(sk, &dp->dccps_xmit_timer); /* * We need to flush the recv. buffs. We do this only on the * descriptor close, not protocol-sourced closes, because the *reader process may not have drained the data yet! */ while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { data_was_unread += skb->len; __kfree_skb(skb); } if (data_was_unread) { /* Unread data was tossed, send an appropriate Reset Code */ DCCP_WARN("DCCP: ABORT -- %u bytes unread\n", data_was_unread); dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED); dccp_set_state(sk, DCCP_CLOSED); } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { /* Check zero linger _after_ checking for unread data. */ sk->sk_prot->disconnect(sk, 0); } else if (sk->sk_state != DCCP_CLOSED) { dccp_terminate_connection(sk); } sk_stream_wait_close(sk, timeout); adjudge_to_death: state = sk->sk_state; sock_hold(sk); sock_orphan(sk); /* * It is the last release_sock in its life. It will remove backlog. */ release_sock(sk); /* * Now socket is owned by kernel and we acquire BH lock * to finish close. No need to check for user refs. */ local_bh_disable(); bh_lock_sock(sk); WARN_ON(sock_owned_by_user(sk)); percpu_counter_inc(sk->sk_prot->orphan_count); /* Have we already been destroyed by a softirq or backlog? */ if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED) goto out; if (sk->sk_state == DCCP_CLOSED) inet_csk_destroy_sock(sk); /* Otherwise, socket is reprieved until protocol close. */ out: bh_unlock_sock(sk); local_bh_enable(); sock_put(sk); }
static int raw_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); int len; void *val; int err = 0; if (level != SOL_CAN_RAW) return -EINVAL; if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: lock_sock(sk); if (ro->count > 0) { int fsize = ro->count * sizeof(struct can_filter); if (len > fsize) len = fsize; if (copy_to_user(optval, ro->filter, len)) err = -EFAULT; } else len = 0; release_sock(sk); if (!err) err = put_user(len, optlen); return err; case CAN_RAW_ERR_FILTER: if (len > sizeof(can_err_mask_t)) len = sizeof(can_err_mask_t); val = &ro->err_mask; break; case CAN_RAW_LOOPBACK: if (len > sizeof(int)) len = sizeof(int); val = &ro->loopback; break; case CAN_RAW_RECV_OWN_MSGS: if (len > sizeof(int)) len = sizeof(int); val = &ro->recv_own_msgs; break; default: return -ENOPROTOOPT; } if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, val, len)) return -EFAULT; return 0; }
static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) { struct atmsvc_msg *msg; struct atm_vcc *session_vcc; struct sock *sk; msg = (struct atmsvc_msg *) skb->data; atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); vcc = *(struct atm_vcc **) &msg->vcc; pr_debug("sigd_send %d (0x%lx)\n",(int) msg->type, (unsigned long) vcc); sk = sk_atm(vcc); switch (msg->type) { case as_okay: sk->sk_err = -msg->reply; clear_bit(ATM_VF_WAITING, &vcc->flags); if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) { vcc->local.sas_family = AF_ATMSVC; memcpy(vcc->local.sas_addr.prv, msg->local.sas_addr.prv,ATM_ESA_LEN); memcpy(vcc->local.sas_addr.pub, msg->local.sas_addr.pub,ATM_E164_LEN+1); } session_vcc = vcc->session ? vcc->session : vcc; if (session_vcc->vpi || session_vcc->vci) break; session_vcc->itf = msg->pvc.sap_addr.itf; session_vcc->vpi = msg->pvc.sap_addr.vpi; session_vcc->vci = msg->pvc.sap_addr.vci; if (session_vcc->vpi || session_vcc->vci) session_vcc->qos = msg->qos; break; case as_error: clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags); sk->sk_err = -msg->reply; clear_bit(ATM_VF_WAITING, &vcc->flags); break; case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; sk = sk_atm(vcc); pr_debug("as_indicate!!!\n"); lock_sock(sk); if (sk_acceptq_is_full(sk)) { sigd_enq(NULL,as_reject,vcc,NULL,NULL); dev_kfree_skb(skb); goto as_indicate_complete; } sk->sk_ack_backlog++; skb_queue_tail(&sk->sk_receive_queue, skb); pr_debug("waking sk_sleep(sk) 0x%p\n", sk_sleep(sk)); sk->sk_state_change(sk); as_indicate_complete: release_sock(sk); return 0; case as_close: set_bit(ATM_VF_RELEASED,&vcc->flags); vcc_release_async(vcc, msg->reply); goto out; case as_modify: modify_qos(vcc,msg); break; case as_addparty: case as_dropparty: sk->sk_err_soft = msg->reply; /* < 0 failure, otherwise ep_ref */ clear_bit(ATM_VF_WAITING, &vcc->flags); break; default: printk(KERN_ALERT "sigd_send: bad message type %d\n", (int) msg->type); return -EINVAL; } sk->sk_state_change(sk); out: dev_kfree_skb(skb); return 0; }
static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct pep_sock *pn = pep_sk(sk); struct sk_buff *skb; long timeo; int flags = msg->msg_flags; int err, done; if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR)) return -EOPNOTSUPP; skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, flags & MSG_DONTWAIT, &err); if (!skb) return -ENOBUFS; skb_reserve(skb, MAX_PHONET_HEADER + 3); err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (err < 0) goto outfree; lock_sock(sk); timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { err = -ENOTCONN; goto out; } if (sk->sk_state != TCP_ESTABLISHED) { /* Wait until the pipe gets to enabled state */ disabled: err = sk_stream_wait_connect(sk, &timeo); if (err) goto out; if (sk->sk_state == TCP_CLOSE_WAIT) { err = -ECONNRESET; goto out; } } BUG_ON(sk->sk_state != TCP_ESTABLISHED); /* Wait until flow control allows TX */ done = atomic_read(&pn->tx_credits); while (!done) { DEFINE_WAIT(wait); if (!timeo) { err = -EAGAIN; goto out; } if (signal_pending(current)) { err = sock_intr_errno(timeo); goto out; } prepare_to_wait(&sk->sk_socket->wait, &wait, TASK_INTERRUPTIBLE); done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); finish_wait(&sk->sk_socket->wait, &wait); if (sk->sk_state != TCP_ESTABLISHED) goto disabled; } err = pipe_skb_send(sk, skb); if (err >= 0) err = len; /* success! */ skb = NULL; out: release_sock(sk); outfree: kfree_skb(skb); return err; }
static int send_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct msghdr my_msg; struct iovec my_iov; struct iovec *curr_iov; int curr_iovlen; char __user *curr_start; u32 hdr_size; int curr_left; int bytes_to_send; int bytes_sent; int res; lock_sock(sk); /* Handle special cases where there is no connection */ if (unlikely(sock->state != SS_CONNECTED)) { if (sock->state == SS_UNCONNECTED) { res = send_packet(NULL, sock, m, total_len); goto exit; } else if (sock->state == SS_DISCONNECTING) { res = -EPIPE; goto exit; } else { res = -ENOTCONN; goto exit; } } if (unlikely(m->msg_name)) { res = -EISCONN; goto exit; } if ((total_len > (unsigned)INT_MAX) || (m->msg_iovlen > (unsigned)INT_MAX)) { res = -EMSGSIZE; goto exit; } /* * Send each iovec entry using one or more messages * * Note: This algorithm is good for the most likely case * (i.e. one large iovec entry), but could be improved to pass sets * of small iovec entries into send_packet(). */ curr_iov = m->msg_iov; curr_iovlen = m->msg_iovlen; my_msg.msg_iov = &my_iov; my_msg.msg_iovlen = 1; my_msg.msg_flags = m->msg_flags; my_msg.msg_name = NULL; bytes_sent = 0; hdr_size = msg_hdr_sz(&tport->phdr); while (curr_iovlen--) { curr_start = curr_iov->iov_base; curr_left = curr_iov->iov_len; while (curr_left) { bytes_to_send = tport->max_pkt - hdr_size; if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE) bytes_to_send = TIPC_MAX_USER_MSG_SIZE; if (curr_left < bytes_to_send) bytes_to_send = curr_left; my_iov.iov_base = curr_start; my_iov.iov_len = bytes_to_send; res = send_packet(NULL, sock, &my_msg, bytes_to_send); if (res < 0) { if (bytes_sent) res = bytes_sent; goto exit; } curr_left -= bytes_to_send; curr_start += bytes_to_send; bytes_sent += bytes_to_send; } curr_iov++; } res = bytes_sent; exit: release_sock(sk); return res; }
static int recv_msg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; struct tipc_msg *msg; long timeout; unsigned int sz; u32 err; int res; /* Catch invalid receive requests */ if (unlikely(!buf_len)) return -EINVAL; lock_sock(sk); if (unlikely(sock->state == SS_UNCONNECTED)) { res = -ENOTCONN; goto exit; } timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); restart: /* Look for a message in receive queue; wait if necessary */ while (skb_queue_empty(&sk->sk_receive_queue)) { if (sock->state == SS_DISCONNECTING) { res = -ENOTCONN; goto exit; } if (timeout <= 0L) { res = timeout ? timeout : -EWOULDBLOCK; goto exit; } release_sock(sk); timeout = wait_event_interruptible_timeout(*sk_sleep(sk), tipc_rx_ready(sock), timeout); lock_sock(sk); } /* Look at first message in receive queue */ buf = skb_peek(&sk->sk_receive_queue); msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); /* Complete connection setup for an implied connect */ if (unlikely(sock->state == SS_CONNECTING)) { res = auto_connect(sock, msg); if (res) goto exit; } /* Discard an empty non-errored message & try again */ if ((!sz) && (!err)) { advance_rx_queue(sk); goto restart; } /* Capture sender's address (optional) */ set_orig_addr(m, msg); /* Capture ancillary data (optional) */ res = anc_data_recv(m, msg, tport); if (res) goto exit; /* Capture message data (if valid) & compute return value (always) */ if (!err) { if (unlikely(buf_len < sz)) { sz = buf_len; m->msg_flags |= MSG_TRUNC; } res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg), m->msg_iov, sz); if (res) goto exit; res = sz; } else { if ((sock->state == SS_READY) || ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)) res = 0; else res = -ECONNRESET; } /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { if ((sock->state != SS_READY) && (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) tipc_acknowledge(tport->ref, tport->conn_unacked); advance_rx_queue(sk); } exit: release_sock(sk); return res; }
static int send_msg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; int needs_conn; long timeout_val; int res = -EINVAL; if (unlikely(!dest)) return -EDESTADDRREQ; if (unlikely((m->msg_namelen < sizeof(*dest)) || (dest->family != AF_TIPC))) return -EINVAL; if ((total_len > TIPC_MAX_USER_MSG_SIZE) || (m->msg_iovlen > (unsigned)INT_MAX)) return -EMSGSIZE; if (iocb) lock_sock(sk); needs_conn = (sock->state != SS_READY); if (unlikely(needs_conn)) { if (sock->state == SS_LISTENING) { res = -EPIPE; goto exit; } if (sock->state != SS_UNCONNECTED) { res = -EISCONN; goto exit; } if ((tport->published) || ((sock->type == SOCK_STREAM) && (total_len != 0))) { res = -EOPNOTSUPP; goto exit; } if (dest->addrtype == TIPC_ADDR_NAME) { tport->conn_type = dest->addr.name.name.type; tport->conn_instance = dest->addr.name.name.instance; } /* Abort any pending connection attempts (very unlikely) */ reject_rx_queue(sk); } timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); do { if (dest->addrtype == TIPC_ADDR_NAME) { res = dest_name_check(dest, m); if (res) break; res = tipc_send2name(tport->ref, &dest->addr.name.name, dest->addr.name.domain, m->msg_iovlen, m->msg_iov, total_len); } else if (dest->addrtype == TIPC_ADDR_ID) { res = tipc_send2port(tport->ref, &dest->addr.id, m->msg_iovlen, m->msg_iov, total_len); } else if (dest->addrtype == TIPC_ADDR_MCAST) { if (needs_conn) { res = -EOPNOTSUPP; break; } res = dest_name_check(dest, m); if (res) break; res = tipc_multicast(tport->ref, &dest->addr.nameseq, m->msg_iovlen, m->msg_iov, total_len); } if (likely(res != -ELINKCONG)) { if (needs_conn && (res >= 0)) sock->state = SS_CONNECTING; break; } if (timeout_val <= 0L) { res = timeout_val ? timeout_val : -EWOULDBLOCK; break; } release_sock(sk); timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), !tport->congested, timeout_val); lock_sock(sk); } while (1); exit: if (iocb) release_sock(sk); return res; }
static int release(struct socket *sock) { struct sock *sk = sock->sk; struct tipc_port *tport; struct sk_buff *buf; int res; /* * Exit if socket isn't fully initialized (occurs when a failed accept() * releases a pre-allocated child socket that was never used) */ if (sk == NULL) return 0; tport = tipc_sk_port(sk); lock_sock(sk); /* * Reject all unreceived messages, except on an active connection * (which disconnects locally & sends a 'FIN+' to peer) */ while (sock->state != SS_DISCONNECTING) { buf = __skb_dequeue(&sk->sk_receive_queue); if (buf == NULL) break; atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != 0) kfree_skb(buf); else { if ((sock->state == SS_CONNECTING) || (sock->state == SS_CONNECTED)) { sock->state = SS_DISCONNECTING; tipc_disconnect(tport->ref); } tipc_reject_msg(buf, TIPC_ERR_NO_PORT); } } /* * Delete TIPC port; this ensures no more messages are queued * (also disconnects an active connection & sends a 'FIN-' to peer) */ res = tipc_deleteport(tport->ref); /* Discard any remaining (connection-based) messages in receive queue */ discard_rx_queue(sk); /* Reject any messages that accumulated in backlog queue */ sock->state = SS_DISCONNECTING; release_sock(sk); sock_put(sk); sock->sk = NULL; return res; }
static int accept(struct socket *sock, struct socket *new_sock, int flags) { struct sock *sk = sock->sk; struct sk_buff *buf; int res; lock_sock(sk); if (sock->state != SS_LISTENING) { res = -EINVAL; goto exit; } while (skb_queue_empty(&sk->sk_receive_queue)) { if (flags & O_NONBLOCK) { res = -EWOULDBLOCK; goto exit; } release_sock(sk); res = wait_event_interruptible(*sk_sleep(sk), (!skb_queue_empty(&sk->sk_receive_queue))); lock_sock(sk); if (res) goto exit; } buf = skb_peek(&sk->sk_receive_queue); res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); if (!res) { struct sock *new_sk = new_sock->sk; struct tipc_sock *new_tsock = tipc_sk(new_sk); struct tipc_port *new_tport = new_tsock->p; u32 new_ref = new_tport->ref; struct tipc_msg *msg = buf_msg(buf); lock_sock(new_sk); /* * Reject any stray messages received by new socket * before the socket lock was taken (very, very unlikely) */ reject_rx_queue(new_sk); /* Connect new socket to it's peer */ new_tsock->peer_name.ref = msg_origport(msg); new_tsock->peer_name.node = msg_orignode(msg); tipc_connect2port(new_ref, &new_tsock->peer_name); new_sock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { new_tport->conn_type = msg_nametype(msg); new_tport->conn_instance = msg_nameinst(msg); } /* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; advance_rx_queue(sk); send_packet(NULL, new_sock, &m, 0); } else { __skb_dequeue(&sk->sk_receive_queue); __skb_queue_head(&new_sk->sk_receive_queue, buf); } release_sock(new_sk); } exit: release_sock(sk); return res; }
int sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk=sock->sk; struct sk_filter *filter; int val; int valbool; struct linger ling; int ret = 0; /* * Options without arguments */ #ifdef SO_DONTLINGER /* Compatibility item... */ switch (optname) { case SO_DONTLINGER: sock_reset_flag(sk, SOCK_LINGER); return 0; } #endif if(optlen<sizeof(int)) return(-EINVAL); if (get_user(val, (int __user *)optval)) return -EFAULT; valbool = val?1:0; lock_sock(sk); switch(optname) { case SO_DEBUG: if(val && !capable(CAP_NET_ADMIN)) { ret = -EACCES; } else sk->sk_debug = valbool; break; case SO_REUSEADDR: sk->sk_reuse = valbool; break; case SO_TYPE: case SO_ERROR: ret = -ENOPROTOOPT; break; case SO_DONTROUTE: sk->sk_localroute = valbool; break; case SO_BROADCAST: sock_valbool_flag(sk, SOCK_BROADCAST, valbool); break; case SO_SNDBUF: /* Don't error on this BSD doesn't and if you think about it this is right. Otherwise apps have to play 'guess the biggest size' games. RCVBUF/SNDBUF are treated in BSD as hints */ if (val > sysctl_wmem_max) val = sysctl_wmem_max; sk->sk_userlocks |= SOCK_SNDBUF_LOCK; if ((val * 2) < SOCK_MIN_SNDBUF) sk->sk_sndbuf = SOCK_MIN_SNDBUF; else sk->sk_sndbuf = val * 2; /* * Wake up sending tasks if we * upped the value. */ sk->sk_write_space(sk); break; case SO_RCVBUF: /* Don't error on this BSD doesn't and if you think about it this is right. Otherwise apps have to play 'guess the biggest size' games. RCVBUF/SNDBUF are treated in BSD as hints */ if (val > sysctl_rmem_max) val = sysctl_rmem_max; sk->sk_userlocks |= SOCK_RCVBUF_LOCK; /* FIXME: is this lower bound the right one? */ if ((val * 2) < SOCK_MIN_RCVBUF) sk->sk_rcvbuf = SOCK_MIN_RCVBUF; else sk->sk_rcvbuf = val * 2; break; case SO_KEEPALIVE: #ifdef CONFIG_INET if (sk->sk_protocol == IPPROTO_TCP) tcp_set_keepalive(sk, valbool); #endif sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool); break; case SO_OOBINLINE: sock_valbool_flag(sk, SOCK_URGINLINE, valbool); break; case SO_NO_CHECK: sk->sk_no_check = valbool; break; case SO_PRIORITY: if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN)) sk->sk_priority = val; else ret = -EPERM; break; case SO_LINGER: if(optlen<sizeof(ling)) { ret = -EINVAL; /* 1003.1g */ break; } if (copy_from_user(&ling,optval,sizeof(ling))) { ret = -EFAULT; break; } if (!ling.l_onoff) sock_reset_flag(sk, SOCK_LINGER); else { #if (BITS_PER_LONG == 32) if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; else #endif sk->sk_lingertime = ling.l_linger * HZ; sock_set_flag(sk, SOCK_LINGER); } break; case SO_BSDCOMPAT: sock_warn_obsolete_bsdism("setsockopt"); break; case SO_PASSCRED: sock->passcred = valbool; break; case SO_TIMESTAMP: sk->sk_rcvtstamp = valbool; break; case SO_RCVLOWAT: if (val < 0) val = INT_MAX; sk->sk_rcvlowat = val ? : 1; break; case SO_RCVTIMEO: ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen); break; case SO_SNDTIMEO: ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen); break; #ifdef CONFIG_NETDEVICES case SO_BINDTODEVICE: { char devname[IFNAMSIZ]; /* Sorry... */ if (!capable(CAP_NET_RAW)) { ret = -EPERM; break; } /* Bind this socket to a particular device like "eth0", * as specified in the passed interface name. If the * name is "" or the option length is zero the socket * is not bound. */ if (!valbool) { sk->sk_bound_dev_if = 0; } else { if (optlen > IFNAMSIZ) optlen = IFNAMSIZ; if (copy_from_user(devname, optval, optlen)) { ret = -EFAULT; break; } /* Remove any cached route for this socket. */ sk_dst_reset(sk); if (devname[0] == '\0') { sk->sk_bound_dev_if = 0; } else { struct net_device *dev = dev_get_by_name(devname); if (!dev) { ret = -ENODEV; break; } sk->sk_bound_dev_if = dev->ifindex; dev_put(dev); } } break; } #endif case SO_ATTACH_FILTER: ret = -EINVAL; if (optlen == sizeof(struct sock_fprog)) { struct sock_fprog fprog; ret = -EFAULT; if (copy_from_user(&fprog, optval, sizeof(fprog))) break; ret = sk_attach_filter(&fprog, sk); } break; case SO_DETACH_FILTER: spin_lock_bh(&sk->sk_lock.slock); filter = sk->sk_filter; if (filter) { sk->sk_filter = NULL; spin_unlock_bh(&sk->sk_lock.slock); sk_filter_release(sk, filter); break; } spin_unlock_bh(&sk->sk_lock.slock); ret = -ENONET; break; /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: ret = -ENOPROTOOPT; break; } release_sock(sk); return ret; }
int ipv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { struct ipv6_pinfo *np = inet6_sk(sk); int val, valbool; int retv = -ENOPROTOOPT; if (level == SOL_IP && sk->sk_type != SOCK_RAW) return udp_prot.setsockopt(sk, level, optname, optval, optlen); if(level!=SOL_IPV6) goto out; if (optval == NULL) val=0; else if (get_user(val, (int __user *) optval)) return -EFAULT; valbool = (val!=0); lock_sock(sk); switch (optname) { case IPV6_ADDRFORM: if (val == PF_INET) { struct ipv6_txoptions *opt; struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_TCP) break; if (sk->sk_state != TCP_ESTABLISHED) { retv = -ENOTCONN; break; } if (ipv6_only_sock(sk) || !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) { retv = -EADDRNOTAVAIL; break; } fl6_free_socklist(sk); ipv6_sock_mc_close(sk); if (sk->sk_protocol == IPPROTO_TCP) { struct tcp_sock *tp = tcp_sk(sk); local_bh_disable(); sock_prot_dec_use(sk->sk_prot); sock_prot_inc_use(&tcp_prot); local_bh_enable(); sk->sk_prot = &tcp_prot; tp->af_specific = &ipv4_specific; sk->sk_socket->ops = &inet_stream_ops; sk->sk_family = PF_INET; tcp_sync_mss(sk, tp->pmtu_cookie); } else { local_bh_disable(); sock_prot_dec_use(sk->sk_prot); sock_prot_inc_use(&udp_prot); local_bh_enable(); sk->sk_prot = &udp_prot; sk->sk_socket->ops = &inet_dgram_ops; sk->sk_family = PF_INET; } opt = xchg(&np->opt, NULL); if (opt) sock_kfree_s(sk, opt, opt->tot_len); pktopt = xchg(&np->pktoptions, NULL); if (pktopt) kfree_skb(pktopt); sk->sk_destruct = inet_sock_destruct; #ifdef INET_REFCNT_DEBUG atomic_dec(&inet6_sock_nr); #endif module_put(THIS_MODULE); retv = 0; break; } goto e_inval; case IPV6_V6ONLY: if (inet_sk(sk)->num) goto e_inval; np->ipv6only = valbool; retv = 0; break; case IPV6_PKTINFO: np->rxopt.bits.rxinfo = valbool; retv = 0; break; case IPV6_HOPLIMIT: np->rxopt.bits.rxhlim = valbool; retv = 0; break; case IPV6_RTHDR: if (val < 0 || val > 2) goto e_inval; np->rxopt.bits.srcrt = val; retv = 0; break; case IPV6_HOPOPTS: np->rxopt.bits.hopopts = valbool; retv = 0; break; case IPV6_DSTOPTS: np->rxopt.bits.dstopts = valbool; retv = 0; break; case IPV6_FLOWINFO: np->rxopt.bits.rxflow = valbool; retv = 0; break; case IPV6_PKTOPTIONS: { struct ipv6_txoptions *opt = NULL; struct msghdr msg; struct flowi fl; int junk; fl.fl6_flowlabel = 0; fl.oif = sk->sk_bound_dev_if; if (optlen == 0) goto update; /* 1K is probably excessive * 1K is surely not enough, 2K per standard header is 16K. */ retv = -EINVAL; if (optlen > 64*1024) break; opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); retv = -ENOBUFS; if (opt == NULL) break; memset(opt, 0, sizeof(*opt)); opt->tot_len = sizeof(*opt) + optlen; retv = -EFAULT; if (copy_from_user(opt+1, optval, optlen)) goto done; msg.msg_controllen = optlen; msg.msg_control = (void*)(opt+1); retv = datagram_send_ctl(&msg, &fl, opt, &junk); if (retv) goto done; update: retv = 0; if (sk->sk_type == SOCK_STREAM) { if (opt) { struct tcp_sock *tp = tcp_sk(sk); if (!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { tp->ext_header_len = opt->opt_flen + opt->opt_nflen; tcp_sync_mss(sk, tp->pmtu_cookie); } } opt = xchg(&np->opt, opt); sk_dst_reset(sk); } else { write_lock(&sk->sk_dst_lock); opt = xchg(&np->opt, opt); write_unlock(&sk->sk_dst_lock); sk_dst_reset(sk); } done: if (opt) sock_kfree_s(sk, opt, opt->tot_len); break; } case IPV6_UNICAST_HOPS: if (val > 255 || val < -1) goto e_inval; np->hop_limit = val; retv = 0; break; case IPV6_MULTICAST_HOPS: if (sk->sk_type == SOCK_STREAM) goto e_inval; if (val > 255 || val < -1) goto e_inval; np->mcast_hops = val; retv = 0; break; case IPV6_MULTICAST_LOOP: np->mc_loop = valbool; retv = 0; break; case IPV6_MULTICAST_IF: if (sk->sk_type == SOCK_STREAM) goto e_inval; if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; if (__dev_get_by_index(val) == NULL) { retv = -ENODEV; break; } np->mcast_oif = val; retv = 0; break; case IPV6_ADD_MEMBERSHIP: case IPV6_DROP_MEMBERSHIP: { struct ipv6_mreq mreq; retv = -EFAULT; if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) break; if (optname == IPV6_ADD_MEMBERSHIP) retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); else retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); break; } case IPV6_JOIN_ANYCAST: case IPV6_LEAVE_ANYCAST: { struct ipv6_mreq mreq; if (optlen != sizeof(struct ipv6_mreq)) goto e_inval; retv = -EFAULT; if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) break; if (optname == IPV6_JOIN_ANYCAST) retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); else retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); break; } case MCAST_JOIN_GROUP: case MCAST_LEAVE_GROUP: { struct group_req greq; struct sockaddr_in6 *psin6; retv = -EFAULT; if (copy_from_user(&greq, optval, sizeof(struct group_req))) break; if (greq.gr_group.ss_family != AF_INET6) { retv = -EADDRNOTAVAIL; break; } psin6 = (struct sockaddr_in6 *)&greq.gr_group; if (optname == MCAST_JOIN_GROUP) retv = ipv6_sock_mc_join(sk, greq.gr_interface, &psin6->sin6_addr); else retv = ipv6_sock_mc_drop(sk, greq.gr_interface, &psin6->sin6_addr); break; } case MCAST_JOIN_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP: case MCAST_BLOCK_SOURCE: case MCAST_UNBLOCK_SOURCE: { struct group_source_req greqs; int omode, add; if (optlen != sizeof(struct group_source_req)) goto e_inval; if (copy_from_user(&greqs, optval, sizeof(greqs))) { retv = -EFAULT; break; } if (greqs.gsr_group.ss_family != AF_INET6 || greqs.gsr_source.ss_family != AF_INET6) { retv = -EADDRNOTAVAIL; break; } if (optname == MCAST_BLOCK_SOURCE) { omode = MCAST_EXCLUDE; add = 1; } else if (optname == MCAST_UNBLOCK_SOURCE) { omode = MCAST_EXCLUDE; add = 0; } else if (optname == MCAST_JOIN_SOURCE_GROUP) { struct sockaddr_in6 *psin6; psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, &psin6->sin6_addr); if (retv) break; omode = MCAST_INCLUDE; add = 1; } else /*IP_DROP_SOURCE_MEMBERSHIP */ { omode = MCAST_INCLUDE; add = 0; } retv = ip6_mc_source(add, omode, sk, &greqs); break; } case MCAST_MSFILTER: { extern int sysctl_optmem_max; extern int sysctl_mld_max_msf; struct group_filter *gsf; if (optlen < GROUP_FILTER_SIZE(0)) goto e_inval; if (optlen > sysctl_optmem_max) { retv = -ENOBUFS; break; } gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL); if (gsf == 0) { retv = -ENOBUFS; break; } retv = -EFAULT; if (copy_from_user(gsf, optval, optlen)) { kfree(gsf); break; } /* numsrc >= (4G-140)/128 overflow in 32 bits */ if (gsf->gf_numsrc >= 0x1ffffffU || gsf->gf_numsrc > sysctl_mld_max_msf) { kfree(gsf); retv = -ENOBUFS; break; } if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { kfree(gsf); retv = -EINVAL; break; } retv = ip6_mc_msfilter(sk, gsf); kfree(gsf); break; } case IPV6_ROUTER_ALERT: retv = ip6_ra_control(sk, val, NULL); break; case IPV6_MTU_DISCOVER: if (val<0 || val>2) goto e_inval; np->pmtudisc = val; retv = 0; break; case IPV6_MTU: if (val && val < IPV6_MIN_MTU) goto e_inval; np->frag_size = val; retv = 0; break; case IPV6_RECVERR: np->recverr = valbool; if (!val) skb_queue_purge(&sk->sk_error_queue); retv = 0; break; case IPV6_FLOWINFO_SEND: np->sndflow = valbool; retv = 0; break; case IPV6_FLOWLABEL_MGR: retv = ipv6_flowlabel_opt(sk, optval, optlen); break; case IPV6_IPSEC_POLICY: case IPV6_XFRM_POLICY: retv = xfrm_user_policy(sk, optname, optval, optlen); break; #ifdef CONFIG_NETFILTER default: retv = nf_setsockopt(sk, PF_INET6, optname, optval, optlen); break; #endif } release_sock(sk); out: return retv; e_inval: release_sock(sk); return -EINVAL; }
int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len) { const struct dccp_hdr *dh; long timeo; lock_sock(sk); if (sk->sk_state == DCCP_LISTEN) { len = -ENOTCONN; goto out; } timeo = sock_rcvtimeo(sk, nonblock); do { struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); if (skb == NULL) goto verify_sock_status; dh = dccp_hdr(skb); switch (dh->dccph_type) { case DCCP_PKT_DATA: case DCCP_PKT_DATAACK: goto found_ok_skb; case DCCP_PKT_CLOSE: case DCCP_PKT_CLOSEREQ: if (!(flags & MSG_PEEK)) dccp_finish_passive_close(sk); /* fall through */ case DCCP_PKT_RESET: dccp_pr_debug("found fin (%s) ok!\n", dccp_packet_name(dh->dccph_type)); len = 0; goto found_fin_ok; default: dccp_pr_debug("packet_type=%s\n", dccp_packet_name(dh->dccph_type)); sk_eat_skb(sk, skb, 0); } verify_sock_status: if (sock_flag(sk, SOCK_DONE)) { len = 0; break; } if (sk->sk_err) { len = sock_error(sk); break; } if (sk->sk_shutdown & RCV_SHUTDOWN) { len = 0; break; } if (sk->sk_state == DCCP_CLOSED) { if (!sock_flag(sk, SOCK_DONE)) { /* This occurs when user tries to read * from never connected socket. */ len = -ENOTCONN; break; } len = 0; break; } if (!timeo) { len = -EAGAIN; break; } if (signal_pending(current)) { len = sock_intr_errno(timeo); break; } sk_wait_data(sk, &timeo); continue; found_ok_skb: if (len > skb->len) len = skb->len; else if (len < skb->len) msg->msg_flags |= MSG_TRUNC; if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) { /* Exception. Bailout! */ len = -EFAULT; break; } if (flags & MSG_TRUNC) len = skb->len; found_fin_ok: if (!(flags & MSG_PEEK)) sk_eat_skb(sk, skb, 0); break; } while (1); out: release_sock(sk); return len; }
int ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { struct ipv6_pinfo *np = inet6_sk(sk); int len; int val; if (level == SOL_IP && sk->sk_type != SOCK_RAW) return udp_prot.getsockopt(sk, level, optname, optval, optlen); if(level!=SOL_IPV6) return -ENOPROTOOPT; if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; break; case MCAST_MSFILTER: { struct group_filter gsf; int err; if (len < GROUP_FILTER_SIZE(0)) return -EINVAL; if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) return -EFAULT; lock_sock(sk); err = ip6_mc_msfget(sk, &gsf, (struct group_filter __user *)optval, optlen); release_sock(sk); return err; } case IPV6_PKTOPTIONS: { struct msghdr msg; struct sk_buff *skb; if (sk->sk_type != SOCK_STREAM) return -ENOPROTOOPT; msg.msg_control = optval; msg.msg_controllen = len; msg.msg_flags = 0; lock_sock(sk); skb = np->pktoptions; if (skb) atomic_inc(&skb->users); release_sock(sk); if (skb) { int err = datagram_recv_ctl(sk, &msg, skb); kfree_skb(skb); if (err) return err; } else { if (np->rxopt.bits.rxinfo) { struct in6_pktinfo src_info; src_info.ipi6_ifindex = np->mcast_oif; ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); } if (np->rxopt.bits.rxhlim) { int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } } len -= msg.msg_controllen; return put_user(len, optlen); } case IPV6_MTU: { struct dst_entry *dst; val = 0; lock_sock(sk); dst = sk_dst_get(sk); if (dst) { val = dst_mtu(dst); dst_release(dst); } release_sock(sk); if (!val) return -ENOTCONN; break; } case IPV6_V6ONLY: val = np->ipv6only; break; case IPV6_PKTINFO: val = np->rxopt.bits.rxinfo; break; case IPV6_HOPLIMIT: val = np->rxopt.bits.rxhlim; break; case IPV6_RTHDR: val = np->rxopt.bits.srcrt; break; case IPV6_HOPOPTS: val = np->rxopt.bits.hopopts; break; case IPV6_DSTOPTS: val = np->rxopt.bits.dstopts; break; case IPV6_FLOWINFO: val = np->rxopt.bits.rxflow; break; case IPV6_UNICAST_HOPS: val = np->hop_limit; break; case IPV6_MULTICAST_HOPS: val = np->mcast_hops; break; case IPV6_MULTICAST_LOOP: val = np->mc_loop; break; case IPV6_MULTICAST_IF: val = np->mcast_oif; break; case IPV6_MTU_DISCOVER: val = np->pmtudisc; break; case IPV6_RECVERR: val = np->recverr; break; case IPV6_FLOWINFO_SEND: val = np->sndflow; break; default: #ifdef CONFIG_NETFILTER lock_sock(sk); val = nf_getsockopt(sk, PF_INET6, optname, optval, &len); release_sock(sk); if (val >= 0) val = put_user(len, optlen); return val; #else return -EINVAL; #endif } len = min_t(unsigned int, sizeof(int), len); if(put_user(len, optlen)) return -EFAULT; if(copy_to_user(optval,&val,len)) return -EFAULT; return 0; }
int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct icmp6hdr user_icmph; int addr_type; struct in6_addr *daddr; int iif = 0; struct flowi6 fl6; int err; int hlimit; struct dst_entry *dst; struct rt6_info *rt; struct pingfakehdr pfh; pr_debug("ping_v6_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num); err = ping_common_sendmsg(AF_INET6, msg, len, &user_icmph, sizeof(user_icmph)); if (err) return err; if (msg->msg_name) { struct sockaddr_in6 *u = (struct sockaddr_in6 *) msg->msg_name; if (msg->msg_namelen < sizeof(struct sockaddr_in6) || u->sin6_family != AF_INET6) { return -EINVAL; } if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != u->sin6_scope_id) { return -EINVAL; } daddr = &(u->sin6_addr); iif = u->sin6_scope_id; } else { if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; daddr = &np->daddr; } if (!iif) iif = sk->sk_bound_dev_if; addr_type = ipv6_addr_type(daddr); if (__ipv6_addr_needs_scope_id(addr_type) && !iif) return -EINVAL; if (addr_type & IPV6_ADDR_MAPPED) return -EINVAL; /* TODO: use ip6_datagram_send_ctl to get options from cmsg */ memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_proto = IPPROTO_ICMPV6; fl6.saddr = np->saddr; fl6.daddr = *daddr; fl6.flowi6_mark = sk->sk_mark; fl6.flowi6_uid = sock_i_uid(sk); fl6.fl6_icmp_type = user_icmph.icmp6_type; fl6.fl6_icmp_code = user_icmph.icmp6_code; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) fl6.flowi6_oif = np->mcast_oif; else if (!fl6.flowi6_oif) fl6.flowi6_oif = np->ucast_oif; dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, 1); if (IS_ERR(dst)) return PTR_ERR(dst); rt = (struct rt6_info *) dst; np = inet6_sk(sk); if (!np) return -EBADF; if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) fl6.flowi6_oif = np->mcast_oif; else if (!fl6.flowi6_oif) fl6.flowi6_oif = np->ucast_oif; pfh.icmph.type = user_icmph.icmp6_type; pfh.icmph.code = user_icmph.icmp6_code; pfh.icmph.checksum = 0; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; pfh.iov = msg->msg_iov; pfh.wcheck = 0; pfh.family = AF_INET6; if (ipv6_addr_is_multicast(&fl6.daddr)) hlimit = np->mcast_hops; else hlimit = np->hop_limit; if (hlimit < 0) hlimit = ip6_dst_hoplimit(dst); lock_sock(sk); err = ip6_append_data(sk, ping_getfrag, &pfh, len, 0, hlimit, np->tclass, NULL, &fl6, rt, MSG_DONTWAIT, np->dontfrag); if (err) { ICMP6_INC_STATS_BH(sock_net(sk), rt->rt6i_idev, ICMP6_MIB_OUTERRORS); ip6_flush_pending_frames(sk); } else { err = icmpv6_push_pending_frames(sk, &fl6, (struct icmp6hdr *) &pfh.icmph, len); } release_sock(sk); if (err) return err; return len; }
static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len,int flags) { DEFINE_WAIT(wait); struct sock *sk = sock->sk; struct sockaddr_atmsvc *addr; struct atm_vcc *vcc = ATM_SD(sock); int error; DPRINTK("svc_connect %p\n",vcc); lock_sock(sk); if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { error = -EINVAL; goto out; } switch (sock->state) { default: error = -EINVAL; goto out; case SS_CONNECTED: error = -EISCONN; goto out; case SS_CONNECTING: if (test_bit(ATM_VF_WAITING, &vcc->flags)) { error = -EALREADY; goto out; } sock->state = SS_UNCONNECTED; if (sk->sk_err) { error = -sk->sk_err; goto out; } break; case SS_UNCONNECTED: addr = (struct sockaddr_atmsvc *) sockaddr; if (addr->sas_family != AF_ATMSVC) { error = -EAFNOSUPPORT; goto out; } if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { error = -EBADFD; goto out; } if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) { error = -EINVAL; goto out; } if (!vcc->qos.txtp.traffic_class && !vcc->qos.rxtp.traffic_class) { error = -EINVAL; goto out; } vcc->remote = *addr; set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); if (flags & O_NONBLOCK) { finish_wait(sk->sk_sleep, &wait); sock->state = SS_CONNECTING; error = -EINPROGRESS; goto out; } error = 0; while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { schedule(); if (!signal_pending(current)) { prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); continue; } DPRINTK("*ABORT*\n"); /* * This is tricky: * Kernel ---close--> Demon * Kernel <--close--- Demon * or * Kernel ---close--> Demon * Kernel <--error--- Demon * or * Kernel ---close--> Demon * Kernel <--okay---- Demon * Kernel <--close--- Demon */ sigd_enq(vcc,as_close,NULL,NULL,NULL); while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); schedule(); } if (!sk->sk_err) while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); schedule(); } clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_RELEASED,&vcc->flags); clear_bit(ATM_VF_CLOSE,&vcc->flags); /* we're gone now but may connect later */ error = -EINTR; break; } finish_wait(sk->sk_sleep, &wait); if (error) goto out; if (!sigd) { error = -EUNATCH; goto out; } if (sk->sk_err) { error = -sk->sk_err; goto out; } } /* * Not supported yet * * #ifndef CONFIG_SINGLE_SIGITF */ vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); vcc->qos.txtp.pcr = 0; vcc->qos.txtp.min_pcr = 0; /* * #endif */ if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci))) sock->state = SS_CONNECTED; else (void) svc_disconnect(vcc); out: release_sock(sk); return error; }
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; struct sockaddr_l2 la; int len, err = 0; BT_DBG("sk %p", sk); if (!addr || addr->sa_family != AF_BLUETOOTH) return -EINVAL; memset(&la, 0, sizeof(la)); len = min_t(unsigned int, sizeof(la), alen); memcpy(&la, addr, len); if (la.l2_cid && la.l2_psm) return -EINVAL; lock_sock(sk); if (sk->sk_state != BT_OPEN) { err = -EBADFD; goto done; } if (la.l2_psm) { __u16 psm = __le16_to_cpu(la.l2_psm); /* PSM must be odd and lsb of upper byte must be 0 */ if ((psm & 0x0101) != 0x0001) { err = -EINVAL; goto done; } /* Restrict usage of well-known PSMs */ if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { err = -EACCES; goto done; } } write_lock_bh(&l2cap_sk_list.lock); if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) { err = -EADDRINUSE; } else { /* Save source address */ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->sport = la.l2_psm; sk->sk_state = BT_BOUND; if (__le16_to_cpu(la.l2_psm) == 0x0001 || __le16_to_cpu(la.l2_psm) == 0x0003) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; } if (la.l2_cid) l2cap_pi(sk)->scid = la.l2_cid; write_unlock_bh(&l2cap_sk_list.lock); done: release_sock(sk); return err; }
static int svc_accept(struct socket *sock,struct socket *newsock,int flags) { struct sock *sk = sock->sk; struct sk_buff *skb; struct atmsvc_msg *msg; struct atm_vcc *old_vcc = ATM_SD(sock); struct atm_vcc *new_vcc; int error; lock_sock(sk); error = svc_create(newsock,0); if (error) goto out; new_vcc = ATM_SD(newsock); DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); while (1) { DEFINE_WAIT(wait); prepare_to_wait(old_vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) && sigd) { if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) { error = -sk->sk_err; break; } if (flags & O_NONBLOCK) { error = -EAGAIN; break; } release_sock(sk); schedule(); lock_sock(sk); if (signal_pending(current)) { error = -ERESTARTSYS; break; } prepare_to_wait(old_vcc->sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } finish_wait(old_vcc->sk->sk_sleep, &wait); if (error) goto out; if (!skb) { error = -EUNATCH; goto out; } msg = (struct atmsvc_msg *) skb->data; new_vcc->qos = msg->qos; set_bit(ATM_VF_HASQOS,&new_vcc->flags); new_vcc->remote = msg->svc; new_vcc->local = msg->local; new_vcc->sap = msg->sap; error = vcc_connect(newsock, msg->pvc.sap_addr.itf, msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci); dev_kfree_skb(skb); old_vcc->sk->sk_ack_backlog--; if (error) { sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, &old_vcc->qos,error); error = error == -EAGAIN ? -EBUSY : error; goto out; } /* wait should be short, so we ignore the non-blocking flag */ set_bit(ATM_VF_WAITING, &new_vcc->flags); prepare_to_wait(new_vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) { release_sock(sk); schedule(); lock_sock(sk); prepare_to_wait(new_vcc->sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(new_vcc->sk->sk_sleep, &wait); if (!sigd) { error = -EUNATCH; goto out; } if (!new_vcc->sk->sk_err) break; if (new_vcc->sk->sk_err != ERESTARTSYS) { error = -new_vcc->sk->sk_err; goto out; } } newsock->state = SS_CONNECTED; out: release_sock(sk); return error; }
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct l2cap_options opts; struct l2cap_conninfo cinfo; int len, err = 0; u32 opt; BT_DBG("sk %p", sk); if (get_user(len, optlen)) return -EFAULT; lock_sock(sk); switch (optname) { case L2CAP_OPTIONS: memset(&opts, 0, sizeof(opts)); opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; opts.max_tx = l2cap_pi(sk)->max_tx; opts.txwin_size = l2cap_pi(sk)->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) err = -EFAULT; break; case L2CAP_LM: switch (l2cap_pi(sk)->sec_level) { case BT_SECURITY_LOW: opt = L2CAP_LM_AUTH; break; case BT_SECURITY_MEDIUM: opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; break; case BT_SECURITY_HIGH: opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE; break; default: opt = 0; break; } if (l2cap_pi(sk)->role_switch) opt |= L2CAP_LM_MASTER; if (l2cap_pi(sk)->force_reliable) opt |= L2CAP_LM_RELIABLE; if (l2cap_pi(sk)->flushable) opt |= L2CAP_LM_FLUSHABLE; if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; break; case L2CAP_CONNINFO: if (sk->sk_state != BT_CONNECTED && !(sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup)) { err = -ENOTCONN; break; } cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) err = -EFAULT; break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct inet_sock *inet = inet_sk(sk); struct ipcm_cookie ipc; struct rtable *rt = NULL; struct flowi4 fl4; int free = 0; __be32 daddr; __be32 saddr; u8 tos; int err; struct ip_options_data opt_copy; err = -EMSGSIZE; if (len > 0xFFFF) goto out; /* * Check the flags. */ err = -EOPNOTSUPP; if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message */ goto out; /* compatibility */ /* * Get and verify the address. */ if (msg->msg_namelen) { struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; err = -EINVAL; if (msg->msg_namelen < sizeof(*usin)) goto out; if (usin->sin_family != AF_INET) { pr_info_once("%s: %s forgot to set AF_INET. Fix it!\n", __func__, current->comm); err = -EAFNOSUPPORT; if (usin->sin_family) goto out; } daddr = usin->sin_addr.s_addr; /* ANK: I did not forget to get protocol from port field. * I just do not know, who uses this weirdness. * IP_HDRINCL is much more convenient. */ } else { err = -EDESTADDRREQ; if (sk->sk_state != TCP_ESTABLISHED) goto out; daddr = inet->inet_daddr; } ipc.addr = inet->inet_saddr; ipc.opt = NULL; ipc.tx_flags = 0; ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { err = ip_cmsg_send(sock_net(sk), msg, &ipc); if (err) goto out; if (ipc.opt) free = 1; } saddr = ipc.addr; ipc.addr = daddr; if (!ipc.opt) { struct ip_options_rcu *inet_opt; rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); if (inet_opt) { memcpy(&opt_copy, inet_opt, sizeof(*inet_opt) + inet_opt->opt.optlen); ipc.opt = &opt_copy.opt; } rcu_read_unlock(); } if (ipc.opt) { err = -EINVAL; /* Linux does not mangle headers on raw sockets, * so that IP options + IP_HDRINCL is non-sense. */ if (inet->hdrincl) goto done; if (ipc.opt->opt.srr) { if (!daddr) goto done; daddr = ipc.opt->opt.faddr; } } tos = RT_CONN_FLAGS(sk); if (msg->msg_flags & MSG_DONTROUTE) tos |= RTO_ONLINK; if (ipv4_is_multicast(daddr)) { if (!ipc.oif) ipc.oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; } else if (!ipc.oif) ipc.oif = inet->uc_index; flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0, sock_i_uid(sk)); if (!inet->hdrincl) { err = raw_probe_proto_opt(&fl4, msg); if (err) goto done; } security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(sock_net(sk), &fl4, sk); if (IS_ERR(rt)) { err = PTR_ERR(rt); rt = NULL; goto done; } err = -EACCES; if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) goto done; if (msg->msg_flags & MSG_CONFIRM) goto do_confirm; back_from_confirm: if (inet->hdrincl) err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len, &rt, msg->msg_flags); else { if (!ipc.addr) ipc.addr = fl4.daddr; lock_sock(sk); err = ip_append_data(sk, &fl4, ip_generic_getfrag, msg->msg_iov, len, 0, &ipc, &rt, msg->msg_flags); if (err) ip_flush_pending_frames(sk); else if (!(msg->msg_flags & MSG_MORE)) { err = ip_push_pending_frames(sk, &fl4); if (err == -ENOBUFS && !inet->recverr) err = 0; } release_sock(sk); } done: if (free) kfree(ipc.opt); ip_rt_put(rt); out: if (err < 0) return err; return len; do_confirm: dst_confirm(&rt->dst); if (!(msg->msg_flags & MSG_PROBE) || len) goto back_from_confirm; err = 0; goto done; }
static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct l2cap_options opts; int len, le_sock, err = 0; u32 opt; BT_DBG("sk %p", sk); lock_sock(sk); le_sock = l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA; switch (optname) { case L2CAP_OPTIONS: if (sk->sk_state == BT_CONNECTED && !le_sock) { err = -EINVAL; break; } opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; opts.max_tx = l2cap_pi(sk)->max_tx; opts.txwin_size = l2cap_pi(sk)->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { err = -EFAULT; break; } if ((opts.imtu || opts.omtu) && le_sock && (sk->sk_state == BT_CONNECTED)) { if (opts.imtu >= L2CAP_LE_DEFAULT_MTU) l2cap_pi(sk)->imtu = opts.imtu; if (opts.omtu >= L2CAP_LE_DEFAULT_MTU) l2cap_pi(sk)->omtu = opts.omtu; if (opts.imtu < L2CAP_LE_DEFAULT_MTU || opts.omtu < L2CAP_LE_DEFAULT_MTU) err = -EINVAL; break; } if (opts.txwin_size < 1 || opts.txwin_size > L2CAP_TX_WIN_MAX_EXTENDED) { err = -EINVAL; break; } l2cap_pi(sk)->mode = opts.mode; switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; case L2CAP_MODE_STREAMING: if (!disable_ertm) { /* No fallback to ERTM or Basic mode */ l2cap_pi(sk)->conf_state |= L2CAP_CONF_STATE2_DEVICE; break; } err = -EINVAL; break; case L2CAP_MODE_ERTM: if (!disable_ertm) break; /* fall through */ default: err = -EINVAL; break; } l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; l2cap_pi(sk)->fcs = opts.fcs; l2cap_pi(sk)->max_tx = opts.max_tx; l2cap_pi(sk)->tx_win = opts.txwin_size; l2cap_pi(sk)->flush_to = opts.flush_to; break; case L2CAP_LM: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } if (opt & L2CAP_LM_AUTH) l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; if (opt & L2CAP_LM_SECURE) l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); l2cap_pi(sk)->flushable = (opt & L2CAP_LM_FLUSHABLE); break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
static void raw_destroy(struct sock *sk) { lock_sock(sk); ip_flush_pending_frames(sk); release_sock(sk); }
static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb; struct sk_buff_head seg_queue; int err; u8 amp_id; BT_DBG("sock %p, sk %p", sock, sk); err = sock_error(sk); if (err) return err; if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; lock_sock(sk); if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; goto done; } /* Connectionless channel */ if (sk->sk_type == SOCK_DGRAM) { skb = l2cap_create_connless_pdu(sk, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { l2cap_do_send(sk, skb); err = len; } goto done; } switch (pi->mode) { case L2CAP_MODE_BASIC: /* Check outgoing MTU */ if (len > pi->omtu) { err = -EMSGSIZE; goto done; } /* Create a basic PDU */ skb = l2cap_create_basic_pdu(sk, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } l2cap_do_send(sk, skb); err = len; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Check outgoing MTU */ if (len > pi->omtu) { err = -EMSGSIZE; goto done; } __skb_queue_head_init(&seg_queue); /* Do segmentation before calling in to the state machine, * since it's possible to block while waiting for memory * allocation. */ amp_id = pi->amp_id; err = l2cap_segment_sdu(sk, &seg_queue, msg, len, 0); /* The socket lock is released while segmenting, so check * that the socket is still connected */ if (sk->sk_state != BT_CONNECTED) { __skb_queue_purge(&seg_queue); err = -ENOTCONN; } if (err) { BT_DBG("Error %d, sk_sndbuf %d, sk_wmem_alloc %d", err, sk->sk_sndbuf, atomic_read(&sk->sk_wmem_alloc)); break; } if (pi->amp_id != amp_id) { /* Channel moved while unlocked. Resegment. */ err = l2cap_resegment_queue(sk, &seg_queue); if (err) break; } if (pi->mode != L2CAP_MODE_STREAMING) err = l2cap_ertm_tx(sk, 0, &seg_queue, L2CAP_ERTM_EVENT_DATA_REQUEST); else err = l2cap_strm_tx(sk, &seg_queue); if (!err) err = len; /* If the skbs were not queued for sending, they'll still be in * seg_queue and need to be purged. */ __skb_queue_purge(&seg_queue); break; default: BT_DBG("bad state %1.1x", pi->mode); err = -EBADFD; } done: release_sock(sk); return err; }
static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) { struct ncp_mount_data_kernel data; struct ncp_server *server; struct file *ncp_filp; struct inode *root_inode; struct inode *sock_inode; struct socket *sock; int error; int default_bufsize; #ifdef CONFIG_NCPFS_PACKET_SIGNING int options; #endif struct ncp_entry_info finfo; memset(&data, 0, sizeof(data)); server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL); if (!server) return -ENOMEM; sb->s_fs_info = server; error = -EFAULT; if (raw_data == NULL) goto out; switch (*(int*)raw_data) { case NCP_MOUNT_VERSION: { struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data; data.flags = md->flags; data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE; data.mounted_uid = md->mounted_uid; data.wdog_pid = find_get_pid(md->wdog_pid); data.ncp_fd = md->ncp_fd; data.time_out = md->time_out; data.retry_count = md->retry_count; data.uid = md->uid; data.gid = md->gid; data.file_mode = md->file_mode; data.dir_mode = md->dir_mode; data.info_fd = -1; memcpy(data.mounted_vol, md->mounted_vol, NCP_VOLNAME_LEN+1); } break; case NCP_MOUNT_VERSION_V4: { struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data; data.flags = md->flags; data.mounted_uid = md->mounted_uid; data.wdog_pid = find_get_pid(md->wdog_pid); data.ncp_fd = md->ncp_fd; data.time_out = md->time_out; data.retry_count = md->retry_count; data.uid = md->uid; data.gid = md->gid; data.file_mode = md->file_mode; data.dir_mode = md->dir_mode; data.info_fd = -1; } break; default: error = -ECHRNG; if (memcmp(raw_data, "vers", 4) == 0) { error = ncp_parse_options(&data, raw_data); } if (error) goto out; break; } error = -EBADF; ncp_filp = fget(data.ncp_fd); if (!ncp_filp) goto out; error = -ENOTSOCK; sock_inode = ncp_filp->f_path.dentry->d_inode; if (!S_ISSOCK(sock_inode->i_mode)) goto out_fput; sock = SOCKET_I(sock_inode); if (!sock) goto out_fput; if (sock->type == SOCK_STREAM) default_bufsize = 0xF000; else default_bufsize = 1024; sb->s_flags |= MS_NODIRATIME; /* probably even noatime */ sb->s_maxbytes = 0xFFFFFFFFU; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = NCP_SUPER_MAGIC; sb->s_op = &ncp_sops; sb->s_d_op = &ncp_dentry_operations; sb->s_bdi = &server->bdi; server = NCP_SBP(sb); memset(server, 0, sizeof(*server)); error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY); if (error) goto out_fput; server->ncp_filp = ncp_filp; server->ncp_sock = sock; if (data.info_fd != -1) { struct socket *info_sock; error = -EBADF; server->info_filp = fget(data.info_fd); if (!server->info_filp) goto out_bdi; error = -ENOTSOCK; sock_inode = server->info_filp->f_path.dentry->d_inode; if (!S_ISSOCK(sock_inode->i_mode)) goto out_fput2; info_sock = SOCKET_I(sock_inode); if (!info_sock) goto out_fput2; error = -EBADFD; if (info_sock->type != SOCK_STREAM) goto out_fput2; server->info_sock = info_sock; } /* server->lock = 0; */ mutex_init(&server->mutex); server->packet = NULL; /* server->buffer_size = 0; */ /* server->conn_status = 0; */ /* server->root_dentry = NULL; */ /* server->root_setuped = 0; */ mutex_init(&server->root_setup_lock); #ifdef CONFIG_NCPFS_PACKET_SIGNING /* server->sign_wanted = 0; */ /* server->sign_active = 0; */ #endif init_rwsem(&server->auth_rwsem); server->auth.auth_type = NCP_AUTH_NONE; /* server->auth.object_name_len = 0; */ /* server->auth.object_name = NULL; */ /* server->auth.object_type = 0; */ /* server->priv.len = 0; */ /* server->priv.data = NULL; */ server->m = data; /* Although anything producing this is buggy, it happens now because of PATH_MAX changes.. */ if (server->m.time_out < 1) { server->m.time_out = 10; printk(KERN_INFO "You need to recompile your ncpfs utils..\n"); } server->m.time_out = server->m.time_out * HZ / 100; server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG; server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR; #ifdef CONFIG_NCPFS_NLS /* load the default NLS charsets */ server->nls_vol = load_nls_default(); server->nls_io = load_nls_default(); #endif /* CONFIG_NCPFS_NLS */ atomic_set(&server->dentry_ttl, 0); /* no caching */ INIT_LIST_HEAD(&server->tx.requests); mutex_init(&server->rcv.creq_mutex); server->tx.creq = NULL; server->rcv.creq = NULL; init_timer(&server->timeout_tm); #undef NCP_PACKET_SIZE #define NCP_PACKET_SIZE 131072 error = -ENOMEM; server->packet_size = NCP_PACKET_SIZE; server->packet = vmalloc(NCP_PACKET_SIZE); if (server->packet == NULL) goto out_nls; server->txbuf = vmalloc(NCP_PACKET_SIZE); if (server->txbuf == NULL) goto out_packet; server->rxbuf = vmalloc(NCP_PACKET_SIZE); if (server->rxbuf == NULL) goto out_txbuf; lock_sock(sock->sk); server->data_ready = sock->sk->sk_data_ready; server->write_space = sock->sk->sk_write_space; server->error_report = sock->sk->sk_error_report; sock->sk->sk_user_data = server; sock->sk->sk_data_ready = ncp_tcp_data_ready; sock->sk->sk_error_report = ncp_tcp_error_report; if (sock->type == SOCK_STREAM) { server->rcv.ptr = (unsigned char*)&server->rcv.buf; server->rcv.len = 10; server->rcv.state = 0; INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc); INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc); sock->sk->sk_write_space = ncp_tcp_write_space; } else { INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc); INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc); server->timeout_tm.data = (unsigned long)server; server->timeout_tm.function = ncpdgram_timeout_call; } release_sock(sock->sk); ncp_lock_server(server); error = ncp_connect(server); ncp_unlock_server(server); if (error < 0) goto out_rxbuf; DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */ #ifdef CONFIG_NCPFS_PACKET_SIGNING if (ncp_negotiate_size_and_options(server, default_bufsize, NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0) { if (options != NCP_DEFAULT_OPTIONS) { if (ncp_negotiate_size_and_options(server, default_bufsize, options & 2, &(server->buffer_size), &options) != 0) { goto out_disconnect; } } ncp_lock_server(server); if (options & 2) server->sign_wanted = 1; ncp_unlock_server(server); } else #endif /* CONFIG_NCPFS_PACKET_SIGNING */ if (ncp_negotiate_buffersize(server, default_bufsize, &(server->buffer_size)) != 0) goto out_disconnect; DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size); memset(&finfo, 0, sizeof(finfo)); finfo.i.attributes = aDIR; finfo.i.dataStreamSize = 0; /* ignored */ finfo.i.dirEntNum = 0; finfo.i.DosDirNum = 0; #ifdef CONFIG_NCPFS_SMALLDOS finfo.i.NSCreator = NW_NS_DOS; #endif finfo.volume = NCP_NUMBER_OF_VOLUMES; /* set dates of mountpoint to Jan 1, 1986; 00:00 */ finfo.i.creationTime = finfo.i.modifyTime = cpu_to_le16(0x0000); finfo.i.creationDate = finfo.i.modifyDate = finfo.i.lastAccessDate = cpu_to_le16(0x0C21); finfo.i.nameLen = 0; finfo.i.entryName[0] = '\0'; finfo.opened = 0; finfo.ino = 2; /* tradition */ server->name_space[finfo.volume] = NW_NS_DOS; error = -ENOMEM; root_inode = ncp_iget(sb, &finfo); if (!root_inode) goto out_disconnect; DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); sb->s_root = d_make_root(root_inode); if (!sb->s_root) goto out_disconnect; return 0; out_disconnect: ncp_lock_server(server); ncp_disconnect(server); ncp_unlock_server(server); out_rxbuf: ncp_stop_tasks(server); vfree(server->rxbuf); out_txbuf: vfree(server->txbuf); out_packet: vfree(server->packet); out_nls: #ifdef CONFIG_NCPFS_NLS unload_nls(server->nls_io); unload_nls(server->nls_vol); #endif mutex_destroy(&server->rcv.creq_mutex); mutex_destroy(&server->root_setup_lock); mutex_destroy(&server->mutex); out_fput2: if (server->info_filp) fput(server->info_filp); out_bdi: bdi_destroy(&server->bdi); out_fput: /* 23/12/1998 Marcin Dalecki <*****@*****.**>: * * The previously used put_filp(ncp_filp); was bogus, since * it doesn't perform proper unlocking. */ fput(ncp_filp); out: put_pid(data.wdog_pid); sb->s_fs_info = NULL; kfree(server); return error; }
static int raw_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); struct can_filter *filter = NULL; /* dyn. alloc'ed filters */ struct can_filter sfilter; /* single filter */ struct net_device *dev = NULL; can_err_mask_t err_mask = 0; int count = 0; int err = 0; if (level != SOL_CAN_RAW) return -EINVAL; if (optlen < 0) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: if (optlen % sizeof(struct can_filter) != 0) return -EINVAL; count = optlen / sizeof(struct can_filter); if (count > 1) { /* filter does not fit into dfilter => alloc space */ filter = kmalloc(optlen, GFP_KERNEL); if (!filter) return -ENOMEM; if (copy_from_user(filter, optval, optlen)) { kfree(filter); return -EFAULT; } } else if (count == 1) { if (copy_from_user(&sfilter, optval, optlen)) return -EFAULT; } lock_sock(sk); if (ro->bound && ro->ifindex) dev = dev_get_by_index(&init_net, ro->ifindex); if (ro->bound) { /* (try to) register the new filters */ if (count == 1) err = raw_enable_filters(dev, sk, &sfilter, 1); else err = raw_enable_filters(dev, sk, filter, count); if (err) { if (count > 1) kfree(filter); goto out_fil; } /* remove old filter registrations */ raw_disable_filters(dev, sk, ro->filter, ro->count); } /* remove old filter space */ if (ro->count > 1) kfree(ro->filter); /* link new filters to the socket */ if (count == 1) { /* copy filter data for single filter */ ro->dfilter = sfilter; filter = &ro->dfilter; } ro->filter = filter; ro->count = count; out_fil: if (dev) dev_put(dev); release_sock(sk); break; case CAN_RAW_ERR_FILTER: if (optlen != sizeof(err_mask)) return -EINVAL; if (copy_from_user(&err_mask, optval, optlen)) return -EFAULT; err_mask &= CAN_ERR_MASK; lock_sock(sk); if (ro->bound && ro->ifindex) dev = dev_get_by_index(&init_net, ro->ifindex); /* remove current error mask */ if (ro->bound) { /* (try to) register the new err_mask */ err = raw_enable_errfilter(dev, sk, err_mask); if (err) goto out_err; /* remove old err_mask registration */ raw_disable_errfilter(dev, sk, ro->err_mask); } /* link new err_mask to the socket */ ro->err_mask = err_mask; out_err: if (dev) dev_put(dev); release_sock(sk); break; case CAN_RAW_LOOPBACK: if (optlen != sizeof(ro->loopback)) return -EINVAL; if (copy_from_user(&ro->loopback, optval, optlen)) return -EFAULT; break; case CAN_RAW_RECV_OWN_MSGS: if (optlen != sizeof(ro->recv_own_msgs)) return -EINVAL; if (copy_from_user(&ro->recv_own_msgs, optval, optlen)) return -EFAULT; break; default: return -ENOPROTOOPT; } return err; }
static int recv_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; struct tipc_msg *msg; long timeout; unsigned int sz; int sz_to_copy, target, needed; int sz_copied = 0; u32 err; int res = 0; /* Catch invalid receive attempts */ if (unlikely(!buf_len)) return -EINVAL; lock_sock(sk); if (unlikely((sock->state == SS_UNCONNECTED) || (sock->state == SS_CONNECTING))) { res = -ENOTCONN; goto exit; } target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); restart: /* Look for a message in receive queue; wait if necessary */ while (skb_queue_empty(&sk->sk_receive_queue)) { if (sock->state == SS_DISCONNECTING) { res = -ENOTCONN; goto exit; } if (timeout <= 0L) { res = timeout ? timeout : -EWOULDBLOCK; goto exit; } release_sock(sk); timeout = wait_event_interruptible_timeout(*sk_sleep(sk), tipc_rx_ready(sock), timeout); lock_sock(sk); } /* Look at first message in receive queue */ buf = skb_peek(&sk->sk_receive_queue); msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); /* Discard an empty non-errored message & try again */ if ((!sz) && (!err)) { advance_rx_queue(sk); goto restart; } /* Optionally capture sender's address & ancillary data of first msg */ if (sz_copied == 0) { set_orig_addr(m, msg); res = anc_data_recv(m, msg, tport); if (res) goto exit; } /* Capture message data (if valid) & compute return value (always) */ if (!err) { u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); sz -= offset; needed = (buf_len - sz_copied); sz_to_copy = (sz <= needed) ? sz : needed; res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset, m->msg_iov, sz_to_copy); if (res) goto exit; sz_copied += sz_to_copy; if (sz_to_copy < sz) { if (!(flags & MSG_PEEK)) TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)(offset + sz_to_copy); goto exit; } } else { if (sz_copied != 0) goto exit; /* can't add error msg to valid data */ if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) res = 0; else res = -ECONNRESET; } /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) tipc_acknowledge(tport->ref, tport->conn_unacked); advance_rx_queue(sk); } /* Loop around if more data is required */ if ((sz_copied < buf_len) && /* didn't get all requested data */ (!skb_queue_empty(&sk->sk_receive_queue) || (sz_copied < target)) && /* and more is ready or required */ (!(flags & MSG_PEEK)) && /* and aren't just peeking at data */ (!err)) /* and haven't reached a FIN */ goto restart; exit: release_sock(sk); return sz_copied ? sz_copied : res; }