socket.c 12 KB

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