socket.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* $Id: socket.c,v 1.6 2002/02/08 03:57:14 davem Exp $
  2. * socket.c: Socket syscall emulation for Solaris 2.6+
  3. *
  4. * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
  5. *
  6. * 1999-08-19 Fixed socketpair code
  7. * Jason Rappleye (rappleye@ccr.buffalo.edu)
  8. */
  9. #include <linux/types.h>
  10. #include <linux/smp_lock.h>
  11. #include <linux/mm.h>
  12. #include <linux/slab.h>
  13. #include <linux/socket.h>
  14. #include <linux/file.h>
  15. #include <linux/net.h>
  16. #include <linux/compat.h>
  17. #include <net/compat.h>
  18. #include <net/sock.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/string.h>
  21. #include <asm/oplib.h>
  22. #include <asm/idprom.h>
  23. #include "conv.h"
  24. #define SOCK_SOL_STREAM 2
  25. #define SOCK_SOL_DGRAM 1
  26. #define SOCK_SOL_RAW 4
  27. #define SOCK_SOL_RDM 5
  28. #define SOCK_SOL_SEQPACKET 6
  29. #define SOL_SO_SNDLOWAT 0x1003
  30. #define SOL_SO_RCVLOWAT 0x1004
  31. #define SOL_SO_SNDTIMEO 0x1005
  32. #define SOL_SO_RCVTIMEO 0x1006
  33. #define SOL_SO_STATE 0x2000
  34. #define SOL_SS_NDELAY 0x040
  35. #define SOL_SS_NONBLOCK 0x080
  36. #define SOL_SS_ASYNC 0x100
  37. #define SO_STATE 0x000e
  38. static int socket_check(int family, int type)
  39. {
  40. if (family != PF_UNIX && family != PF_INET)
  41. return -ESOCKTNOSUPPORT;
  42. switch (type) {
  43. case SOCK_SOL_STREAM: type = SOCK_STREAM; break;
  44. case SOCK_SOL_DGRAM: type = SOCK_DGRAM; break;
  45. case SOCK_SOL_RAW: type = SOCK_RAW; break;
  46. case SOCK_SOL_RDM: type = SOCK_RDM; break;
  47. case SOCK_SOL_SEQPACKET: type = SOCK_SEQPACKET; break;
  48. default: return -EINVAL;
  49. }
  50. return type;
  51. }
  52. static int solaris_to_linux_sockopt(int optname)
  53. {
  54. switch (optname) {
  55. case SOL_SO_SNDLOWAT: optname = SO_SNDLOWAT; break;
  56. case SOL_SO_RCVLOWAT: optname = SO_RCVLOWAT; break;
  57. case SOL_SO_SNDTIMEO: optname = SO_SNDTIMEO; break;
  58. case SOL_SO_RCVTIMEO: optname = SO_RCVTIMEO; break;
  59. case SOL_SO_STATE: optname = SO_STATE; break;
  60. };
  61. return optname;
  62. }
  63. asmlinkage int solaris_socket(int family, int type, int protocol)
  64. {
  65. int (*sys_socket)(int, int, int) =
  66. (int (*)(int, int, int))SYS(socket);
  67. type = socket_check (family, type);
  68. if (type < 0) return type;
  69. return sys_socket(family, type, protocol);
  70. }
  71. asmlinkage int solaris_socketpair(int *usockvec)
  72. {
  73. int (*sys_socketpair)(int, int, int, int *) =
  74. (int (*)(int, int, int, int *))SYS(socketpair);
  75. /* solaris socketpair really only takes one arg at the syscall
  76. * level, int * usockvec. The libs apparently take care of
  77. * making sure that family==AF_UNIX and type==SOCK_STREAM. The
  78. * pointer we really want ends up residing in the first (and
  79. * supposedly only) argument.
  80. */
  81. return sys_socketpair(AF_UNIX, SOCK_STREAM, 0, (int *)usockvec);
  82. }
  83. asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen)
  84. {
  85. int (*sys_bind)(int, struct sockaddr *, int) =
  86. (int (*)(int, struct sockaddr *, int))SUNOS(104);
  87. return sys_bind(fd, addr, addrlen);
  88. }
  89. asmlinkage int solaris_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
  90. {
  91. int (*sunos_setsockopt)(int, int, int, u32, int) =
  92. (int (*)(int, int, int, u32, int))SUNOS(105);
  93. optname = solaris_to_linux_sockopt(optname);
  94. if (optname < 0)
  95. return optname;
  96. if (optname == SO_STATE)
  97. return 0;
  98. return sunos_setsockopt(fd, level, optname, optval, optlen);
  99. }
  100. asmlinkage int solaris_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
  101. {
  102. int (*sunos_getsockopt)(int, int, int, u32, u32) =
  103. (int (*)(int, int, int, u32, u32))SUNOS(118);
  104. optname = solaris_to_linux_sockopt(optname);
  105. if (optname < 0)
  106. return optname;
  107. if (optname == SO_STATE)
  108. optname = SOL_SO_STATE;
  109. return sunos_getsockopt(fd, level, optname, optval, optlen);
  110. }
  111. asmlinkage int solaris_connect(int fd, struct sockaddr __user *addr, int addrlen)
  112. {
  113. int (*sys_connect)(int, struct sockaddr __user *, int) =
  114. (int (*)(int, struct sockaddr __user *, int))SYS(connect);
  115. return sys_connect(fd, addr, addrlen);
  116. }
  117. asmlinkage int solaris_accept(int fd, struct sockaddr __user *addr, int __user *addrlen)
  118. {
  119. int (*sys_accept)(int, struct sockaddr __user *, int __user *) =
  120. (int (*)(int, struct sockaddr __user *, int __user *))SYS(accept);
  121. return sys_accept(fd, addr, addrlen);
  122. }
  123. asmlinkage int solaris_listen(int fd, int backlog)
  124. {
  125. int (*sys_listen)(int, int) =
  126. (int (*)(int, int))SUNOS(106);
  127. return sys_listen(fd, backlog);
  128. }
  129. asmlinkage int solaris_shutdown(int fd, int how)
  130. {
  131. int (*sys_shutdown)(int, int) =
  132. (int (*)(int, int))SYS(shutdown);
  133. return sys_shutdown(fd, how);
  134. }
  135. #define MSG_SOL_OOB 0x1
  136. #define MSG_SOL_PEEK 0x2
  137. #define MSG_SOL_DONTROUTE 0x4
  138. #define MSG_SOL_EOR 0x8
  139. #define MSG_SOL_CTRUNC 0x10
  140. #define MSG_SOL_TRUNC 0x20
  141. #define MSG_SOL_WAITALL 0x40
  142. #define MSG_SOL_DONTWAIT 0x80
  143. static int solaris_to_linux_msgflags(int flags)
  144. {
  145. int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE);
  146. if (flags & MSG_SOL_EOR) fl |= MSG_EOR;
  147. if (flags & MSG_SOL_CTRUNC) fl |= MSG_CTRUNC;
  148. if (flags & MSG_SOL_TRUNC) fl |= MSG_TRUNC;
  149. if (flags & MSG_SOL_WAITALL) fl |= MSG_WAITALL;
  150. if (flags & MSG_SOL_DONTWAIT) fl |= MSG_DONTWAIT;
  151. return fl;
  152. }
  153. static int linux_to_solaris_msgflags(int flags)
  154. {
  155. int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE);
  156. if (flags & MSG_EOR) fl |= MSG_SOL_EOR;
  157. if (flags & MSG_CTRUNC) fl |= MSG_SOL_CTRUNC;
  158. if (flags & MSG_TRUNC) fl |= MSG_SOL_TRUNC;
  159. if (flags & MSG_WAITALL) fl |= MSG_SOL_WAITALL;
  160. if (flags & MSG_DONTWAIT) fl |= MSG_SOL_DONTWAIT;
  161. return fl;
  162. }
  163. asmlinkage int solaris_recvfrom(int s, char __user *buf, int len, int flags, u32 from, u32 fromlen)
  164. {
  165. int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *) =
  166. (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
  167. return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), A(from), A(fromlen));
  168. }
  169. asmlinkage int solaris_recv(int s, char __user *buf, int len, int flags)
  170. {
  171. int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *) =
  172. (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
  173. return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL);
  174. }
  175. asmlinkage int solaris_sendto(int s, char __user *buf, int len, int flags, u32 to, u32 tolen)
  176. {
  177. int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *) =
  178. (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(sendto);
  179. return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), A(to), A(tolen));
  180. }
  181. asmlinkage int solaris_send(int s, char *buf, int len, int flags)
  182. {
  183. int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) =
  184. (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto);
  185. return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL);
  186. }
  187. asmlinkage int solaris_getpeername(int fd, struct sockaddr *addr, int *addrlen)
  188. {
  189. int (*sys_getpeername)(int, struct sockaddr *, int *) =
  190. (int (*)(int, struct sockaddr *, int *))SYS(getpeername);
  191. return sys_getpeername(fd, addr, addrlen);
  192. }
  193. asmlinkage int solaris_getsockname(int fd, struct sockaddr *addr, int *addrlen)
  194. {
  195. int (*sys_getsockname)(int, struct sockaddr *, int *) =
  196. (int (*)(int, struct sockaddr *, int *))SYS(getsockname);
  197. return sys_getsockname(fd, addr, addrlen);
  198. }
  199. /* XXX This really belongs in some header file... -DaveM */
  200. #define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
  201. 16 for IP, 16 for IPX,
  202. 24 for IPv6,
  203. about 80 for AX.25 */
  204. struct sol_nmsghdr {
  205. u32 msg_name;
  206. int msg_namelen;
  207. u32 msg_iov;
  208. u32 msg_iovlen;
  209. u32 msg_control;
  210. u32 msg_controllen;
  211. u32 msg_flags;
  212. };
  213. struct sol_cmsghdr {
  214. u32 cmsg_len;
  215. int cmsg_level;
  216. int cmsg_type;
  217. unsigned char cmsg_data[0];
  218. };
  219. static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
  220. struct sol_nmsghdr __user *umsg)
  221. {
  222. u32 tmp1, tmp2, tmp3;
  223. int err;
  224. err = get_user(tmp1, &umsg->msg_name);
  225. err |= __get_user(tmp2, &umsg->msg_iov);
  226. err |= __get_user(tmp3, &umsg->msg_control);
  227. if (err)
  228. return -EFAULT;
  229. kmsg->msg_name = A(tmp1);
  230. kmsg->msg_iov = A(tmp2);
  231. kmsg->msg_control = A(tmp3);
  232. err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
  233. err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
  234. err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
  235. kmsg->msg_flags = solaris_to_linux_msgflags(kmsg->msg_flags);
  236. return err;
  237. }
  238. asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr __user *user_msg, unsigned user_flags)
  239. {
  240. struct socket *sock;
  241. char address[MAX_SOCK_ADDR];
  242. struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
  243. unsigned char ctl[sizeof(struct cmsghdr) + 20];
  244. unsigned char *ctl_buf = ctl;
  245. struct msghdr msg_sys;
  246. int err, ctl_len, iov_size, total_len;
  247. err = -EFAULT;
  248. if (msghdr_from_user32_to_kern(&msg_sys, user_msg))
  249. goto out;
  250. sock = sockfd_lookup(fd, &err);
  251. if (!sock)
  252. goto out;
  253. /* do not move before msg_sys is valid */
  254. err = -EMSGSIZE;
  255. if (msg_sys.msg_iovlen > UIO_MAXIOV)
  256. goto out_put;
  257. /* Check whether to allocate the iovec area*/
  258. err = -ENOMEM;
  259. iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
  260. if (msg_sys.msg_iovlen > UIO_FASTIOV) {
  261. iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
  262. if (!iov)
  263. goto out_put;
  264. }
  265. err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ);
  266. if (err < 0)
  267. goto out_freeiov;
  268. total_len = err;
  269. err = -ENOBUFS;
  270. if (msg_sys.msg_controllen > INT_MAX)
  271. goto out_freeiov;
  272. ctl_len = msg_sys.msg_controllen;
  273. if (ctl_len) {
  274. struct sol_cmsghdr __user *ucmsg = msg_sys.msg_control;
  275. unsigned long *kcmsg;
  276. compat_size_t cmlen;
  277. err = -EINVAL;
  278. if (ctl_len <= sizeof(compat_size_t))
  279. goto out_freeiov;
  280. if (ctl_len > sizeof(ctl)) {
  281. err = -ENOBUFS;
  282. ctl_buf = kmalloc(ctl_len, GFP_KERNEL);
  283. if (!ctl_buf)
  284. goto out_freeiov;
  285. }
  286. __get_user(cmlen, &ucmsg->cmsg_len);
  287. kcmsg = (unsigned long *) ctl_buf;
  288. *kcmsg++ = (unsigned long)cmlen;
  289. err = -EFAULT;
  290. if (copy_from_user(kcmsg, &ucmsg->cmsg_level,
  291. ctl_len - sizeof(compat_size_t)))
  292. goto out_freectl;
  293. msg_sys.msg_control = ctl_buf;
  294. }
  295. msg_sys.msg_flags = solaris_to_linux_msgflags(user_flags);
  296. if (sock->file->f_flags & O_NONBLOCK)
  297. msg_sys.msg_flags |= MSG_DONTWAIT;
  298. err = sock_sendmsg(sock, &msg_sys, total_len);
  299. out_freectl:
  300. if (ctl_buf != ctl)
  301. sock_kfree_s(sock->sk, ctl_buf, ctl_len);
  302. out_freeiov:
  303. if (iov != iovstack)
  304. sock_kfree_s(sock->sk, iov, iov_size);
  305. out_put:
  306. sockfd_put(sock);
  307. out:
  308. return err;
  309. }
  310. asmlinkage int solaris_recvmsg(int fd, struct sol_nmsghdr __user *user_msg, unsigned int user_flags)
  311. {
  312. struct socket *sock;
  313. struct iovec iovstack[UIO_FASTIOV];
  314. struct iovec *iov = iovstack;
  315. struct msghdr msg_sys;
  316. unsigned long cmsg_ptr;
  317. int err, iov_size, total_len, len;
  318. /* kernel mode address */
  319. char addr[MAX_SOCK_ADDR];
  320. /* user mode address pointers */
  321. struct sockaddr __user *uaddr;
  322. int __user *uaddr_len;
  323. if (msghdr_from_user32_to_kern(&msg_sys, user_msg))
  324. return -EFAULT;
  325. sock = sockfd_lookup(fd, &err);
  326. if (!sock)
  327. goto out;
  328. err = -EMSGSIZE;
  329. if (msg_sys.msg_iovlen > UIO_MAXIOV)
  330. goto out_put;
  331. /* Check whether to allocate the iovec area*/
  332. err = -ENOMEM;
  333. iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
  334. if (msg_sys.msg_iovlen > UIO_FASTIOV) {
  335. iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
  336. if (!iov)
  337. goto out_put;
  338. }
  339. /*
  340. * Save the user-mode address (verify_iovec will change the
  341. * kernel msghdr to use the kernel address space)
  342. */
  343. uaddr = (void __user *) msg_sys.msg_name;
  344. uaddr_len = &user_msg->msg_namelen;
  345. err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
  346. if (err < 0)
  347. goto out_freeiov;
  348. total_len = err;
  349. cmsg_ptr = (unsigned long) msg_sys.msg_control;
  350. msg_sys.msg_flags = MSG_CMSG_COMPAT;
  351. if (sock->file->f_flags & O_NONBLOCK)
  352. user_flags |= MSG_DONTWAIT;
  353. err = sock_recvmsg(sock, &msg_sys, total_len, user_flags);
  354. if(err < 0)
  355. goto out_freeiov;
  356. len = err;
  357. if (uaddr != NULL) {
  358. err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
  359. if (err < 0)
  360. goto out_freeiov;
  361. }
  362. err = __put_user(linux_to_solaris_msgflags(msg_sys.msg_flags), &user_msg->msg_flags);
  363. if (err)
  364. goto out_freeiov;
  365. err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
  366. &user_msg->msg_controllen);
  367. if (err)
  368. goto out_freeiov;
  369. err = len;
  370. out_freeiov:
  371. if (iov != iovstack)
  372. sock_kfree_s(sock->sk, iov, iov_size);
  373. out_put:
  374. sockfd_put(sock);
  375. out:
  376. return err;
  377. }