Commit message: net: rework recvmsg handler msg_name and msg_namelen logic

This patch now always passes msg->msg_namelen as 0. recvmsg handlers must
set msg_namelen to the proper size <= sizeof(struct sockaddr_storage)
to return msg_name to the user.

This prevents numerous uninitialized memory leaks we had in the
recvmsg handlers and makes it harder for new code to accidentally leak
uninitialized memory.

Optimize for the case recvfrom is called with NULL as address. We don't
need to copy the address at all, so set it to NULL before invoking the
recvmsg handler. We can do so, because all the recvmsg handlers must
cope with the case a plain read() is called on them. read() also sets
msg_name to NULL.

Also document these changes in include/linux/net.h as suggested by David
Miller.

Changes since RFC:

Set msg->msg_name = NULL if user specified a NULL in msg_name but had a
non-null msg_namelen in verify_iovec/verify_compat_iovec. This doesn't
affect sendto as it would bail out earlier while trying to copy-in the
address. It also more naturally reflects the logic by the callers of
verify_iovec.

With this change in place I could remove "
if (!uaddr || msg_sys->msg_namelen == 0)
	msg->msg_name = NULL
".

This change does not alter the user visible error logic as we ignore
msg_namelen as long as msg_name is NULL.

Also remove two unnecessary curly brackets in ___sys_recvmsg and change
comments to netdev style.

Cc: David Miller <davem@davemloft.net>
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
CVE: CVE-2013-7270
CWE: CWE-20
Vulnerability description: The packet_recvmsg function in net/packet/af_packet.c in the Linux kernel before 3.12.4 updates a certain length value before ensuring that an associated data structure has been initialized, which allows local users to obtain sensitive information from kernel memory via a (1) recvfrom, (2) recvmmsg, or (3) recvmsg system call.

Project: linux
File: socket.c

data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
	struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
	struct sock *sk = sock->sk;
	struct sock *csk;
	int err = 0;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
	if (addr_len != sizeof(struct sockaddr_mISDN))
		return -EINVAL;
	if (!maddr || maddr->family != AF_ISDN)
		return -EINVAL;

	lock_sock(sk);

	if (_pms(sk)->dev) {
		err = -EALREADY;
		goto done;
	}
	_pms(sk)->dev = get_mdevice(maddr->dev);
	if (!_pms(sk)->dev) {
		err = -ENODEV;
		goto done;
	}

	if (sk->sk_protocol < ISDN_P_B_START) {
		read_lock_bh(&data_sockets.lock);
		sk_for_each(csk, &data_sockets.head) {
			if (sk == csk)
				continue;
			if (_pms(csk)->dev != _pms(sk)->dev)
				continue;
			if (csk->sk_protocol >= ISDN_P_B_START)
				continue;
			if (IS_ISDN_P_TE(csk->sk_protocol)
			    == IS_ISDN_P_TE(sk->sk_protocol))
				continue;
			read_unlock_bh(&data_sockets.lock);
			err = -EBUSY;
			goto done;
		}
		read_unlock_bh(&data_sockets.lock);
	}

	_pms(sk)->ch.send = mISDN_send;
	_pms(sk)->ch.ctrl = mISDN_ctrl;

	switch (sk->sk_protocol) {
	case ISDN_P_TE_S0:
	case ISDN_P_NT_S0:
	case ISDN_P_TE_E1:
	case ISDN_P_NT_E1:
		mISDN_sock_unlink(&data_sockets, sk);
		err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch,
				     sk->sk_protocol, maddr);
		if (err)
			mISDN_sock_link(&data_sockets, sk);
		break;
	case ISDN_P_LAPD_TE:
	case ISDN_P_LAPD_NT:
		err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch,
				      sk->sk_protocol, maddr);
		break;
	case ISDN_P_B_RAW:
	case ISDN_P_B_HDLC:
	case ISDN_P_B_X75SLP:
	case ISDN_P_B_L2DTMF:
	case ISDN_P_B_L2DSP:
	case ISDN_P_B_L2DSPHDLC:
		err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch,
				     sk->sk_protocol, maddr);
		break;
	default:
		err = -EPROTONOSUPPORT;
	}
	if (err)
		goto done;
	sk->sk_state = MISDN_BOUND;
	_pms(sk)->ch.protocol = sk->sk_protocol;

done:
	release_sock(sk);
	return err;
}

Project: linux
File: socket.c

data_sock_create(struct net *net, struct socket *sock, int protocol)
{
	struct sock *sk;

	if (sock->type != SOCK_DGRAM)
		return -ESOCKTNOSUPPORT;

	sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto);
	if (!sk)
		return -ENOMEM;

	sock_init_data(sock, sk);

	sock->ops = &data_sock_ops;
	sock->state = SS_UNCONNECTED;
	sock_reset_flag(sk, SOCK_ZAPPED);

	sk->sk_protocol = protocol;
	sk->sk_state    = MISDN_OPEN;
	mISDN_sock_link(&data_sockets, sk);

	return 0;
}

Project: linux
File: socket.c

static int data_sock_getsockopt(struct socket *sock, int level, int optname,
				char __user *optval, int __user *optlen)
{
	struct sock *sk = sock->sk;
	int len, opt;

	if (get_user(len, optlen))
		return -EFAULT;

	if (len != sizeof(char))
		return -EINVAL;

	switch (optname) {
	case MISDN_TIME_STAMP:
		if (_pms(sk)->cmask & MISDN_TIME_STAMP)
			opt = 1;
		else
			opt = 0;

		if (put_user(opt, optval))
			return -EFAULT;
		break;
	default:
		return -ENOPROTOOPT;
	}

	return 0;
}

Project: linux
File: socket.c

misdn_sock_cleanup(void)
{
	sock_unregister(PF_ISDN);
}

Project: linux
File: pppoe.c

static __net_exit void pppoe_exit_net(struct net *net)
{
	remove_proc_entry("pppoe", net->proc_net);
}

Project: linux
File: pppoe.c

static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
{
	struct pppox_sock *po = pppox_sk(sk);
	struct pppox_sock *relay_po;

	/* Backlog receive. Semantics of backlog rcv preclude any code from
	 * executing in lock_sock()/release_sock() bounds; meaning sk->sk_state
	 * can't change.
	 */

	if (sk->sk_state & PPPOX_BOUND) {
		ppp_input(&po->chan, skb);
	} else if (sk->sk_state & PPPOX_RELAY) {
		relay_po = get_item_by_addr(sock_net(sk),
					    &po->pppoe_relay);
		if (relay_po == NULL)
			goto abort_kfree;

		if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0)
			goto abort_put;

		if (!__pppoe_xmit(sk_pppox(relay_po), skb))
			goto abort_put;
	} else {
		if (sock_queue_rcv_skb(sk, skb))
			goto abort_kfree;
	}

	return NET_RX_SUCCESS;

abort_put:
	sock_put(sk_pppox(relay_po));

abort_kfree:
	kfree_skb(skb);
	return NET_RX_DROP;
}

Project: linux
File: pppoe.c

static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
		  struct msghdr *m, size_t total_len)
{
	struct sk_buff *skb;
	struct sock *sk = sock->sk;
	struct pppox_sock *po = pppox_sk(sk);
	int error;
	struct pppoe_hdr hdr;
	struct pppoe_hdr *ph;
	struct net_device *dev;
	char *start;

	lock_sock(sk);
	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
		error = -ENOTCONN;
		goto end;
	}

	hdr.ver = 1;
	hdr.type = 1;
	hdr.code = 0;
	hdr.sid = po->num;

	dev = po->pppoe_dev;

	error = -EMSGSIZE;
	if (total_len > (dev->mtu + dev->hard_header_len))
		goto end;


	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
			   0, GFP_KERNEL);
	if (!skb) {
		error = -ENOMEM;
		goto end;
	}

	/* Reserve space for headers. */
	skb_reserve(skb, dev->hard_header_len);
	skb_reset_network_header(skb);

	skb->dev = dev;

	skb->priority = sk->sk_priority;
	skb->protocol = cpu_to_be16(ETH_P_PPP_SES);

	ph = (struct pppoe_hdr *)skb_put(skb, total_len + sizeof(struct pppoe_hdr));
	start = (char *)&ph->tag[0];

	error = memcpy_fromiovec(start, m->msg_iov, total_len);
	if (error < 0) {
		kfree_skb(skb);
		goto end;
	}

	error = total_len;
	dev_hard_header(skb, dev, ETH_P_PPP_SES,
			po->pppoe_pa.remote, NULL, total_len);

	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));

	ph->length = htons(total_len);

	dev_queue_xmit(skb);

end:
	release_sock(sk);
	return error;
}

Project: linux
File: ddp.c

static __be16 atalk_checksum(const struct sk_buff *skb, int len)
{
	unsigned long sum;

	/* skip header 4 bytes */
	sum = atalk_sum_skb(skb, 4, len-4, 0);

	/* Use 0xFFFF for 0. 0 itself means none */
	return sum ? htons((unsigned short)sum) : htons(0xFFFF);
}

Project: linux
File: ddp.c

static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
		     struct packet_type *pt, struct net_device *orig_dev)
{
	struct ddpehdr *ddp;
	struct sock *sock;
	struct atalk_iface *atif;
	struct sockaddr_at tosat;
	int origlen;
	__u16 len_hops;

	if (!net_eq(dev_net(dev), &init_net))
		goto drop;

	/* Don't mangle buffer if shared */
	if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
		goto out;

	/* Size check and make sure header is contiguous */
	if (!pskb_may_pull(skb, sizeof(*ddp)))
		goto drop;

	ddp = ddp_hdr(skb);

	len_hops = ntohs(ddp->deh_len_hops);

	/* Trim buffer in case of stray trailing data */
	origlen = skb->len;
	skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));

	/*
	 * Size check to see if ddp->deh_len was crap
	 * (Otherwise we'll detonate most spectacularly
	 * in the middle of atalk_checksum() or recvmsg()).
	 */
	if (skb->len < sizeof(*ddp) || skb->len < (len_hops & 1023)) {
		pr_debug("AppleTalk: dropping corrupted frame (deh_len=%u, "
			 "skb->len=%u)\n", len_hops & 1023, skb->len);
		goto drop;
	}

	/*
	 * Any checksums. Note we don't do htons() on this == is assumed to be
	 * valid for net byte orders all over the networking code...
	 */
	if (ddp->deh_sum &&
	    atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
		/* Not a valid AppleTalk frame - dustbin time */
		goto drop;

	/* Check the packet is aimed at us */
	if (!ddp->deh_dnet)	/* Net 0 is 'this network' */
		atif = atalk_find_anynet(ddp->deh_dnode, dev);
	else
		atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);

	if (!atif) {
		/* Not ours, so we route the packet via the correct
		 * AppleTalk iface
		 */
		return atalk_route_packet(skb, dev, ddp, len_hops, origlen);
	}

	/* if IP over DDP is not selected this code will be optimized out */
	if (is_ip_over_ddp(skb))
		return handle_ip_over_ddp(skb);
	/*
	 * Which socket - atalk_search_socket() looks for a *full match*
	 * of the <net, node, port> tuple.
	 */
	tosat.sat_addr.s_net  = ddp->deh_dnet;
	tosat.sat_addr.s_node = ddp->deh_dnode;
	tosat.sat_port	      = ddp->deh_dport;

	sock = atalk_search_socket(&tosat, atif);
	if (!sock) /* But not one of our sockets */
		goto drop;

	/* Queue packet (standard) */
	skb->sk = sock;

	if (sock_queue_rcv_skb(sock, skb) < 0)
		goto drop;

	return NET_RX_SUCCESS;

drop:
	kfree_skb(skb);
out:
	return NET_RX_DROP;

}

Project: linux
File: ddp.c

static int atrtr_ioctl(unsigned int cmd, void __user *arg)
{
	struct rtentry rt;

	if (copy_from_user(&rt, arg, sizeof(rt)))
		return -EFAULT;

	switch (cmd) {
	case SIOCDELRT:
		if (rt.rt_dst.sa_family != AF_APPLETALK)
			return -EINVAL;
		return atrtr_delete(&((struct sockaddr_at *)
				      &rt.rt_dst)->sat_addr);

	case SIOCADDRT: {
		struct net_device *dev = NULL;
		if (rt.rt_dev) {
			char name[IFNAMSIZ];
			if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))
				return -EFAULT;
			name[IFNAMSIZ-1] = '\0';
			dev = __dev_get_by_name(&init_net, name);
			if (!dev)
				return -ENODEV;
		}
		return atrtr_create(&rt, dev);
	}
	}
	return -EINVAL;
}

Project: linux
File: ddp.c

static int ddp_device_event(struct notifier_block *this, unsigned long event,
			    void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);

	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

	if (event == NETDEV_DOWN)
		/* Discard any use of this */
		atalk_dev_down(dev);

	return NOTIFY_DONE;
}

Project: linux
File: ddp.c

static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
		     struct packet_type *pt, struct net_device *orig_dev)
{
	if (!net_eq(dev_net(dev), &init_net))
		goto freeit;

	/* Expand any short form frames */
	if (skb_mac_header(skb)[2] == 1) {
		struct ddpehdr *ddp;
		/* Find our address */
		struct atalk_addr *ap = atalk_find_dev_addr(dev);

		if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
			goto freeit;

		/* Don't mangle buffer if shared */
		if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
			return 0;

		/*
		 * The push leaves us with a ddephdr not an shdr, and
		 * handily the port bytes in the right place preset.
		 */
		ddp = (struct ddpehdr *) skb_push(skb, sizeof(*ddp) - 4);

		/* Now fill in the long header */

		/*
		 * These two first. The mac overlays the new source/dest
		 * network information so we MUST copy these before
		 * we write the network numbers !
		 */

		ddp->deh_dnode = skb_mac_header(skb)[0];     /* From physical header */
		ddp->deh_snode = skb_mac_header(skb)[1];     /* From physical header */

		ddp->deh_dnet  = ap->s_net;	/* Network number */
		ddp->deh_snet  = ap->s_net;
		ddp->deh_sum   = 0;		/* No checksum */
		/*
		 * Not sure about this bit...
		 */
		/* Non routable, so force a drop if we slip up later */
		ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
	}
	skb_reset_transport_header(skb);

	return atalk_rcv(skb, dev, pt, orig_dev);
freeit:
	kfree_skb(skb);
	return 0;
}

Project: linux
File: hci_sock.c

static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
{
	struct hci_event_hdr *hdr;
	struct hci_ev_stack_internal *ev;
	struct sk_buff *skb;

	skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
	if (!skb)
		return;

	hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
	hdr->evt  = HCI_EV_STACK_INTERNAL;
	hdr->plen = sizeof(*ev) + dlen;

	ev  = (void *) skb_put(skb, sizeof(*ev) + dlen);
	ev->type = type;
	memcpy(ev->data, data, dlen);

	bt_cb(skb)->incoming = 1;
	__net_timestamp(skb);

	bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
	hci_send_to_sock(hdev, skb);
	kfree_skb(skb);
}

Project: linux
File: sock.c

void __exit rfcomm_cleanup_sockets(void)
{
	bt_procfs_cleanup(&init_net, "rfcomm");

	debugfs_remove(rfcomm_sock_debugfs);

	bt_sock_unregister(BTPROTO_RFCOMM);

	proto_unregister(&rfcomm_proto);
}

Project: linux
File: sco.c

static int sco_debugfs_show(struct seq_file *f, void *p)
{
	struct sock *sk;

	read_lock(&sco_sk_list.lock);

	sk_for_each(sk, &sco_sk_list.head) {
		seq_printf(f, "%pMR %pMR %d\n", &sco_pi(sk)->src,
			   &sco_pi(sk)->dst, sk->sk_state);
	}

	read_unlock(&sco_sk_list.lock);

	return 0;
}

Project: linux
File: af_ipx.c

static void __ipxitf_down(struct ipx_interface *intrfc)
{
	struct sock *s;
	struct hlist_node *t;

	/* Delete all routes associated with this interface */
	ipxrtr_del_routes(intrfc);

	spin_lock_bh(&intrfc->if_sklist_lock);
	/* error sockets */
	sk_for_each_safe(s, t, &intrfc->if_sklist) {
		struct ipx_sock *ipxs = ipx_sk(s);

		s->sk_err = ENOLINK;
		s->sk_error_report(s);
		ipxs->intrfc = NULL;
		ipxs->port   = 0;
		sock_set_flag(s, SOCK_ZAPPED); /* Indicates it is no longer bound */
		sk_del_node_init(s);
	}
	INIT_HLIST_HEAD(&intrfc->if_sklist);
	spin_unlock_bh(&intrfc->if_sklist_lock);

	/* remove this interface from list */
	list_del(&intrfc->node);

	/* remove this interface from *special* networks */
	if (intrfc == ipx_primary_net)
		ipxitf_clear_primary_net();
	if (intrfc == ipx_internal_net)
		ipx_internal_net = NULL;

	if (intrfc->if_dev)
		dev_put(intrfc->if_dev);
	kfree(intrfc);
}

Project: linux
File: af_ipx.c

static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
						      __be16 datalink)
{
	struct ipx_interface *i;

	list_for_each_entry(i, &ipx_interfaces, node)
		if (i->if_dev == dev && i->if_dlink_type == datalink)
			goto out;
	i = NULL;
out:
	return i;
}

Project: linux
File: af_ipx.c

static int __init ipx_init(void)
{
	int rc = proto_register(&ipx_proto, 1);

	if (rc != 0)
		goto out;

	sock_register(&ipx_family_ops);

	pEII_datalink = make_EII_client();
	if (pEII_datalink)
		dev_add_pack(&ipx_dix_packet_type);
	else
		printk(ipx_EII_err_msg);

	p8023_datalink = make_8023_client();
	if (p8023_datalink)
		dev_add_pack(&ipx_8023_packet_type);
	else
		printk(ipx_8023_err_msg);

	p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv);
	if (!p8022_datalink)
		printk(ipx_llc_err_msg);

	pSNAP_datalink = register_snap_client(ipx_snap_id, ipx_rcv);
	if (!pSNAP_datalink)
		printk(ipx_snap_err_msg);

	register_netdevice_notifier(&ipx_dev_notifier);
	ipx_register_sysctl();
	ipx_proc_init();
out:
	return rc;
}

Project: linux
File: af_ipx.c

static int ipx_release(struct socket *sock)
{
	struct sock *sk = sock->sk;

	if (!sk)
		goto out;

	lock_sock(sk);
	if (!sock_flag(sk, SOCK_DEAD))
		sk->sk_state_change(sk);

	sock_set_flag(sk, SOCK_DEAD);
	sock->sk = NULL;
	sk_refcnt_debug_release(sk);
	ipx_destroy_socket(sk);
	release_sock(sk);
	sock_put(sk);
out:
	return 0;
}

Project: linux
File: af_ipx.c

static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock,
	struct msghdr *msg, size_t len)
{
	struct sock *sk = sock->sk;
	struct ipx_sock *ipxs = ipx_sk(sk);
	struct sockaddr_ipx *usipx = (struct sockaddr_ipx *)msg->msg_name;
	struct sockaddr_ipx local_sipx;
	int rc = -EINVAL;
	int flags = msg->msg_flags;

	lock_sock(sk);
	/* Socket gets bound below anyway */
/*	if (sk->sk_zapped)
		return -EIO; */	/* Socket not bound */
	if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
		goto out;

	/* Max possible packet size limited by 16 bit pktsize in header */
	if (len >= 65535 - sizeof(struct ipxhdr))
		goto out;

	if (usipx) {
		if (!ipxs->port) {
			struct sockaddr_ipx uaddr;

			uaddr.sipx_port		= 0;
			uaddr.sipx_network	= 0;
#ifdef CONFIG_IPX_INTERN
			rc = -ENETDOWN;
			if (!ipxs->intrfc)
				goto out; /* Someone zonked the iface */
			memcpy(uaddr.sipx_node, ipxs->intrfc->if_node,
				IPX_NODE_LEN);
#endif
			rc = __ipx_bind(sock, (struct sockaddr *)&uaddr,
					sizeof(struct sockaddr_ipx));
			if (rc)
				goto out;
		}

		rc = -EINVAL;
		if (msg->msg_namelen < sizeof(*usipx) ||
		    usipx->sipx_family != AF_IPX)
			goto out;
	} else {
		rc = -ENOTCONN;
		if (sk->sk_state != TCP_ESTABLISHED)
			goto out;

		usipx = &local_sipx;
		usipx->sipx_family 	= AF_IPX;
		usipx->sipx_type 	= ipxs->type;
		usipx->sipx_port 	= ipxs->dest_addr.sock;
		usipx->sipx_network 	= ipxs->dest_addr.net;
		memcpy(usipx->sipx_node, ipxs->dest_addr.node, IPX_NODE_LEN);
	}

	rc = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len,
				 flags & MSG_DONTWAIT);
	if (rc >= 0)
		rc = len;
out:
	release_sock(sk);
	return rc;
}

Project: linux
File: af_ipx.c

static int ipxcfg_get_config_data(struct ipx_config_data __user *arg)
{
	struct ipx_config_data vals;

	vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces;
	vals.ipxcfg_auto_select_primary	   = ipxcfg_auto_select_primary;

	return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0;
}

Project: linux
File: af_ipx.c

static void ipxcfg_set_auto_select(char val)
{
	ipxcfg_auto_select_primary = val;
	if (val && !ipx_primary_net)
		ipx_primary_net = ipx_interfaces_head();
}

Project: linux
File: af_ipx.c

static int ipxitf_device_event(struct notifier_block *notifier,
				unsigned long event, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct ipx_interface *i, *tmp;

	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

	if (event != NETDEV_DOWN && event != NETDEV_UP)
		goto out;

	spin_lock_bh(&ipx_interfaces_lock);
	list_for_each_entry_safe(i, tmp, &ipx_interfaces, node)
		if (i->if_dev == dev) {
			if (event == NETDEV_UP)
				ipxitf_hold(i);
			else
				__ipxitf_put(i);
		}
	spin_unlock_bh(&ipx_interfaces_lock);
out:
	return NOTIFY_DONE;
}

Project: linux
File: af_ipx.c

void ipxitf_down(struct ipx_interface *intrfc)
{
	spin_lock_bh(&ipx_interfaces_lock);
	__ipxitf_down(intrfc);
	spin_unlock_bh(&ipx_interfaces_lock);
}

Project: linux
File: af_iucv.c

static void iucv_callback_txdone(struct iucv_path *path,
				 struct iucv_message *msg)
{
	struct sock *sk = path->private;
	struct sk_buff *this = NULL;
	struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q;
	struct sk_buff *list_skb = list->next;
	unsigned long flags;

	bh_lock_sock(sk);
	if (!skb_queue_empty(list)) {
		spin_lock_irqsave(&list->lock, flags);

		while (list_skb != (struct sk_buff *)list) {
			if (msg->tag != IUCV_SKB_CB(list_skb)->tag) {
				this = list_skb;
				break;
			}
			list_skb = list_skb->next;
		}
		if (this)
			__skb_unlink(this, list);

		spin_unlock_irqrestore(&list->lock, flags);

		if (this) {
			kfree_skb(this);
			/* wake up any process waiting for sending */
			iucv_sock_wake_msglim(sk);
		}
	}

	if (sk->sk_state == IUCV_CLOSING) {
		if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
			sk->sk_state = IUCV_CLOSED;
			sk->sk_state_change(sk);
		}
	}
	bh_unlock_sock(sk);

}

Project: linux
File: af_iucv.c

static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
			     struct msghdr *msg, size_t len)
{
	struct sock *sk = sock->sk;
	struct iucv_sock *iucv = iucv_sk(sk);
	struct sk_buff *skb;
	struct iucv_message txmsg;
	struct cmsghdr *cmsg;
	int cmsg_done;
	long timeo;
	char user_id[9];
	char appl_id[9];
	int err;
	int noblock = msg->msg_flags & MSG_DONTWAIT;

	err = sock_error(sk);
	if (err)
		return err;

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	/* SOCK_SEQPACKET: we do not support segmented records */
	if (sk->sk_type == SOCK_SEQPACKET && !(msg->msg_flags & MSG_EOR))
		return -EOPNOTSUPP;

	lock_sock(sk);

	if (sk->sk_shutdown & SEND_SHUTDOWN) {
		err = -EPIPE;
		goto out;
	}

	/* Return if the socket is not in connected state */
	if (sk->sk_state != IUCV_CONNECTED) {
		err = -ENOTCONN;
		goto out;
	}

	/* initialize defaults */
	cmsg_done   = 0;	/* check for duplicate headers */
	txmsg.class = 0;

	/* iterate over control messages */
	for (cmsg = CMSG_FIRSTHDR(msg); cmsg;
		cmsg = CMSG_NXTHDR(msg, cmsg)) {

		if (!CMSG_OK(msg, cmsg)) {
			err = -EINVAL;
			goto out;
		}

		if (cmsg->cmsg_level != SOL_IUCV)
			continue;

		if (cmsg->cmsg_type & cmsg_done) {
			err = -EINVAL;
			goto out;
		}
		cmsg_done |= cmsg->cmsg_type;

		switch (cmsg->cmsg_type) {
		case SCM_IUCV_TRGCLS:
			if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
				err = -EINVAL;
				goto out;
			}

			/* set iucv message target class */
			memcpy(&txmsg.class,
				(void *) CMSG_DATA(cmsg), TRGCLS_SIZE);

			break;

		default:
			err = -EINVAL;
			goto out;
			break;
		}
	}

	/* allocate one skb for each iucv message:
	 * this is fine for SOCK_SEQPACKET (unless we want to support
	 * segmented records using the MSG_EOR flag), but
	 * for SOCK_STREAM we might want to improve it in future */
	if (iucv->transport == AF_IUCV_TRANS_HIPER)
		skb = sock_alloc_send_skb(sk,
			len + sizeof(struct af_iucv_trans_hdr) + ETH_HLEN,
			noblock, &err);
	else
		skb = sock_alloc_send_skb(sk, len, noblock, &err);
	if (!skb) {
		err = -ENOMEM;
		goto out;
	}
	if (iucv->transport == AF_IUCV_TRANS_HIPER)
		skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN);
	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
		err = -EFAULT;
		goto fail;
	}

	/* wait if outstanding messages for iucv path has reached */
	timeo = sock_sndtimeo(sk, noblock);
	err = iucv_sock_wait(sk, iucv_below_msglim(sk), timeo);
	if (err)
		goto fail;

	/* return -ECONNRESET if the socket is no longer connected */
	if (sk->sk_state != IUCV_CONNECTED) {
		err = -ECONNRESET;
		goto fail;
	}

	/* increment and save iucv message tag for msg_completion cbk */
	txmsg.tag = iucv->send_tag++;
	IUCV_SKB_CB(skb)->tag = txmsg.tag;

	if (iucv->transport == AF_IUCV_TRANS_HIPER) {
		atomic_inc(&iucv->msg_sent);
		err = afiucv_hs_send(&txmsg, sk, skb, 0);
		if (err) {
			atomic_dec(&iucv->msg_sent);
			goto fail;
		}
		goto release;
	}
	skb_queue_tail(&iucv->send_skb_q, skb);

	if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
	      && skb->len <= 7) {
		err = iucv_send_iprm(iucv->path, &txmsg, skb);

		/* on success: there is no message_complete callback
		 * for an IPRMDATA msg; remove skb from send queue */
		if (err == 0) {
			skb_unlink(skb, &iucv->send_skb_q);
			kfree_skb(skb);
		}

		/* this error should never happen since the
		 * IUCV_IPRMDATA path flag is set... sever path */
		if (err == 0x15) {
			pr_iucv->path_sever(iucv->path, NULL);
			skb_unlink(skb, &iucv->send_skb_q);
			err = -EPIPE;
			goto fail;
		}
	} else
		err = pr_iucv->message_send(iucv->path, &txmsg, 0, 0,
					(void *) skb->data, skb->len);
	if (err) {
		if (err == 3) {
			user_id[8] = 0;
			memcpy(user_id, iucv->dst_user_id, 8);
			appl_id[8] = 0;
			memcpy(appl_id, iucv->dst_name, 8);
			pr_err("Application %s on z/VM guest %s"
				" exceeds message limit\n",
				appl_id, user_id);
			err = -EAGAIN;
		} else
			err = -EPIPE;
		skb_unlink(skb, &iucv->send_skb_q);
		goto fail;
	}

release:
	release_sock(sk);
	return len;

fail:
	kfree_skb(skb);
out:
	release_sock(sk);
	return err;
}

Project: linux
File: af_llc.c

static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
{
	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
	struct sock *sk = sock->sk;
	struct llc_sock *llc = llc_sk(sk);
	struct llc_sap *sap;
	int rc = -EINVAL;

	dprintk("%s: binding %02X\n", __func__, addr->sllc_sap);
	if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)))
		goto out;
	rc = -EAFNOSUPPORT;
	if (unlikely(addr->sllc_family != AF_LLC))
		goto out;
	rc = -ENODEV;
	rcu_read_lock();
	if (sk->sk_bound_dev_if) {
		llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if);
		if (llc->dev) {
			if (!addr->sllc_arphrd)
				addr->sllc_arphrd = llc->dev->type;
			if (is_zero_ether_addr(addr->sllc_mac))
				memcpy(addr->sllc_mac, llc->dev->dev_addr,
				       IFHWADDRLEN);
			if (addr->sllc_arphrd != llc->dev->type ||
			    !ether_addr_equal(addr->sllc_mac,
					      llc->dev->dev_addr)) {
				rc = -EINVAL;
				llc->dev = NULL;
			}
		}
	} else
		llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
					   addr->sllc_mac);
	if (llc->dev)
		dev_hold(llc->dev);
	rcu_read_unlock();
	if (!llc->dev)
		goto out;
	if (!addr->sllc_sap) {
		rc = -EUSERS;
		addr->sllc_sap = llc_ui_autoport();
		if (!addr->sllc_sap)
			goto out;
	}
	sap = llc_sap_find(addr->sllc_sap);
	if (!sap) {
		sap = llc_sap_open(addr->sllc_sap, NULL);
		rc = -EBUSY; /* some other network layer is using the sap */
		if (!sap)
			goto out;
	} else {
		struct llc_addr laddr, daddr;
		struct sock *ask;

		memset(&laddr, 0, sizeof(laddr));
		memset(&daddr, 0, sizeof(daddr));
		/*
		 * FIXME: check if the address is multicast,
		 * 	  only SOCK_DGRAM can do this.
		 */
		memcpy(laddr.mac, addr->sllc_mac, IFHWADDRLEN);
		laddr.lsap = addr->sllc_sap;
		rc = -EADDRINUSE; /* mac + sap clash. */
		ask = llc_lookup_established(sap, &daddr, &laddr);
		if (ask) {
			sock_put(ask);
			goto out_put;
		}
	}
	llc->laddr.lsap = addr->sllc_sap;
	memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN);
	memcpy(&llc->addr, addr, sizeof(llc->addr));
	/* assign new connection to its SAP */
	llc_sap_add_socket(sap, sk);
	sock_reset_flag(sk, SOCK_ZAPPED);
	rc = 0;
out_put:
	llc_sap_put(sap);
out:
	return rc;
}

Project: linux
File: af_netlink.c

__netlink_kernel_create(struct net *net, int unit, struct module *module,
			struct netlink_kernel_cfg *cfg)
{
	struct socket *sock;
	struct sock *sk;
	struct netlink_sock *nlk;
	struct listeners *listeners = NULL;
	struct mutex *cb_mutex = cfg ? cfg->cb_mutex : NULL;
	unsigned int groups;

	BUG_ON(!nl_table);

	if (unit < 0 || unit >= MAX_LINKS)
		return NULL;

	if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
		return NULL;

	/*
	 * We have to just have a reference on the net from sk, but don't
	 * get_net it. Besides, we cannot get and then put the net here.
	 * So we create one inside init_net and the move it to net.
	 */

	if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0)
		goto out_sock_release_nosk;

	sk = sock->sk;
	sk_change_net(sk, net);

	if (!cfg || cfg->groups < 32)
		groups = 32;
	else
		groups = cfg->groups;

	listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
	if (!listeners)
		goto out_sock_release;

	sk->sk_data_ready = netlink_data_ready;
	if (cfg && cfg->input)
		nlk_sk(sk)->netlink_rcv = cfg->input;

	if (netlink_insert(sk, net, 0))
		goto out_sock_release;

	nlk = nlk_sk(sk);
	nlk->flags |= NETLINK_KERNEL_SOCKET;

	netlink_table_grab();
	if (!nl_table[unit].registered) {
		nl_table[unit].groups = groups;
		rcu_assign_pointer(nl_table[unit].listeners, listeners);
		nl_table[unit].cb_mutex = cb_mutex;
		nl_table[unit].module = module;
		if (cfg) {
			nl_table[unit].bind = cfg->bind;
			nl_table[unit].flags = cfg->flags;
			if (cfg->compare)
				nl_table[unit].compare = cfg->compare;
		}
		nl_table[unit].registered = 1;
	} else {
		kfree(listeners);
		nl_table[unit].registered++;
	}
	netlink_table_ungrab();
	return sk;

out_sock_release:
	kfree(listeners);
	netlink_kernel_release(sk);
	return NULL;

out_sock_release_nosk:
	sock_release(sock);
	return NULL;
}

Project: linux
File: af_netlink.c

static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
{
	int len = skb->len;

	netlink_deliver_tap(skb);

#ifdef CONFIG_NETLINK_MMAP
	if (netlink_skb_is_mmaped(skb))
		netlink_queue_mmaped_skb(sk, skb);
	else if (netlink_rx_is_mmaped(sk))
		netlink_ring_set_copied(sk, skb);
	else
#endif /* CONFIG_NETLINK_MMAP */
		skb_queue_tail(&sk->sk_receive_queue, skb);
	sk->sk_data_ready(sk, len);
	return len;
}

Project: linux
File: af_netlink.c

int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
		      long *timeo, struct sock *ssk)
{
	struct netlink_sock *nlk;

	nlk = nlk_sk(sk);

	if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
	     test_bit(NETLINK_CONGESTED, &nlk->state)) &&
	    !netlink_skb_is_mmaped(skb)) {
		DECLARE_WAITQUEUE(wait, current);
		if (!*timeo) {
			if (!ssk || netlink_is_kernel(ssk))
				netlink_overrun(sk);
			sock_put(sk);
			kfree_skb(skb);
			return -EAGAIN;
		}

		__set_current_state(TASK_INTERRUPTIBLE);
		add_wait_queue(&nlk->wait, &wait);

		if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
		     test_bit(NETLINK_CONGESTED, &nlk->state)) &&
		    !sock_flag(sk, SOCK_DEAD))
			*timeo = schedule_timeout(*timeo);

		__set_current_state(TASK_RUNNING);
		remove_wait_queue(&nlk->wait, &wait);
		sock_put(sk);

		if (signal_pending(current)) {
			kfree_skb(skb);
			return sock_intr_errno(*timeo);
		}
		return 1;
	}
	netlink_skb_set_owner_r(skb, sk);
	return 0;
}

Project: linux
File: af_netlink.c

int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid,
	u32 group, gfp_t allocation,
	int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
	void *filter_data)
{
	struct net *net = sock_net(ssk);
	struct netlink_broadcast_data info;
	struct sock *sk;

	skb = netlink_trim(skb, allocation);

	info.exclude_sk = ssk;
	info.net = net;
	info.portid = portid;
	info.group = group;
	info.failure = 0;
	info.delivery_failure = 0;
	info.congested = 0;
	info.delivered = 0;
	info.allocation = allocation;
	info.skb = skb;
	info.skb2 = NULL;
	info.tx_filter = filter;
	info.tx_data = filter_data;

	/* While we sleep in clone, do not allow to change socket list */

	netlink_lock_table();

	sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list)
		do_one_broadcast(sk, &info);

	consume_skb(skb);

	netlink_unlock_table();

	if (info.delivery_failure) {
		kfree_skb(info.skb2);
		return -ENOBUFS;
	}
	consume_skb(info.skb2);

	if (info.delivered) {
		if (info.congested && (allocation & __GFP_WAIT))
			yield();
		return 0;
	}
	return -ESRCH;
}

Project: linux
File: af_netlink.c

static void netlink_deliver_tap(struct sk_buff *skb)
{
	rcu_read_lock();

	if (unlikely(!list_empty(&netlink_tap_all)))
		__netlink_deliver_tap(skb);

	rcu_read_unlock();
}

Project: linux
File: af_netlink.c

static void netlink_mm_close(struct vm_area_struct *vma)
{
	struct file *file = vma->vm_file;
	struct socket *sock = file->private_data;
	struct sock *sk = sock->sk;

	if (sk)
		atomic_dec(&nlk_sk(sk)->mapped);
}

Project: linux
File: af_netlink.c

static int netlink_mmap(struct file *file, struct socket *sock,
			struct vm_area_struct *vma)
{
	struct sock *sk = sock->sk;
	struct netlink_sock *nlk = nlk_sk(sk);
	struct netlink_ring *ring;
	unsigned long start, size, expected;
	unsigned int i;
	int err = -EINVAL;

	if (vma->vm_pgoff)
		return -EINVAL;

	mutex_lock(&nlk->pg_vec_lock);

	expected = 0;
	for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
		if (ring->pg_vec == NULL)
			continue;
		expected += ring->pg_vec_len * ring->pg_vec_pages * PAGE_SIZE;
	}

	if (expected == 0)
		goto out;

	size = vma->vm_end - vma->vm_start;
	if (size != expected)
		goto out;

	start = vma->vm_start;
	for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
		if (ring->pg_vec == NULL)
			continue;

		for (i = 0; i < ring->pg_vec_len; i++) {
			struct page *page;
			void *kaddr = ring->pg_vec[i];
			unsigned int pg_num;

			for (pg_num = 0; pg_num < ring->pg_vec_pages; pg_num++) {
				page = pgvec_to_page(kaddr);
				err = vm_insert_page(vma, start, page);
				if (err < 0)
					goto out;
				start += PAGE_SIZE;
				kaddr += PAGE_SIZE;
			}
		}
	}

	atomic_inc(&nlk->mapped);
	vma->vm_ops = &netlink_mmap_ops;
	err = 0;
out:
	mutex_unlock(&nlk->pg_vec_lock);
	return err;
}

Project: linux
File: af_netlink.c

static int netlink_release(struct socket *sock)
{
	struct sock *sk = sock->sk;
	struct netlink_sock *nlk;

	if (!sk)
		return 0;

	netlink_remove(sk);
	sock_orphan(sk);
	nlk = nlk_sk(sk);

	/*
	 * OK. Socket is unlinked, any packets that arrive now
	 * will be purged.
	 */

	sock->sk = NULL;
	wake_up_interruptible_all(&nlk->wait);

	skb_queue_purge(&sk->sk_write_queue);

	if (nlk->portid) {
		struct netlink_notify n = {
						.net = sock_net(sk),
						.protocol = sk->sk_protocol,
						.portid = nlk->portid,
					  };
		atomic_notifier_call_chain(&netlink_chain,
				NETLINK_URELEASE, &n);
	}

	module_put(nlk->module);

	netlink_table_grab();
	if (netlink_is_kernel(sk)) {
		BUG_ON(nl_table[sk->sk_protocol].registered == 0);
		if (--nl_table[sk->sk_protocol].registered == 0) {
			struct listeners *old;

			old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
			RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
			kfree_rcu(old, rcu);
			nl_table[sk->sk_protocol].module = NULL;
			nl_table[sk->sk_protocol].bind = NULL;
			nl_table[sk->sk_protocol].flags = 0;
			nl_table[sk->sk_protocol].registered = 0;
		}
	} else if (nlk->subscriptions) {
		netlink_update_listeners(sk);
	}
	netlink_table_ungrab();

	kfree(nlk->groups);
	nlk->groups = NULL;

	local_bh_disable();
	sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
	local_bh_enable();
	sock_put(sk);
	return 0;
}

Project: linux
File: af_netlink.c

static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb)
{
	struct netlink_sock *nlk = nlk_sk(sk);
	struct netlink_ring *ring = &nlk->rx_ring;
	struct nl_mmap_hdr *hdr;

	spin_lock_bh(&sk->sk_receive_queue.lock);
	hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
	if (hdr == NULL) {
		spin_unlock_bh(&sk->sk_receive_queue.lock);
		kfree_skb(skb);
		netlink_overrun(sk);
		return;
	}
	netlink_increment_head(ring);
	__skb_queue_tail(&sk->sk_receive_queue, skb);
	spin_unlock_bh(&sk->sk_receive_queue.lock);

	hdr->nm_len	= skb->len;
	hdr->nm_group	= NETLINK_CB(skb).dst_group;
	hdr->nm_pid	= NETLINK_CB(skb).creds.pid;
	hdr->nm_uid	= from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid);
	hdr->nm_gid	= from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid);
	netlink_set_status(hdr, NL_MMAP_STATUS_COPY);
}

Project: linux
File: af_netlink.c

static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
{
	struct nl_seq_iter *iter = seq->private;
	int i, j;
	struct sock *s;
	loff_t off = 0;

	for (i = 0; i < MAX_LINKS; i++) {
		struct nl_portid_hash *hash = &nl_table[i].hash;

		for (j = 0; j <= hash->mask; j++) {
			sk_for_each(s, &hash->table[j]) {
				if (sock_net(s) != seq_file_net(seq))
					continue;
				if (off == pos) {
					iter->link = i;
					iter->hash_idx = j;
					return s;
				}
				++off;
			}
		}
	}
	return NULL;
}

Project: linux
File: af_netlink.c

static void nl_portid_hash_free(struct hlist_head *table, size_t size)
{
	if (size <= PAGE_SIZE)
		kfree(table);
	else
		free_pages((unsigned long)table, get_order(size));
}

Project: linux
File: af_netlink.c

static int nl_portid_hash_rehash(struct nl_portid_hash *hash, int grow)
{
	unsigned int omask, mask, shift;
	size_t osize, size;
	struct hlist_head *otable, *table;
	int i;

	omask = mask = hash->mask;
	osize = size = (mask + 1) * sizeof(*table);
	shift = hash->shift;

	if (grow) {
		if (++shift > hash->max_shift)
			return 0;
		mask = mask * 2 + 1;
		size *= 2;
	}

	table = nl_portid_hash_zalloc(size);
	if (!table)
		return 0;

	otable = hash->table;
	hash->table = table;
	hash->mask = mask;
	hash->shift = shift;
	get_random_bytes(&hash->rnd, sizeof(hash->rnd));

	for (i = 0; i <= omask; i++) {
		struct sock *sk;
		struct hlist_node *tmp;

		sk_for_each_safe(sk, tmp, &otable[i])
			__sk_add_node(sk, nl_portid_hashfn(hash, nlk_sk(sk)->portid));
	}

	nl_portid_hash_free(otable, osize);
	hash->rehash_time = jiffies + 10 * 60 * HZ;
	return 1;
}

Project: linux
File: af_packet.c

static void __packet_set_status(struct packet_sock *po, void *frame, int status)
{
	union tpacket_uhdr h;

	h.raw = frame;
	switch (po->tp_version) {
	case TPACKET_V1:
		h.h1->tp_status = status;
		flush_dcache_page(pgv_to_page(&h.h1->tp_status));
		break;
	case TPACKET_V2:
		h.h2->tp_status = status;
		flush_dcache_page(pgv_to_page(&h.h2->tp_status));
		break;
	case TPACKET_V3:
	default:
		WARN(1, "TPACKET version not supported.\n");
		BUG();
	}

	smp_wmb();
}

Project: linux
File: af_packet.c

static void __unregister_prot_hook(struct sock *sk, bool sync)
{
	struct packet_sock *po = pkt_sk(sk);

	po->running = 0;
	if (po->fanout)
		__fanout_unlink(sk, po);
	else
		__dev_remove_pack(&po->prot_hook);
	__sock_put(sk);

	if (sync) {
		spin_unlock(&po->bind_lock);
		synchronize_net();
		spin_lock(&po->bind_lock);
	}
}

Project: linux
File: af_packet.c

static unsigned int fanout_demux_hash(struct packet_fanout *f,
				      struct sk_buff *skb,
				      unsigned int num)
{
	return reciprocal_divide(skb->rxhash, num);
}

Project: linux
File: af_packet.c

static void packet_increment_rx_head(struct packet_sock *po,
					    struct packet_ring_buffer *rb)
{
	switch (po->tp_version) {
	case TPACKET_V1:
	case TPACKET_V2:
		return packet_increment_head(rb);
	case TPACKET_V3:
	default:
		WARN(1, "TPACKET version not supported.\n");
		BUG();
		return;
	}
}

Project: linux
File: af_packet.c

static int packet_notifier(struct notifier_block *this,
			   unsigned long msg, void *ptr)
{
	struct sock *sk;
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct net *net = dev_net(dev);

	rcu_read_lock();
	sk_for_each_rcu(sk, &net->packet.sklist) {
		struct packet_sock *po = pkt_sk(sk);

		switch (msg) {
		case NETDEV_UNREGISTER:
			if (po->mclist)
				packet_dev_mclist(dev, po->mclist, -1);
			/* fallthrough */

		case NETDEV_DOWN:
			if (dev->ifindex == po->ifindex) {
				spin_lock(&po->bind_lock);
				if (po->running) {
					__unregister_prot_hook(sk, false);
					sk->sk_err = ENETDOWN;
					if (!sock_flag(sk, SOCK_DEAD))
						sk->sk_error_report(sk);
				}
				if (msg == NETDEV_UNREGISTER) {
					po->ifindex = -1;
					if (po->prot_hook.dev)
						dev_put(po->prot_hook.dev);
					po->prot_hook.dev = NULL;
				}
				spin_unlock(&po->bind_lock);
			}
			break;
		case NETDEV_UP:
			if (dev->ifindex == po->ifindex) {
				spin_lock(&po->bind_lock);
				if (po->num)
					register_prot_hook(sk);
				spin_unlock(&po->bind_lock);
			}
			break;
		}
	}
	rcu_read_unlock();
	return NOTIFY_DONE;
}

Project: linux
File: af_packet.c

static void prb_close_block(struct tpacket_kbdq_core *pkc1,
		struct tpacket_block_desc *pbd1,
		struct packet_sock *po, unsigned int stat)
{
	__u32 status = TP_STATUS_USER | stat;

	struct tpacket3_hdr *last_pkt;
	struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;

	if (po->stats.stats3.tp_drops)
		status |= TP_STATUS_LOSING;

	last_pkt = (struct tpacket3_hdr *)pkc1->prev;
	last_pkt->tp_next_offset = 0;

	/* Get the ts of the last pkt */
	if (BLOCK_NUM_PKTS(pbd1)) {
		h1->ts_last_pkt.ts_sec = last_pkt->tp_sec;
		h1->ts_last_pkt.ts_nsec	= last_pkt->tp_nsec;
	} else {
		/* Ok, we tmo'd - so get the current time */
		struct timespec ts;
		getnstimeofday(&ts);
		h1->ts_last_pkt.ts_sec = ts.tv_sec;
		h1->ts_last_pkt.ts_nsec	= ts.tv_nsec;
	}

	smp_wmb();

	/* Flush the block */
	prb_flush_block(pkc1, pbd1, status);

	pkc1->kactive_blk_num = GET_NEXT_PRB_BLK_NUM(pkc1);
}

Project: linux
File: af_packet.c

static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
			struct tpacket3_hdr *ppd)
{
	if (vlan_tx_tag_present(pkc->skb)) {
		ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb);
		ppd->tp_status = TP_STATUS_VLAN_VALID;
	} else {
		ppd->hv1.tp_vlan_tci = 0;
		ppd->tp_status = TP_STATUS_AVAILABLE;
	}
}

Project: linux
File: af_packet.c

static void *prb_lookup_block(struct packet_sock *po,
				     struct packet_ring_buffer *rb,
				     unsigned int idx,
				     int status)
{
	struct tpacket_kbdq_core *pkc  = GET_PBDQC_FROM_RB(rb);
	struct tpacket_block_desc *pbd = GET_PBLOCK_DESC(pkc, idx);

	if (status != BLOCK_STATUS(pbd))
		return NULL;
	return pbd;
}

Project: linux
File: af_packet.c

static int prb_queue_frozen(struct tpacket_kbdq_core *pkc)
{
	return pkc->reset_pending_on_curr_blk;
}

Project: linux
File: af_packet.c

static void prb_thaw_queue(struct tpacket_kbdq_core *pkc)
{
	pkc->reset_pending_on_curr_blk = 0;
}

Project: linux
File: af_packet.c

static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
		void *frame, struct net_device *dev, int size_max,
		__be16 proto, unsigned char *addr, int hlen)
{
	union tpacket_uhdr ph;
	int to_write, offset, len, tp_len, nr_frags, len_max;
	struct socket *sock = po->sk.sk_socket;
	struct page *page;
	void *data;
	int err;

	ph.raw = frame;

	skb->protocol = proto;
	skb->dev = dev;
	skb->priority = po->sk.sk_priority;
	skb->mark = po->sk.sk_mark;
	sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags);
	skb_shinfo(skb)->destructor_arg = ph.raw;

	switch (po->tp_version) {
	case TPACKET_V2:
		tp_len = ph.h2->tp_len;
		break;
	default:
		tp_len = ph.h1->tp_len;
		break;
	}
	if (unlikely(tp_len > size_max)) {
		pr_err("packet size is too long (%d > %d)\n", tp_len, size_max);
		return -EMSGSIZE;
	}

	skb_reserve(skb, hlen);
	skb_reset_network_header(skb);
	skb_probe_transport_header(skb, 0);

	if (po->tp_tx_has_off) {
		int off_min, off_max, off;
		off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
		off_max = po->tx_ring.frame_size - tp_len;
		if (sock->type == SOCK_DGRAM) {
			switch (po->tp_version) {
			case TPACKET_V2:
				off = ph.h2->tp_net;
				break;
			default:
				off = ph.h1->tp_net;
				break;
			}
		} else {
			switch (po->tp_version) {
			case TPACKET_V2:
				off = ph.h2->tp_mac;
				break;
			default:
				off = ph.h1->tp_mac;
				break;
			}
		}
		if (unlikely((off < off_min) || (off_max < off)))
			return -EINVAL;
		data = ph.raw + off;
	} else {
		data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll);
	}
	to_write = tp_len;

	if (sock->type == SOCK_DGRAM) {
		err = dev_hard_header(skb, dev, ntohs(proto), addr,
				NULL, tp_len);
		if (unlikely(err < 0))
			return -EINVAL;
	} else if (dev->hard_header_len) {
		/* net device doesn't like empty head */
		if (unlikely(tp_len <= dev->hard_header_len)) {
			pr_err("packet size is too short (%d < %d)\n",
			       tp_len, dev->hard_header_len);
			return -EINVAL;
		}

		skb_push(skb, dev->hard_header_len);
		err = skb_store_bits(skb, 0, data,
				dev->hard_header_len);
		if (unlikely(err))
			return err;

		data += dev->hard_header_len;
		to_write -= dev->hard_header_len;
	}

	offset = offset_in_page(data);
	len_max = PAGE_SIZE - offset;
	len = ((to_write > len_max) ? len_max : to_write);

	skb->data_len = to_write;
	skb->len += to_write;
	skb->truesize += to_write;
	atomic_add(to_write, &po->sk.sk_wmem_alloc);

	while (likely(to_write)) {
		nr_frags = skb_shinfo(skb)->nr_frags;

		if (unlikely(nr_frags >= MAX_SKB_FRAGS)) {
			pr_err("Packet exceed the number of skb frags(%lu)\n",
			       MAX_SKB_FRAGS);
			return -EFAULT;
		}

		page = pgv_to_page(data);
		data += len;
		flush_dcache_page(page);
		get_page(page);
		skb_fill_page_desc(skb, nr_frags, page, offset, len);
		to_write -= len;
		offset = 0;
		len_max = PAGE_SIZE;
		len = ((to_write > len_max) ? len_max : to_write);
	}

	return tp_len;
}

Project: linux
File: socket.c

SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
		int __user *, usockvec)
{
	struct socket *sock1, *sock2;
	int fd1, fd2, err;
	struct file *newfile1, *newfile2;
	int flags;

	flags = type & ~SOCK_TYPE_MASK;
	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
		return -EINVAL;
	type &= SOCK_TYPE_MASK;

	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;

	/*
	 * Obtain the first socket and check if the underlying protocol
	 * supports the socketpair call.
	 */

	err = sock_create(family, type, protocol, &sock1);
	if (err < 0)
		goto out;

	err = sock_create(family, type, protocol, &sock2);
	if (err < 0)
		goto out_release_1;

	err = sock1->ops->socketpair(sock1, sock2);
	if (err < 0)
		goto out_release_both;

	fd1 = get_unused_fd_flags(flags);
	if (unlikely(fd1 < 0)) {
		err = fd1;
		goto out_release_both;
	}
	fd2 = get_unused_fd_flags(flags);
	if (unlikely(fd2 < 0)) {
		err = fd2;
		put_unused_fd(fd1);
		goto out_release_both;
	}

	newfile1 = sock_alloc_file(sock1, flags, NULL);
	if (unlikely(IS_ERR(newfile1))) {
		err = PTR_ERR(newfile1);
		put_unused_fd(fd1);
		put_unused_fd(fd2);
		goto out_release_both;
	}

	newfile2 = sock_alloc_file(sock2, flags, NULL);
	if (IS_ERR(newfile2)) {
		err = PTR_ERR(newfile2);
		fput(newfile1);
		put_unused_fd(fd1);
		put_unused_fd(fd2);
		sock_release(sock2);
		goto out;
	}

	audit_fd_pair(fd1, fd2);
	fd_install(fd1, newfile1);
	fd_install(fd2, newfile2);
	/* fd1 and fd2 may be already another descriptors.
	 * Not kernel problem.
	 */

	err = put_user(fd1, &usockvec[0]);
	if (!err)
		err = put_user(fd2, &usockvec[1]);
	if (!err)
		return 0;

	sys_close(fd2);
	sys_close(fd1);
	return err;

out_release_both:
	sock_release(sock2);
out_release_1:
	sock_release(sock1);
out:
	return err;
}

Project: linux
File: socket.c

SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
		unsigned int, vlen, unsigned int, flags)
{
	if (flags & MSG_CMSG_COMPAT)
		return -EINVAL;
	return __sys_sendmmsg(fd, mmsg, vlen, flags);
}

Project: linux
File: socket.c

int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
		   unsigned int flags, struct timespec *timeout)
{
	int fput_needed, err, datagrams;
	struct socket *sock;
	struct mmsghdr __user *entry;
	struct compat_mmsghdr __user *compat_entry;
	struct msghdr msg_sys;
	struct timespec end_time;

	if (timeout &&
	    poll_select_set_timeout(&end_time, timeout->tv_sec,
				    timeout->tv_nsec))
		return -EINVAL;

	datagrams = 0;

	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	if (!sock)
		return err;

	err = sock_error(sock->sk);
	if (err)
		goto out_put;

	entry = mmsg;
	compat_entry = (struct compat_mmsghdr __user *)mmsg;

	while (datagrams < vlen) {
		/*
		 * No need to ask LSM for more than the first datagram.
		 */
		if (MSG_CMSG_COMPAT & flags) {
			err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
					     &msg_sys, flags & ~MSG_WAITFORONE,
					     datagrams);
			if (err < 0)
				break;
			err = __put_user(err, &compat_entry->msg_len);
			++compat_entry;
		} else {
			err = ___sys_recvmsg(sock,
					     (struct msghdr __user *)entry,
					     &msg_sys, flags & ~MSG_WAITFORONE,
					     datagrams);
			if (err < 0)
				break;
			err = put_user(err, &entry->msg_len);
			++entry;
		}

		if (err)
			break;
		++datagrams;

		/* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
		if (flags & MSG_WAITFORONE)
			flags |= MSG_DONTWAIT;

		if (timeout) {
			ktime_get_ts(timeout);
			*timeout = timespec_sub(end_time, *timeout);
			if (timeout->tv_sec < 0) {
				timeout->tv_sec = timeout->tv_nsec = 0;
				break;
			}

			/* Timeout, return less than vlen datagrams */
			if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
				break;
		}

		/* Out of band data, return right away */
		if (msg_sys.msg_flags & MSG_OOB)
			break;
	}

out_put:
	fput_light(sock->file, fput_needed);

	if (err == 0)
		return datagrams;

	if (datagrams != 0) {
		/*
		 * We may return less entries than requested (vlen) if the
		 * sock is non block and there aren't enough datagrams...
		 */
		if (err != -EAGAIN) {
			/*
			 * ... or  if recvmsg returns an error after we
			 * received some datagrams, where we record the
			 * error to return on the next call or if the
			 * app asks about it using getsockopt(SO_ERROR).
			 */
			sock->sk->sk_err = -err;
		}

		return datagrams;
	}

	return err;
}

Project: linux
File: socket.c

static unsigned int sock_poll(struct file *file, poll_table *wait)
{
	unsigned int busy_flag = 0;
	struct socket *sock;

	/*
	 *      We can't return errors to poll, so it's either yes or no.
	 */
	sock = file->private_data;

	if (sk_can_busy_loop(sock->sk)) {
		/* this socket can poll_ll so tell the system call */
		busy_flag = POLL_BUSY_LOOP;

		/* once, only if requested by syscall */
		if (wait && (wait->_key & POLL_BUSY_LOOP))
			sk_busy_loop(sock->sk, 1);
	}

	return busy_flag | sock->ops->poll(file, sock, wait);
}

Project: linux
File: socket.c

static int send_packet(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;
	long timeout_val;
	int res;

	/* Handle implied connection establishment */
	if (unlikely(dest))
		return send_msg(iocb, sock, m, total_len);

	if (total_len > TIPC_MAX_USER_MSG_SIZE)
		return -EMSGSIZE;

	if (iocb)
		lock_sock(sk);

	timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);

	do {
		if (unlikely(sock->state != SS_CONNECTED)) {
			if (sock->state == SS_DISCONNECTING)
				res = -EPIPE;
			else
				res = -ENOTCONN;
			break;
		}

		res = tipc_send(tport->ref, m->msg_iov, total_len);
		if (likely(res != -ELINKCONG))
			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 || !tport->connected), timeout_val);
		lock_sock(sk);
	} while (1);

	if (iocb)
		release_sock(sk);
	return res;
}

Project: linux
File: af_unix.c

static void unix_release_sock(struct sock *sk, int embrion)
{
	struct unix_sock *u = unix_sk(sk);
	struct path path;
	struct sock *skpair;
	struct sk_buff *skb;
	int state;

	unix_remove_socket(sk);

	/* Clear state */
	unix_state_lock(sk);
	sock_orphan(sk);
	sk->sk_shutdown = SHUTDOWN_MASK;
	path	     = u->path;
	u->path.dentry = NULL;
	u->path.mnt = NULL;
	state = sk->sk_state;
	sk->sk_state = TCP_CLOSE;
	unix_state_unlock(sk);

	wake_up_interruptible_all(&u->peer_wait);

	skpair = unix_peer(sk);

	if (skpair != NULL) {
		if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
			unix_state_lock(skpair);
			/* No more writes */
			skpair->sk_shutdown = SHUTDOWN_MASK;
			if (!skb_queue_empty(&sk->sk_receive_queue) || embrion)
				skpair->sk_err = ECONNRESET;
			unix_state_unlock(skpair);
			skpair->sk_state_change(skpair);
			sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
		}
		sock_put(skpair); /* It may now die */
		unix_peer(sk) = NULL;
	}

	/* Try to flush out this socket. Throw out buffers at least */

	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
		if (state == TCP_LISTEN)
			unix_release_sock(skb->sk, 1);
		/* passed fds are erased in the kfree_skb hook	      */
		kfree_skb(skb);
	}

	if (path.dentry)
		path_put(&path);

	sock_put(sk);

	/* ---- Socket is dead now and most probably destroyed ---- */

	/*
	 * Fixme: BSD difference: In BSD all sockets connected to us get
	 *	  ECONNRESET and we die on the spot. In Linux we behave
	 *	  like files and pipes do and wait for the last
	 *	  dereference.
	 *
	 * Can't we simply set sock->err?
	 *
	 *	  What the above comment does talk about? --ANK(980817)
	 */

	if (unix_tot_inflight)
		unix_gc();		/* Garbage collect fds */
}

Project: linux
File: af_unix.c

static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
{
	int err = 0;

	UNIXCB(skb).pid  = get_pid(scm->pid);
	UNIXCB(skb).uid = scm->creds.uid;
	UNIXCB(skb).gid = scm->creds.gid;
	UNIXCB(skb).fp = NULL;
	if (scm->fp && send_fds)
		err = unix_attach_fds(scm, skb);

	skb->destructor = unix_destruct_scm;
	return err;
}

Project: linux
File: af_vsock.c

static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr,
				int addr_len, int flags)
{
	int err;
	struct sock *sk;
	struct vsock_sock *vsk;
	struct sockaddr_vm *remote_addr;
	long timeout;
	DEFINE_WAIT(wait);

	err = 0;
	sk = sock->sk;
	vsk = vsock_sk(sk);

	lock_sock(sk);

	/* XXX AF_UNSPEC should make us disconnect like AF_INET. */
	switch (sock->state) {
	case SS_CONNECTED:
		err = -EISCONN;
		goto out;
	case SS_DISCONNECTING:
		err = -EINVAL;
		goto out;
	case SS_CONNECTING:
		/* This continues on so we can move sock into the SS_CONNECTED
		 * state once the connection has completed (at which point err
		 * will be set to zero also).  Otherwise, we will either wait
		 * for the connection or return -EALREADY should this be a
		 * non-blocking call.
		 */
		err = -EALREADY;
		break;
	default:
		if ((sk->sk_state == SS_LISTEN) ||
		    vsock_addr_cast(addr, addr_len, &remote_addr) != 0) {
			err = -EINVAL;
			goto out;
		}

		/* The hypervisor and well-known contexts do not have socket
		 * endpoints.
		 */
		if (!transport->stream_allow(remote_addr->svm_cid,
					     remote_addr->svm_port)) {
			err = -ENETUNREACH;
			goto out;
		}

		/* Set the remote address that we are connecting to. */
		memcpy(&vsk->remote_addr, remote_addr,
		       sizeof(vsk->remote_addr));

		err = vsock_auto_bind(vsk);
		if (err)
			goto out;

		sk->sk_state = SS_CONNECTING;

		err = transport->connect(vsk);
		if (err < 0)
			goto out;

		/* Mark sock as connecting and set the error code to in
		 * progress in case this is a non-blocking connect.
		 */
		sock->state = SS_CONNECTING;
		err = -EINPROGRESS;
	}

	/* The receive path will handle all communication until we are able to
	 * enter the connected state.  Here we wait for the connection to be
	 * completed or a notification of an error.
	 */
	timeout = vsk->connect_timeout;
	prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);

	while (sk->sk_state != SS_CONNECTED && sk->sk_err == 0) {
		if (flags & O_NONBLOCK) {
			/* If we're not going to block, we schedule a timeout
			 * function to generate a timeout on the connection
			 * attempt, in case the peer doesn't respond in a
			 * timely manner. We hold on to the socket until the
			 * timeout fires.
			 */
			sock_hold(sk);
			INIT_DELAYED_WORK(&vsk->dwork,
					  vsock_connect_timeout);
			schedule_delayed_work(&vsk->dwork, timeout);

			/* Skip ahead to preserve error code set above. */
			goto out_wait;
		}

		release_sock(sk);
		timeout = schedule_timeout(timeout);
		lock_sock(sk);

		if (signal_pending(current)) {
			err = sock_intr_errno(timeout);
			goto out_wait_error;
		} else if (timeout == 0) {
			err = -ETIMEDOUT;
			goto out_wait_error;
		}

		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
	}

	if (sk->sk_err) {
		err = -sk->sk_err;
		goto out_wait_error;
	} else
		err = 0;

out_wait:
	finish_wait(sk_sleep(sk), &wait);
out:
	release_sock(sk);
	return err;

out_wait_error:
	sk->sk_state = SS_UNCONNECTED;
	sock->state = SS_UNCONNECTED;
	goto out_wait;
}

Project: linux
File: vmci_transport.c

static u32 vmci_transport_peer_rid(u32 peer_cid)
{
	if (VMADDR_CID_HYPERVISOR == peer_cid)
		return VMCI_TRANSPORT_HYPERVISOR_PACKET_RID;

	return VMCI_TRANSPORT_PACKET_RID;
}

Project: linux
File: vmci_transport.c

static bool vmci_transport_stream_allow(u32 cid, u32 port)
{
	static const u32 non_socket_contexts[] = {
		VMADDR_CID_RESERVED,
	};
	int i;

	BUILD_BUG_ON(sizeof(cid) != sizeof(*non_socket_contexts));

	for (i = 0; i < ARRAY_SIZE(non_socket_contexts); i++) {
		if (cid == non_socket_contexts[i])
			return false;
	}

	return true;
}

Project: linux
File: af_x25.c

static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
		       int addr_len, int flags)
{
	struct sock *sk = sock->sk;
	struct x25_sock *x25 = x25_sk(sk);
	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
	struct x25_route *rt;
	int rc = 0;

	lock_sock(sk);
	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
		sock->state = SS_CONNECTED;
		goto out; /* Connect completed during a ERESTARTSYS event */
	}

	rc = -ECONNREFUSED;
	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
		sock->state = SS_UNCONNECTED;
		goto out;
	}

	rc = -EISCONN;	/* No reconnect on a seqpacket socket */
	if (sk->sk_state == TCP_ESTABLISHED)
		goto out;

	sk->sk_state   = TCP_CLOSE;
	sock->state = SS_UNCONNECTED;

	rc = -EINVAL;
	if (addr_len != sizeof(struct sockaddr_x25) ||
	    addr->sx25_family != AF_X25)
		goto out;

	rc = -ENETUNREACH;
	rt = x25_get_route(&addr->sx25_addr);
	if (!rt)
		goto out;

	x25->neighbour = x25_get_neigh(rt->dev);
	if (!x25->neighbour)
		goto out_put_route;

	x25_limit_facilities(&x25->facilities, x25->neighbour);

	x25->lci = x25_new_lci(x25->neighbour);
	if (!x25->lci)
		goto out_put_neigh;

	rc = -EINVAL;
	if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
		goto out_put_neigh;

	if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
		memset(&x25->source_addr, '\0', X25_ADDR_LEN);

	x25->dest_addr = addr->sx25_addr;

	/* Move to connecting socket, start sending Connect Requests */
	sock->state   = SS_CONNECTING;
	sk->sk_state  = TCP_SYN_SENT;

	x25->state = X25_STATE_1;

	x25_write_internal(sk, X25_CALL_REQUEST);

	x25_start_heartbeat(sk);
	x25_start_t21timer(sk);

	/* Now the loop */
	rc = -EINPROGRESS;
	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
		goto out_put_neigh;

	rc = x25_wait_for_connection_establishment(sk);
	if (rc)
		goto out_put_neigh;

	sock->state = SS_CONNECTED;
	rc = 0;
out_put_neigh:
	if (rc)
		x25_neigh_put(x25->neighbour);
out_put_route:
	x25_route_put(rt);
out:
	release_sock(sk);
	return rc;
}

Project: linux
File: af_x25.c

static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	struct sock *sk = sock->sk;
	struct x25_sock *x25 = x25_sk(sk);
	void __user *argp = (void __user *)arg;
	int rc;

	switch (cmd) {
	case TIOCOUTQ: {
		int amount;

		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
		if (amount < 0)
			amount = 0;
		rc = put_user(amount, (unsigned int __user *)argp);
		break;
	}

	case TIOCINQ: {
		struct sk_buff *skb;
		int amount = 0;
		/*
		 * These two are safe on a single CPU system as
		 * only user tasks fiddle here
		 */
		lock_sock(sk);
		if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
			amount = skb->len;
		release_sock(sk);
		rc = put_user(amount, (unsigned int __user *)argp);
		break;
	}

	case SIOCGSTAMP:
		rc = -EINVAL;
		if (sk)
			rc = sock_get_timestamp(sk,
						(struct timeval __user *)argp);
		break;
	case SIOCGSTAMPNS:
		rc = -EINVAL;
		if (sk)
			rc = sock_get_timestampns(sk,
					(struct timespec __user *)argp);
		break;
	case SIOCGIFADDR:
	case SIOCSIFADDR:
	case SIOCGIFDSTADDR:
	case SIOCSIFDSTADDR:
	case SIOCGIFBRDADDR:
	case SIOCSIFBRDADDR:
	case SIOCGIFNETMASK:
	case SIOCSIFNETMASK:
	case SIOCGIFMETRIC:
	case SIOCSIFMETRIC:
		rc = -EINVAL;
		break;
	case SIOCADDRT:
	case SIOCDELRT:
		rc = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			break;
		rc = x25_route_ioctl(cmd, argp);
		break;
	case SIOCX25GSUBSCRIP:
		rc = x25_subscr_ioctl(cmd, argp);
		break;
	case SIOCX25SSUBSCRIP:
		rc = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			break;
		rc = x25_subscr_ioctl(cmd, argp);
		break;
	case SIOCX25GFACILITIES: {
		lock_sock(sk);
		rc = copy_to_user(argp, &x25->facilities,
				  sizeof(x25->facilities))
			? -EFAULT : 0;
		release_sock(sk);
		break;
	}

	case SIOCX25SFACILITIES: {
		struct x25_facilities facilities;
		rc = -EFAULT;
		if (copy_from_user(&facilities, argp, sizeof(facilities)))
			break;
		rc = -EINVAL;
		lock_sock(sk);
		if (sk->sk_state != TCP_LISTEN &&
		    sk->sk_state != TCP_CLOSE)
			goto out_fac_release;
		if (facilities.pacsize_in < X25_PS16 ||
		    facilities.pacsize_in > X25_PS4096)
			goto out_fac_release;
		if (facilities.pacsize_out < X25_PS16 ||
		    facilities.pacsize_out > X25_PS4096)
			goto out_fac_release;
		if (facilities.winsize_in < 1 ||
		    facilities.winsize_in > 127)
			goto out_fac_release;
		if (facilities.throughput) {
			int out = facilities.throughput & 0xf0;
			int in  = facilities.throughput & 0x0f;
			if (!out)
				facilities.throughput |=
					X25_DEFAULT_THROUGHPUT << 4;
			else if (out < 0x30 || out > 0xD0)
				goto out_fac_release;
			if (!in)
				facilities.throughput |=
					X25_DEFAULT_THROUGHPUT;
			else if (in < 0x03 || in > 0x0D)
				goto out_fac_release;
		}
		if (facilities.reverse &&
		    (facilities.reverse & 0x81) != 0x81)
			goto out_fac_release;
		x25->facilities = facilities;
		rc = 0;
out_fac_release:
		release_sock(sk);
		break;
	}

	case SIOCX25GDTEFACILITIES: {
		lock_sock(sk);
		rc = copy_to_user(argp, &x25->dte_facilities,
				  sizeof(x25->dte_facilities));
		release_sock(sk);
		if (rc)
			rc = -EFAULT;
		break;
	}

	case SIOCX25SDTEFACILITIES: {
		struct x25_dte_facilities dtefacs;
		rc = -EFAULT;
		if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
			break;
		rc = -EINVAL;
		lock_sock(sk);
		if (sk->sk_state != TCP_LISTEN &&
		    sk->sk_state != TCP_CLOSE)
			goto out_dtefac_release;
		if (dtefacs.calling_len > X25_MAX_AE_LEN)
			goto out_dtefac_release;
		if (dtefacs.calling_ae == NULL)
			goto out_dtefac_release;
		if (dtefacs.called_len > X25_MAX_AE_LEN)
			goto out_dtefac_release;
		if (dtefacs.called_ae == NULL)
			goto out_dtefac_release;
		x25->dte_facilities = dtefacs;
		rc = 0;
out_dtefac_release:
		release_sock(sk);
		break;
	}

	case SIOCX25GCALLUSERDATA: {
		lock_sock(sk);
		rc = copy_to_user(argp, &x25->calluserdata,
				  sizeof(x25->calluserdata))
			? -EFAULT : 0;
		release_sock(sk);
		break;
	}

	case SIOCX25SCALLUSERDATA: {
		struct x25_calluserdata calluserdata;

		rc = -EFAULT;
		if (copy_from_user(&calluserdata, argp, sizeof(calluserdata)))
			break;
		rc = -EINVAL;
		if (calluserdata.cudlength > X25_MAX_CUD_LEN)
			break;
		lock_sock(sk);
		x25->calluserdata = calluserdata;
		release_sock(sk);
		rc = 0;
		break;
	}

	case SIOCX25GCAUSEDIAG: {
		lock_sock(sk);
		rc = copy_to_user(argp, &x25->causediag, sizeof(x25->causediag))
			? -EFAULT : 0;
		release_sock(sk);
		break;
	}

	case SIOCX25SCAUSEDIAG: {
		struct x25_causediag causediag;
		rc = -EFAULT;
		if (copy_from_user(&causediag, argp, sizeof(causediag)))
			break;
		lock_sock(sk);
		x25->causediag = causediag;
		release_sock(sk);
		rc = 0;
		break;

	}

	case SIOCX25SCUDMATCHLEN: {
		struct x25_subaddr sub_addr;
		rc = -EINVAL;
		lock_sock(sk);
		if(sk->sk_state != TCP_CLOSE)
			goto out_cud_release;
		rc = -EFAULT;
		if (copy_from_user(&sub_addr, argp,
				   sizeof(sub_addr)))
			goto out_cud_release;
		rc = -EINVAL;
		if (sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
			goto out_cud_release;
		x25->cudmatchlength = sub_addr.cudmatchlength;
		rc = 0;
out_cud_release:
		release_sock(sk);
		break;
	}

	case SIOCX25CALLACCPTAPPRV: {
		rc = -EINVAL;
		lock_sock(sk);
		if (sk->sk_state == TCP_CLOSE) {
			clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags);
			rc = 0;
		}
		release_sock(sk);
		break;
	}

	case SIOCX25SENDCALLACCPT:  {
		rc = -EINVAL;
		lock_sock(sk);
		if (sk->sk_state != TCP_ESTABLISHED)
			goto out_sendcallaccpt_release;
		/* must call accptapprv above */
		if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags))
			goto out_sendcallaccpt_release;
		x25_write_internal(sk, X25_CALL_ACCEPTED);
		x25->state = X25_STATE_3;
		rc = 0;
out_sendcallaccpt_release:
		release_sock(sk);
		break;
	}

	default:
		rc = -ENOIOCTLCMD;
		break;
	}

	return rc;
}

Project: linux
File: af_x25.c

static struct sock *x25_make_new(struct sock *osk)
{
	struct sock *sk = NULL;
	struct x25_sock *x25, *ox25;

	if (osk->sk_type != SOCK_SEQPACKET)
		goto out;

	if ((sk = x25_alloc_socket(sock_net(osk))) == NULL)
		goto out;

	x25 = x25_sk(sk);

	sk->sk_type        = osk->sk_type;
	sk->sk_priority    = osk->sk_priority;
	sk->sk_protocol    = osk->sk_protocol;
	sk->sk_rcvbuf      = osk->sk_rcvbuf;
	sk->sk_sndbuf      = osk->sk_sndbuf;
	sk->sk_state       = TCP_ESTABLISHED;
	sk->sk_backlog_rcv = osk->sk_backlog_rcv;
	sock_copy_flags(sk, osk);

	ox25 = x25_sk(osk);
	x25->t21        = ox25->t21;
	x25->t22        = ox25->t22;
	x25->t23        = ox25->t23;
	x25->t2         = ox25->t2;
	x25->flags	= ox25->flags;
	x25->facilities = ox25->facilities;
	x25->dte_facilities = ox25->dte_facilities;
	x25->cudmatchlength = ox25->cudmatchlength;

	clear_bit(X25_INTERRUPT_FLAG, &x25->flags);
	x25_init_timers(sk);
out:
	return sk;
}

Project: linux
File: af_x25.c

static void x25_remove_socket(struct sock *sk)
{
	write_lock_bh(&x25_list_lock);
	sk_del_node_init(sk);
	write_unlock_bh(&x25_list_lock);
}

Project: linux
File: af_x25.c

int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
			unsigned int lci)
{
	struct sock *sk;
	struct sock *make;
	struct x25_sock *makex25;
	struct x25_address source_addr, dest_addr;
	struct x25_facilities facilities;
	struct x25_dte_facilities dte_facilities;
	int len, addr_len, rc;

	/*
	 *	Remove the LCI and frame type.
	 */
	skb_pull(skb, X25_STD_MIN_LEN);

	/*
	 *	Extract the X.25 addresses and convert them to ASCII strings,
	 *	and remove them.
	 *
	 *	Address block is mandatory in call request packets
	 */
	addr_len = x25_parse_address_block(skb, &source_addr, &dest_addr);
	if (addr_len <= 0)
		goto out_clear_request;
	skb_pull(skb, addr_len);

	/*
	 *	Get the length of the facilities, skip past them for the moment
	 *	get the call user data because this is needed to determine
	 *	the correct listener
	 *
	 *	Facilities length is mandatory in call request packets
	 */
	if (!pskb_may_pull(skb, 1))
		goto out_clear_request;
	len = skb->data[0] + 1;
	if (!pskb_may_pull(skb, len))
		goto out_clear_request;
	skb_pull(skb,len);

	/*
	 *	Ensure that the amount of call user data is valid.
	 */
	if (skb->len > X25_MAX_CUD_LEN)
		goto out_clear_request;

	/*
	 *	Get all the call user data so it can be used in
	 *	x25_find_listener and skb_copy_from_linear_data up ahead.
	 */
	if (!pskb_may_pull(skb, skb->len))
		goto out_clear_request;

	/*
	 *	Find a listener for the particular address/cud pair.
	 */
	sk = x25_find_listener(&source_addr,skb);
	skb_push(skb,len);

	if (sk != NULL && sk_acceptq_is_full(sk)) {
		goto out_sock_put;
	}

	/*
	 *	We dont have any listeners for this incoming call.
	 *	Try forwarding it.
	 */
	if (sk == NULL) {
		skb_push(skb, addr_len + X25_STD_MIN_LEN);
		if (sysctl_x25_forward &&
				x25_forward_call(&dest_addr, nb, skb, lci) > 0)
		{
			/* Call was forwarded, dont process it any more */
			kfree_skb(skb);
			rc = 1;
			goto out;
		} else {
			/* No listeners, can't forward, clear the call */
			goto out_clear_request;
		}
	}

	/*
	 *	Try to reach a compromise on the requested facilities.
	 */
	len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities);
	if (len == -1)
		goto out_sock_put;

	/*
	 * current neighbour/link might impose additional limits
	 * on certain facilties
	 */

	x25_limit_facilities(&facilities, nb);

	/*
	 *	Try to create a new socket.
	 */
	make = x25_make_new(sk);
	if (!make)
		goto out_sock_put;

	/*
	 *	Remove the facilities
	 */
	skb_pull(skb, len);

	skb->sk     = make;
	make->sk_state = TCP_ESTABLISHED;

	makex25 = x25_sk(make);
	makex25->lci           = lci;
	makex25->dest_addr     = dest_addr;
	makex25->source_addr   = source_addr;
	makex25->neighbour     = nb;
	makex25->facilities    = facilities;
	makex25->dte_facilities= dte_facilities;
	makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
	/* ensure no reverse facil on accept */
	makex25->vc_facil_mask &= ~X25_MASK_REVERSE;
	/* ensure no calling address extension on accept */
	makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE;
	makex25->cudmatchlength = x25_sk(sk)->cudmatchlength;

	/* Normally all calls are accepted immediately */
	if (test_bit(X25_ACCPT_APPRV_FLAG, &makex25->flags)) {
		x25_write_internal(make, X25_CALL_ACCEPTED);
		makex25->state = X25_STATE_3;
	}

	/*
	 *	Incoming Call User Data.
	 */
	skb_copy_from_linear_data(skb, makex25->calluserdata.cuddata, skb->len);
	makex25->calluserdata.cudlength = skb->len;

	sk->sk_ack_backlog++;

	x25_insert_socket(make);

	skb_queue_head(&sk->sk_receive_queue, skb);

	x25_start_heartbeat(make);

	if (!sock_flag(sk, SOCK_DEAD))
		sk->sk_data_ready(sk, skb->len);
	rc = 1;
	sock_put(sk);
out:
	return rc;
out_sock_put:
	sock_put(sk);
out_clear_request:
	rc = 0;
	x25_transmit_clear_request(nb, lci, 0x01);
	goto out;
}