socket.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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