18e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   HIDP implementation for Linux Bluetooth stack (BlueZ).
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License version 2 as
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   published by the Free Software Foundation;
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
138e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
148e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
198e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   SOFTWARE IS DISCLAIMED.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
238c520a59927a5600973782505dbb750d985057c4Gustavo Padovan#include <linux/export.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hidp.h"
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATOstatic struct bt_sock_list hidp_sk_list = {
295c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	.lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
305c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO};
315c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hidp_sock_release(struct socket *sock)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p sk %p", sock, sk);
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
415c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	bt_sock_unlink(&hidp_sk_list, sk);
425c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_orphan(sk);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_put(sk);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *argp = (void __user *) arg;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hidp_connadd_req ca;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hidp_conndel_req cd;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hidp_connlist_req cl;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hidp_conninfo ci;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct socket *csock;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct socket *isock;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("cmd %x arg %lx", cmd, arg);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case HIDPCONNADD:
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_NET_ADMIN))
65bf5b30b8a4416de04f1ac1196281ddb318669464Zhao Hongjiang			return -EPERM;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&ca, argp, sizeof(ca)))
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		csock = sockfd_lookup(ca.ctrl_sock, &err);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!csock)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isock = sockfd_lookup(ca.intr_sock, &err);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!isock) {
7667b23219ce2f78352b0c566a472ff16c1b0fea9aJulia Lawall			sockfd_put(csock);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
805205185d461d5902325e457ca80bd421127b7308David Herrmann		err = hidp_connection_add(&ca, csock, isock);
815205185d461d5902325e457ca80bd421127b7308David Herrmann		if (!err && copy_to_user(argp, &ca, sizeof(ca)))
825205185d461d5902325e457ca80bd421127b7308David Herrmann			err = -EFAULT;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
845205185d461d5902325e457ca80bd421127b7308David Herrmann		sockfd_put(csock);
855205185d461d5902325e457ca80bd421127b7308David Herrmann		sockfd_put(isock);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case HIDPCONNDEL:
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_NET_ADMIN))
91bf5b30b8a4416de04f1ac1196281ddb318669464Zhao Hongjiang			return -EPERM;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&cd, argp, sizeof(cd)))
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
965205185d461d5902325e457ca80bd421127b7308David Herrmann		return hidp_connection_del(&cd);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case HIDPGETCONNLIST:
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&cl, argp, sizeof(cl)))
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cl.cnum <= 0)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = hidp_get_connlist(&cl);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!err && copy_to_user(argp, &cl, sizeof(cl)))
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case HIDPGETCONNINFO:
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&ci, argp, sizeof(ci)))
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = hidp_get_conninfo(&ci);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!err && copy_to_user(argp, &ci, sizeof(ci)))
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann#ifdef CONFIG_COMPAT
126e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmannstruct compat_hidp_connadd_req {
12717f09a7e4ec5dd6a0d96498da6bf78762fba4468Szymon Janc	int   ctrl_sock;	/* Connected control socket */
12817f09a7e4ec5dd6a0d96498da6bf78762fba4468Szymon Janc	int   intr_sock;	/* Connected interrupt socket */
129e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u16 parser;
130e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u16 rd_size;
131e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	compat_uptr_t rd_data;
132e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u8  country;
133e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u8  subclass;
134e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u16 vendor;
135e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u16 product;
136e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u16 version;
137e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u32 flags;
138e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	__u32 idle_to;
139e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	char  name[128];
140e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann};
141e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
142e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmannstatic int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
143e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann{
144e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	if (cmd == HIDPGETCONNLIST) {
145e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		struct hidp_connlist_req cl;
146816a11d5ced501d368fabe09172f3d62744e8b53Johan Hedberg		u32 uci;
147e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		int err;
148e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
149816a11d5ced501d368fabe09172f3d62744e8b53Johan Hedberg		if (get_user(cl.cnum, (u32 __user *) arg) ||
150e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				get_user(uci, (u32 __user *) (arg + 4)))
151e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann			return -EFAULT;
152e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
153e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		cl.ci = compat_ptr(uci);
154e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
155e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		if (cl.cnum <= 0)
156e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann			return -EINVAL;
157e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
158e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		err = hidp_get_connlist(&cl);
159e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
160816a11d5ced501d368fabe09172f3d62744e8b53Johan Hedberg		if (!err && put_user(cl.cnum, (u32 __user *) arg))
161e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann			err = -EFAULT;
162e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
163e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		return err;
164e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	} else if (cmd == HIDPCONNADD) {
165e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		struct compat_hidp_connadd_req ca;
166e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		struct hidp_connadd_req __user *uca;
167e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
168e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		uca = compat_alloc_user_space(sizeof(*uca));
169e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
17055e747445beec8df1133bb8681c884500546775cAl Viro		if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
171e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann			return -EFAULT;
172e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
173e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
174e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.intr_sock, &uca->intr_sock) ||
175e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.parser, &uca->parser) ||
176a83d6c0de8811d7bcc4eb67ed199d1120ca6cad8Marcel Holtmann				put_user(ca.rd_size, &uca->rd_size) ||
177e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
178e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.country, &uca->country) ||
179e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.subclass, &uca->subclass) ||
180e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.vendor, &uca->vendor) ||
181e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.product, &uca->product) ||
182e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.version, &uca->version) ||
183e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.flags, &uca->flags) ||
184e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				put_user(ca.idle_to, &uca->idle_to) ||
185e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann				copy_to_user(&uca->name[0], &ca.name[0], 128))
186e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann			return -EFAULT;
1878e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
188e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		arg = (unsigned long) uca;
189e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
190e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		/* Fall through. We don't actually write back any _changes_
191e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		   to the structure anyway, so there's no need to copy back
192e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann		   into the original compat version */
193e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	}
194e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
195e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	return hidp_sock_ioctl(sock, cmd, arg);
196e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann}
197e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann#endif
198e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann
19990ddc4f0470427df306f308ad03db6b6b21644b8Eric Dumazetstatic const struct proto_ops hidp_sock_ops = {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family		= PF_BLUETOOTH,
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release	= hidp_sock_release,
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl		= hidp_sock_ioctl,
204e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann#ifdef CONFIG_COMPAT
205e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann	.compat_ioctl	= hidp_sock_compat_ioctl,
206e9c5702e3c5558dade169949abd730173e87ef9cMarcel Holtmann#endif
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bind		= sock_no_bind,
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.getname	= sock_no_getname,
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sendmsg	= sock_no_sendmsg,
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.recvmsg	= sock_no_recvmsg,
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.poll		= sock_no_poll,
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.listen		= sock_no_listen,
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shutdown	= sock_no_shutdown,
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setsockopt	= sock_no_setsockopt,
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.getsockopt	= sock_no_getsockopt,
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.connect	= sock_no_connect,
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.socketpair	= sock_no_socketpair,
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accept		= sock_no_accept,
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mmap		= sock_no_mmap
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proto hidp_proto = {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "HIDP",
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.obj_size	= sizeof(struct bt_sock)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2283f378b684453f2a028eda463ce383370545d9cc9Eric Parisstatic int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
2293f378b684453f2a028eda463ce383370545d9cc9Eric Paris			    int kern)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("sock %p", sock);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sock->type != SOCK_RAW)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESOCKTNOSUPPORT;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2386257ff2177ff02d7f260a7a501876aa41cb9a9f6Pavel Emelyanov	sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sk)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_init_data(sock, sk);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock->ops = &hidp_sock_ops;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock->state = SS_UNCONNECTED;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_reset_flag(sk, SOCK_ZAPPED);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_protocol = protocol;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sk->sk_state	= BT_OPEN;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2535c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	bt_sock_link(&hidp_sk_list, sk);
2545c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
258ec1b4cf74c81bfd0fbe5bf62bafc86c45917e72fStephen Hemmingerstatic const struct net_proto_family hidp_sock_family_ops = {
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family	= PF_BLUETOOTH,
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner	= THIS_MODULE,
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.create	= hidp_sock_create
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init hidp_init_sockets(void)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = proto_register(&hidp_proto, 0);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0)
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
2735c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	if (err < 0) {
2745c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO		BT_ERR("Can't register HIDP socket");
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error;
2765c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	}
2775c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO
278b03166152f6da91cec8b66837b309dd3923ea536Al Viro	err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
2795c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	if (err < 0) {
2805c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO		BT_ERR("Failed to create HIDP proc file");
2815c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO		bt_sock_unregister(BTPROTO_HIDP);
2825c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO		goto error;
2835c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	}
2845c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO
2855c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	BT_INFO("HIDP socket layer initialized");
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror:
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	proto_unregister(&hidp_proto);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit hidp_cleanup_sockets(void)
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2965c6ad8eee0a8c5fb4ba8b741008490da9eb66af6Masatake YAMATO	bt_procfs_cleanup(&init_net, "hidp");
2975e9d7f868f04106139a58212b860dcdc268ad3afDavid Herrmann	bt_sock_unregister(BTPROTO_HIDP);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	proto_unregister(&hidp_proto);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
300