vcom_socket.c revision e1b749ab
1/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <unistd.h>
16#include <stdio.h>
17
18#include <vppinfra/types.h>
19#include <vppinfra/hash.h>
20#include <vppinfra/pool.h>
21
22#include <libvcl-ldpreload/vcom_socket.h>
23#include <libvcl-ldpreload/vcom_socket_wrapper.h>
24#include <libvcl-ldpreload/vcom.h>
25
26#include <uri/vppcom.h>
27
28
29/*
30 * VCOM_SOCKET Private definitions and functions.
31 */
32
33typedef struct vcom_socket_main_t_
34{
35  u8 init;
36
37  /* vcom_socket pool */
38  vcom_socket_t *vsockets;
39
40  /* Hash table for socketidx to fd mapping */
41  uword *sockidx_by_fd;
42
43} vcom_socket_main_t;
44
45vcom_socket_main_t vcom_socket_main;
46
47
48/*
49 * Public API functions
50 */
51int
52vcom_socket_open_socket (int domain, int type, int protocol)
53{
54  int rv = -1;
55
56  /* handle domains implemented by vpp */
57  switch (domain)
58    {
59    case AF_INET:
60    case AF_INET6:
61      /* get socket type and
62       * handle the socket types supported by vpp */
63      switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
64	{
65	case SOCK_STREAM:
66	case SOCK_DGRAM:
67	  /* the type argument serves a second purpose,
68	   * in addition to specifying a socket type,
69	   * it may include the bitwise OR of any of
70	   * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
71	   * the behavior of socket. */
72	  rv = libc_socket (domain, type, protocol);
73	  if (rv == -1)
74	    rv = -errno;
75	  break;
76
77	default:
78	  break;
79	}
80
81      break;
82
83    default:
84      break;
85    }
86
87  return rv;
88}
89
90int
91vcom_socket_close_socket (int fd)
92{
93  int rv;
94
95  rv = libc_close (fd);
96  if (rv == -1)
97    rv = -errno;
98
99  return rv;
100}
101
102int
103vcom_socket_main_init (void)
104{
105  vcom_socket_main_t *vsm = &vcom_socket_main;
106
107  if (VCOM_DEBUG > 0)
108    printf ("vcom_socket_main_init\n");
109
110  if (!vsm->init)
111    {
112      /* TBD: define FD_MAXSIZE and use it here */
113      pool_alloc (vsm->vsockets, FD_SETSIZE);
114      vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
115      vsm->init = 1;
116    }
117
118  return 0;
119}
120
121void
122vcom_socket_main_destroy (void)
123{
124  vcom_socket_main_t *vsm = &vcom_socket_main;
125  vcom_socket_t *vsock;
126
127  if (VCOM_DEBUG > 0)
128    printf ("vcom_socket_main_destroy\n");
129
130  if (vsm->init)
131    {
132      /*
133       * from active list of vsockets,
134       * close socket and vppcom session
135       * */
136
137      /* *INDENT-OFF* */
138      pool_foreach (vsock, vsm->vsockets,
139        ({
140          if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
141            {
142              vppcom_session_close (vsock->sid);
143              vcom_socket_close_socket (vsock->fd);
144              vsocket_init (vsock);
145            }
146        }));
147      /* *INDENT-ON* */
148
149      /*
150       * return vsocket element to the pool
151       * */
152
153      /* *INDENT-OFF* */
154      pool_flush (vsock, vsm->vsockets,
155        ({
156          // vsocket_init(vsock);
157          ;
158        }));
159      /* *INDENT-ON* */
160
161      pool_free (vsm->vsockets);
162      hash_free (vsm->sockidx_by_fd);
163      vsm->init = 0;
164    }
165}
166
167void
168vcom_socket_main_show (void)
169{
170  vcom_socket_main_t *vsm = &vcom_socket_main;
171  vcom_socket_t *vsock;
172
173  if (vsm->init)
174    {
175      /* from active list of vsockets,
176       * close socket and vppcom session */
177
178      /* *INDENT-OFF* */
179      pool_foreach (vsock, vsm->vsockets,
180        ({
181          printf(
182                 "fd='%04d', sid='%08x',type='%-30s'\n",
183                 vsock->fd, vsock->sid,
184                 vcom_socket_type_str (vsock->type));
185        }));
186      /* *INDENT-ON* */
187    }
188}
189
190
191int
192vcom_socket_is_vcom_fd (int fd)
193{
194  vcom_socket_main_t *vsm = &vcom_socket_main;
195  uword *p;
196  vcom_socket_t *vsock;
197
198  p = hash_get (vsm->sockidx_by_fd, fd);
199
200  if (p)
201    {
202      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
203      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
204	return 1;
205    }
206  return 0;
207}
208
209static inline int
210vcom_socket_get_sid (int fd)
211{
212  vcom_socket_main_t *vsm = &vcom_socket_main;
213  uword *p;
214  vcom_socket_t *vsock;
215
216  p = hash_get (vsm->sockidx_by_fd, fd);
217
218  if (p)
219    {
220      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
221      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
222	return vsock->sid;
223    }
224  return INVALID_SESSION_ID;
225}
226
227int
228vcom_socket_close (int __fd)
229{
230  int rv = -1;
231  vcom_socket_main_t *vsm = &vcom_socket_main;
232  uword *p;
233  vcom_socket_t *vsock;
234
235  p = hash_get (vsm->sockidx_by_fd, __fd);
236  if (!p)
237    return -EBADF;
238
239  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
240  if (!vsock)
241    return -ENOTSOCK;
242
243  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
244    return -EINVAL;
245
246  rv = vppcom_session_close (vsock->sid);
247  rv = vcom_socket_close_socket (vsock->fd);
248
249  vsocket_init (vsock);
250  hash_unset (vsm->sockidx_by_fd, __fd);
251  pool_put (vsm->vsockets, vsock);
252
253  return rv;
254}
255
256ssize_t
257vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
258{
259  int rv = -1;
260  vcom_socket_main_t *vsm = &vcom_socket_main;
261  uword *p;
262  vcom_socket_t *vsock;
263
264  p = hash_get (vsm->sockidx_by_fd, __fd);
265  if (!p)
266    return -EBADF;
267
268  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
269  if (!vsock)
270    return -ENOTSOCK;
271
272  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
273    return -EINVAL;
274
275  if (!__buf || __nbytes < 0)
276    {
277      return -EINVAL;
278    }
279
280  rv = vcom_fcntl (__fd, F_GETFL, 0);
281  if (rv < 0)
282    {
283      return rv;
284
285    }
286
287  /* is blocking */
288  if (!(rv & O_NONBLOCK))
289    {
290      do
291	{
292	  rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
293	}
294      while (rv == -EAGAIN || rv == -EWOULDBLOCK);
295      return rv;
296    }
297  /* The file descriptor refers to a socket and has been
298   * marked nonblocking(O_NONBLOCK) and the read would
299   * block.
300   * */
301  /* is non blocking */
302  rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
303  return rv;
304}
305
306ssize_t
307vcom_socket_write (int __fd, const void *__buf, size_t __n)
308{
309  int rv = -1;
310  vcom_socket_main_t *vsm = &vcom_socket_main;
311  uword *p;
312  vcom_socket_t *vsock;
313
314  p = hash_get (vsm->sockidx_by_fd, __fd);
315  if (!p)
316    return -EBADF;
317
318  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
319  if (!vsock)
320    return -ENOTSOCK;
321
322  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
323    return -EINVAL;
324
325  if (!__buf || __n < 0)
326    {
327      return -EINVAL;
328    }
329
330  rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
331  return rv;
332}
333
334/*
335 * RETURN:  0 - invalid cmd
336 *          1 - cmd not handled by vcom and vppcom
337 *          2 - cmd handled by vcom socket resource
338 *          3 - cmd handled by vppcom
339 * */
340/* TBD: incomplete list of cmd */
341static int
342vcom_socket_check_fcntl_cmd (int __cmd)
343{
344  switch (__cmd)
345    {
346      /*cmd not handled by vcom and vppcom */
347      /* Fallthrough */
348    case F_DUPFD:
349    case F_DUPFD_CLOEXEC:
350      return 1;
351
352      /* cmd handled by vcom socket resource */
353      /* Fallthrough */
354    case F_GETFD:
355    case F_SETFD:
356    case F_GETFL:
357    case F_SETFL:
358    case F_GETLK:
359    case F_SETLK:
360    case F_SETLKW:
361    case F_GETOWN:
362    case F_SETOWN:
363      return 2;
364
365#if 0
366      /* cmd handled by vppcom */
367    case F_XXXXX:
368      return 3;
369#endif
370      /* invalid cmd */
371    default:
372      return 0;
373    }
374  return 0;
375}
376
377/* TBD: move it to vppcom */
378static int
379vppcom_session_fcntl_va (int __fd, int __cmd, va_list __ap)
380{
381  int rv;
382
383  rv = -EINVAL;
384
385  return rv;
386}
387
388int
389vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
390{
391  int rv = -EBADF;
392  vcom_socket_main_t *vsm = &vcom_socket_main;
393  uword *p;
394  vcom_socket_t *vsock;
395
396  p = hash_get (vsm->sockidx_by_fd, __fd);
397  if (!p)
398    return -EBADF;
399
400  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
401  if (!vsock)
402    return -ENOTSOCK;
403
404  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
405    return -EINVAL;
406
407  switch (vcom_socket_check_fcntl_cmd (__cmd))
408    {
409      /* invalid cmd */
410    case 0:
411      rv = -EBADF;
412      break;
413      /*cmd not handled by vcom and vppcom */
414    case 1:
415      rv = -EBADF;
416      break;
417      /* cmd handled by vcom socket resource */
418    case 2:
419      rv = libc_vfcntl (vsock->fd, __cmd, __ap);
420      break;
421      /* cmd handled by vppcom */
422    case 3:
423      rv = vppcom_session_fcntl_va (vsock->sid, __cmd, __ap);
424      break;
425
426    default:
427      rv = -EINVAL;
428      break;
429    }
430
431  return rv;
432}
433
434static inline int
435vcom_socket_fds_2_sid_fds (
436			    /* dest */
437			    int *vcom_nsid_fds,
438			    fd_set * __restrict vcom_rd_sid_fds,
439			    fd_set * __restrict vcom_wr_sid_fds,
440			    fd_set * __restrict vcom_ex_sid_fds,
441			    /* src */
442			    int vcom_nfds,
443			    fd_set * __restrict vcom_readfds,
444			    fd_set * __restrict vcom_writefds,
445			    fd_set * __restrict vcom_exceptfds)
446{
447  int rv = 0;
448  int fd;
449  int sid;
450  /* invalid max_sid is -1 */
451  int max_sid = -1;
452  int nsid = 0;
453
454  /*
455   *  set sid in sid sets corresponding to fd's in fd sets
456   *  compute nsid and vcom_nsid_fds from sid sets
457   */
458
459  for (fd = 0; fd < vcom_nfds; fd++)
460    {
461      /*
462       * F fd set, src
463       * S sid set, dest
464       */
465#define _(S,F)                              \
466      if ((F) && (S) && FD_ISSET (fd, (F))) \
467        {                                   \
468          sid = vcom_socket_get_sid (fd);   \
469          if (sid != INVALID_SESSION_ID)    \
470            {                               \
471              FD_SET (sid, (S));            \
472              if (sid > max_sid)            \
473                {                           \
474                  max_sid = sid;            \
475                }                           \
476              ++nsid;                       \
477            }                               \
478          else                              \
479            {                               \
480              rv = -EBADFD;                 \
481              goto done;                    \
482            }                               \
483        }
484
485
486      _(vcom_rd_sid_fds, vcom_readfds);
487      _(vcom_wr_sid_fds, vcom_writefds);
488      _(vcom_ex_sid_fds, vcom_exceptfds);
489#undef _
490    }
491
492  *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
493  rv = nsid;
494
495done:
496  return rv;
497}
498
499/*
500 * PRE: 00. sid sets were derived from fd sets
501 *      01. sid sets were updated with sids that actually changed
502 *          status
503 *      02. fd sets still has watched fds
504 *
505 * This function will modify in place fd sets to indicate which fd's
506 * actually changed status(inferred from sid sets)
507 */
508static inline int
509vcom_socket_sid_fds_2_fds (
510			    /* dest */
511			    int *new_vcom_nfds,
512			    int vcom_nfds,
513			    fd_set * __restrict vcom_readfds,
514			    fd_set * __restrict vcom_writefds,
515			    fd_set * __restrict vcom_exceptfds,
516			    /* src */
517			    int vcom_nsid_fds,
518			    fd_set * __restrict vcom_rd_sid_fds,
519			    fd_set * __restrict vcom_wr_sid_fds,
520			    fd_set * __restrict vcom_ex_sid_fds)
521{
522  int rv = 0;
523  int fd;
524  int sid;
525  /* invalid max_fd is -1 */
526  int max_fd = -1;
527  int nfd = 0;
528
529
530  /*
531   *  modify in place fd sets to indicate which fd's
532   * actually changed status(inferred from sid sets)
533   */
534  for (fd = 0; fd < vcom_nfds; fd++)
535    {
536      /*
537       * F fd set, dest
538       * S sid set, src
539       */
540#define _(S,F)                              \
541      if ((F) && (S) && FD_ISSET (fd, (F))) \
542        {                                   \
543          sid = vcom_socket_get_sid (fd);   \
544          if (sid != INVALID_SESSION_ID)    \
545            {                               \
546              if (!FD_ISSET (sid, (S)))     \
547                {                           \
548                   FD_CLR(fd, (F));         \
549                }                           \
550            }                               \
551          else                              \
552            {                               \
553              rv = -EBADFD;                 \
554              goto done;                    \
555            }                               \
556        }
557
558
559      _(vcom_rd_sid_fds, vcom_readfds);
560      _(vcom_wr_sid_fds, vcom_writefds);
561      _(vcom_ex_sid_fds, vcom_exceptfds);
562#undef _
563    }
564
565  /*
566   *  compute nfd and new_vcom_nfds from fd sets
567   */
568  for (fd = 0; fd < vcom_nfds; fd++)
569    {
570
571#define _(F)                                \
572      if ((F) && FD_ISSET (fd, (F)))        \
573        {                                   \
574          if (fd > max_fd)                  \
575            {                               \
576              max_fd = fd;                  \
577            }                               \
578          ++nfd;                            \
579        }
580
581
582      _(vcom_readfds);
583      _(vcom_writefds);
584      _(vcom_exceptfds);
585#undef _
586
587    }
588
589  *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
590  rv = nfd;
591
592done:
593  return rv;
594}
595
596/*
597 * PRE:
598 * vom_socket_select is always called with
599 * timeout->tv_sec and timeout->tv_usec set to zero.
600 * hence vppcom_select return immediately.
601 */
602/*
603 * TBD: do{body;} while(timeout conditional); timeout loop
604 */
605int
606vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
607		    fd_set * __restrict vcom_writefds,
608		    fd_set * __restrict vcom_exceptfds,
609		    struct timeval *__restrict timeout)
610{
611  int rv = -EBADF;
612  pid_t pid = getpid ();
613
614  int new_vcom_nfds = 0;
615  int new_vcom_nfd = 0;
616
617  /* vcom sid fds */
618  fd_set vcom_rd_sid_fds;
619  fd_set vcom_wr_sid_fds;
620  fd_set vcom_ex_sid_fds;
621  unsigned long vcom_nsid_fds = 0;
622  int vcom_nsid = 0;
623
624  /* in seconds eg. 3.123456789 seconds */
625  double time_to_wait = (double) 0;
626
627  /* validate inputs */
628  if (vcom_nfds < 0)
629    {
630      return -EINVAL;
631    }
632
633  /* convert timeval timeout to double time_to_wait */
634  if (timeout)
635    {
636      if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
637	{
638	  /* polling: vppcom_select returns immediately */
639	  time_to_wait = (double) 0;
640	}
641      else
642	{
643	  /*TBD:  use timeval api */
644	  time_to_wait = (double) timeout->tv_sec +
645	    (double) timeout->tv_usec / (double) 1000000 +
646	    (double) (timeout->tv_usec % 1000000) / (double) 1000000;
647	}
648    }
649  else
650    {
651      /*
652       * no timeout: vppcom_select can block indefinitely
653       * waiting for a file descriptor to become ready
654       * */
655      /* set to a phantom value */
656      time_to_wait = ~0;
657    }
658
659  /* zero the sid_sets */
660  /*
661   * F fd set
662   * S sid set
663   */
664#define _(S,F)                          \
665  if ((F))                              \
666    {                                   \
667      FD_ZERO ((S));                    \
668    }
669
670
671  _(&vcom_rd_sid_fds, vcom_readfds);
672  _(&vcom_wr_sid_fds, vcom_writefds);
673  _(&vcom_ex_sid_fds, vcom_exceptfds);
674#undef _
675
676  /* populate read, write and except sid_sets */
677  vcom_nsid = vcom_socket_fds_2_sid_fds (
678					  /* dest */
679					  vcom_readfds || vcom_writefds
680					  || vcom_exceptfds ? (int *)
681					  &vcom_nsid_fds : NULL,
682					  vcom_readfds ? &vcom_rd_sid_fds :
683					  NULL,
684					  vcom_writefds ? &vcom_wr_sid_fds :
685					  NULL,
686					  vcom_exceptfds ? &vcom_ex_sid_fds :
687					  NULL,
688					  /* src */
689					  vcom_nfds,
690					  vcom_readfds,
691					  vcom_writefds, vcom_exceptfds);
692  if (vcom_nsid < 0)
693    {
694      return vcom_nsid;
695    }
696  if (vcom_nsid_fds < 0)
697    {
698      return -EINVAL;
699    }
700
701  rv = vppcom_select (vcom_nsid_fds,
702		      vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
703		      NULL,
704		      vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
705		      NULL,
706		      vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
707		      NULL, time_to_wait);
708  if (VCOM_DEBUG > 0)
709    fprintf (stderr, "[%d] vppcom_select: "
710	     "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
711
712  /* check if any file descriptors changed status */
713  if (rv > 0)
714    {
715      /*
716       * on exit, sets are modified in place to indicate which
717       * file descriptors actually changed status
718       * */
719
720      /*
721       * comply with pre-condition
722       * do not clear vcom fd sets befor calling
723       * vcom_socket_sid_fds_2_fds
724       */
725      new_vcom_nfd = vcom_socket_sid_fds_2_fds (
726						 /* dest */
727						 &new_vcom_nfds,
728						 vcom_nfds,
729						 vcom_readfds,
730						 vcom_writefds,
731						 vcom_exceptfds,
732						 /* src */
733						 vcom_nsid_fds,
734						 vcom_readfds ?
735						 &vcom_rd_sid_fds : NULL,
736						 vcom_writefds ?
737						 &vcom_wr_sid_fds : NULL,
738						 vcom_exceptfds ?
739						 &vcom_ex_sid_fds : NULL);
740      if (new_vcom_nfd < 0)
741	{
742	  return new_vcom_nfd;
743	}
744      if (new_vcom_nfds < 0)
745	{
746	  return -EINVAL;
747	}
748      rv = new_vcom_nfd;
749    }
750  return rv;
751}
752
753
754int
755vcom_socket_socket (int __domain, int __type, int __protocol)
756{
757  int rv = -1;
758  vcom_socket_main_t *vsm = &vcom_socket_main;
759  vcom_socket_t *vsock;
760
761  i32 fd;
762  i32 sid;
763  i32 sockidx;
764  u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
765  int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
766
767  fd = vcom_socket_open_socket (__domain, __type, __protocol);
768  if (fd < 0)
769    {
770      rv = fd;
771      goto out;
772    }
773
774  sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
775			       (type == SOCK_DGRAM) ?
776			       VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
777			       is_nonblocking);
778  if (sid < 0)
779    {
780      rv = sid;
781      goto out_close_socket;
782    }
783
784  pool_get (vsm->vsockets, vsock);
785  sockidx = vsock - vsm->vsockets;
786  hash_set (vsm->sockidx_by_fd, fd, sockidx);
787
788  vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
789  return fd;
790
791out_close_socket:
792  vcom_socket_close_socket (fd);
793out:
794  return rv;
795}
796
797int
798vcom_socket_socketpair (int __domain, int __type, int __protocol,
799			int __fds[2])
800{
801/* TBD: */
802  return 0;
803}
804
805int
806vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
807{
808  int rv = -1;
809  vcom_socket_main_t *vsm = &vcom_socket_main;
810  uword *p;
811  vcom_socket_t *vsock;
812
813  vppcom_endpt_t ep;
814
815  p = hash_get (vsm->sockidx_by_fd, __fd);
816  if (!p)
817    return -EBADF;
818
819  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
820  if (!vsock)
821    return -ENOTSOCK;
822
823  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
824    return -EINVAL;
825
826  if (!__addr)
827    {
828      return -EINVAL;
829    }
830
831  ep.vrf = VPPCOM_VRF_DEFAULT;
832  switch (__addr->sa_family)
833    {
834    case AF_INET:
835      if (__len != sizeof (struct sockaddr_in))
836	{
837	  return -EINVAL;
838	}
839      ep.is_ip4 = VPPCOM_IS_IP4;
840      ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
841      ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
842      break;
843
844    case AF_INET6:
845      if (__len != sizeof (struct sockaddr_in6))
846	{
847	  return -EINVAL;
848	}
849      ep.is_ip4 = VPPCOM_IS_IP6;
850      ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
851      ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
852      break;
853
854    default:
855      return -1;
856      break;
857    }
858
859  rv = vppcom_session_bind (vsock->sid, &ep);
860  /* TBD: remove libc_bind code snippet
861   * once vppcom implements vppcom_session_getsockname */
862  if (rv == 0)
863    {
864      rv = libc_bind (__fd, __addr, __len);
865      if (rv != 0)
866	{
867	  rv = -errno;
868	}
869    }
870  return rv;
871}
872
873int
874vppcom_session_getsockname (int sid, vppcom_endpt_t * ep)
875{
876  /* TBD: move it to vppcom */
877  return 0;
878}
879
880int
881vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
882			 socklen_t * __restrict __len)
883{
884  int rv = -1;
885  vcom_socket_main_t *vsm = &vcom_socket_main;
886  uword *p;
887  vcom_socket_t *vsock;
888
889
890  p = hash_get (vsm->sockidx_by_fd, __fd);
891  if (!p)
892    return -EBADF;
893
894  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
895  if (!vsock)
896    return -ENOTSOCK;
897
898  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
899    return -EINVAL;
900
901  if (!__addr || !__len)
902    return -EFAULT;
903
904  if (*__len < 0)
905    {
906      return -EINVAL;
907    }
908
909  /* TBD: remove libc_getsockname code snippet
910   * once vppcom implements vppcom_session_getsockname */
911  rv = libc_getsockname (__fd, __addr, __len);
912  if (rv != 0)
913    {
914      rv = -errno;
915      return rv;
916    }
917
918  /* TBD: use the below code snippet when vppcom
919   * implements vppcom_session_getsockname */
920#if 0
921  vppcom_endpt_t ep;
922  ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
923  rv = vppcom_session_getsockname (vsock->sid, &ep);
924  if (rv == 0)
925    {
926      if (ep.vrf == VPPCOM_VRF_DEFAULT)
927	{
928	  __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
929	  switch (__addr->sa_family)
930	    {
931	    case AF_INET:
932	      ((struct sockaddr_in *) __addr)->sin_port = ep.port;
933	      *__len = sizeof (struct sockaddr_in);
934	      break;
935
936	    case AF_INET6:
937	      ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
938	      *__len = sizeof (struct sockaddr_in6);
939	      break;
940
941	    default:
942	      break;
943	    }
944	}
945    }
946#endif
947
948  return rv;
949}
950
951int
952vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
953{
954  int rv = -1;
955  vcom_socket_main_t *vsm = &vcom_socket_main;
956  uword *p;
957  vcom_socket_t *vsock;
958
959  vppcom_endpt_t ep;
960
961  p = hash_get (vsm->sockidx_by_fd, __fd);
962  if (p)
963    {
964      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
965
966      ep.vrf = VPPCOM_VRF_DEFAULT;
967      switch (__addr->sa_family)
968	{
969	case AF_INET:
970	  ep.is_ip4 = VPPCOM_IS_IP4;
971	  ep.ip =
972	    (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
973	  ep.port =
974	    (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
975	  break;
976
977	case AF_INET6:
978	  ep.is_ip4 = VPPCOM_IS_IP6;
979	  ep.ip =
980	    (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
981	  ep.port =
982	    (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
983	  break;
984
985	default:
986	  return -1;
987	  break;
988	}
989
990      rv = vppcom_session_connect (vsock->sid, &ep);
991    }
992  return rv;
993}
994
995int
996vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
997{
998  /* TBD: move it to vppcom */
999  return 0;
1000}
1001
1002int
1003vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1004			 socklen_t * __restrict __len)
1005{
1006  int rv = -1;
1007  vcom_socket_main_t *vsm = &vcom_socket_main;
1008  uword *p;
1009  vcom_socket_t *vsock;
1010
1011
1012  p = hash_get (vsm->sockidx_by_fd, __fd);
1013  if (!p)
1014    return -EBADF;
1015
1016  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1017  if (!vsock)
1018    return -ENOTSOCK;
1019
1020  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1021    return -EINVAL;
1022
1023  if (!__addr || !__len)
1024    return -EFAULT;
1025
1026  if (*__len < 0)
1027    {
1028      return -EINVAL;
1029    }
1030
1031  /* DAW: hack to allow iperf3 to be happy w/ getpeername output */
1032  {
1033    uint8_t *a;
1034    ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1035    ((struct sockaddr_in *) __addr)->sin_port = 0x1000;
1036    a = (uint8_t *) & ((struct sockaddr_in *) __addr)->sin_addr;
1037    a[0] = 0x7f;
1038    a[1] = 0x00;
1039    a[2] = 0x00;
1040    a[3] = 0x01;
1041    *__len = sizeof (struct sockaddr_in);
1042    return 0;
1043  }
1044
1045  /* TBD: remove libc_getpeername code snippet
1046   * once vppcom implements vppcom_session_getpeername */
1047  rv = libc_getpeername (__fd, __addr, __len);
1048  if (rv != 0)
1049    {
1050      rv = -errno;
1051      return rv;
1052    }
1053
1054  /* TBD: use the below code snippet when vppcom
1055   * implements vppcom_session_getpeername */
1056#if 0
1057  vppcom_endpt_t ep;
1058  ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1059  rv = vppcom_session_getpeername (vsock->sid, &ep);
1060  if (rv == 0)
1061    {
1062      if (ep.vrf == VPPCOM_VRF_DEFAULT)
1063	{
1064	  __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1065	  switch (__addr->sa_family)
1066	    {
1067	    case AF_INET:
1068	      ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1069	      *__len = sizeof (struct sockaddr_in);
1070	      break;
1071
1072	    case AF_INET6:
1073	      ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1074	      *__len = sizeof (struct sockaddr_in6);
1075	      break;
1076
1077	    default:
1078	      break;
1079	    }
1080	}
1081    }
1082#endif
1083
1084  return rv;
1085}
1086
1087ssize_t
1088vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1089{
1090  return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1091}
1092
1093ssize_t
1094vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1095{
1096  int rv = -1;
1097  rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1098  return rv;
1099}
1100
1101/*
1102 * RETURN   1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1103 * 0 otherwise
1104 * */
1105int
1106vcom_socket_is_connection_mode_socket (int __fd)
1107{
1108  int rv = -1;
1109  /* TBD define new vppcom api */
1110  vcom_socket_main_t *vsm = &vcom_socket_main;
1111  uword *p;
1112  vcom_socket_t *vsock;
1113
1114  int type;
1115  socklen_t optlen;
1116
1117  p = hash_get (vsm->sockidx_by_fd, __fd);
1118
1119  if (p)
1120    {
1121      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1122      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1123	{
1124	  optlen = sizeof (type);
1125	  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1126	  if (rv != 0)
1127	    {
1128	      return 0;
1129	    }
1130	  /* get socket type */
1131	  switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1132	    {
1133	    case SOCK_STREAM:
1134	    case SOCK_SEQPACKET:
1135	      return 1;
1136	      break;
1137
1138	    default:
1139	      return 0;
1140	      break;
1141	    }
1142	}
1143    }
1144  return 0;
1145}
1146
1147ssize_t
1148vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
1149			int __flags, __CONST_SOCKADDR_ARG __addr,
1150			socklen_t __addr_len)
1151{
1152  int rv = -1;
1153  /* TBD add new vpp api  */
1154  /* TBD add flags parameter */
1155  rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1156  return rv;
1157}
1158
1159ssize_t
1160vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1161		    int __flags, __CONST_SOCKADDR_ARG __addr,
1162		    socklen_t __addr_len)
1163{
1164  int rv = -1;
1165  vcom_socket_main_t *vsm = &vcom_socket_main;
1166  uword *p;
1167  vcom_socket_t *vsock;
1168
1169  p = hash_get (vsm->sockidx_by_fd, __fd);
1170  if (!p)
1171    return -EBADF;
1172
1173  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1174  if (!vsock)
1175    return -ENOTSOCK;
1176
1177  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1178    return -EINVAL;
1179
1180  if (!__buf || __n < 0)
1181    {
1182      return -EINVAL;
1183    }
1184
1185  if (vcom_socket_is_connection_mode_socket (__fd))
1186    {
1187      /* ignore __addr and _addr_len */
1188      /* and EISCONN may be returned when they are not NULL and 0 */
1189      if ((__addr != NULL) || (__addr_len != 0))
1190	{
1191	  return -EISCONN;
1192	}
1193    }
1194  else
1195    {
1196      if (!__addr || __addr_len < 0)
1197	{
1198	  return -EDESTADDRREQ;
1199	}
1200      /* not a vppcom supported address family */
1201      if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1202	{
1203	  return -EINVAL;
1204	}
1205    }
1206
1207  rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1208			       __flags, __addr, __addr_len);
1209  return rv;
1210}
1211
1212/* TBD: move it to vppcom */
1213static ssize_t
1214vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1215			 int __flags, __SOCKADDR_ARG __addr,
1216			 socklen_t * __restrict __addr_len)
1217{
1218  int rv = -1;
1219
1220  /* TBD add flags parameter */
1221  rv = vppcom_session_read (__sid, __buf, __n);
1222  return rv;
1223}
1224
1225ssize_t
1226vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1227		      int __flags, __SOCKADDR_ARG __addr,
1228		      socklen_t * __restrict __addr_len)
1229{
1230  int rv = -1;
1231  vcom_socket_main_t *vsm = &vcom_socket_main;
1232  uword *p;
1233  vcom_socket_t *vsock;
1234
1235  p = hash_get (vsm->sockidx_by_fd, __fd);
1236  if (!p)
1237    return -EBADF;
1238
1239  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1240  if (!vsock)
1241    return -ENOTSOCK;
1242
1243  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1244    return -EINVAL;
1245
1246  if (!__buf || __n < 0)
1247    {
1248      return -EINVAL;
1249    }
1250
1251  if (__addr || __addr_len < 0)
1252    {
1253      return -EINVAL;
1254    }
1255
1256  rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
1257				__flags, __addr, __addr_len);
1258  return rv;
1259}
1260
1261/* TBD: move it to vppcom */
1262static ssize_t
1263vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1264{
1265  int rv = -1;
1266  /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1267     (int)__n); */
1268  return rv;
1269}
1270
1271ssize_t
1272vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1273{
1274  int rv = -1;
1275  vcom_socket_main_t *vsm = &vcom_socket_main;
1276  uword *p;
1277  vcom_socket_t *vsock;
1278
1279  p = hash_get (vsm->sockidx_by_fd, __fd);
1280  if (!p)
1281    return -EBADF;
1282
1283  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1284  if (!vsock)
1285    return -ENOTSOCK;
1286
1287  if (vcom_socket_is_connection_mode_socket (__fd))
1288    {
1289      /* ignore __addr and _addr_len */
1290      /* and EISCONN may be returned when they are not NULL and 0 */
1291      if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1292	{
1293	  return -EISCONN;
1294	}
1295    }
1296  else
1297    {
1298      /* TBD: validate __message->msg_name and __message->msg_namelen
1299       * and return -EINVAL on validation error
1300       * */
1301      ;
1302    }
1303
1304  rv = vppcom_sendmsg (vsock->sid, __message, __flags);
1305
1306  return rv;
1307}
1308
1309#ifdef __USE_GNU
1310int
1311vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1312		      unsigned int __vlen, int __flags)
1313{
1314
1315  /* TBD: define a new vppcom api */
1316  return 0;
1317}
1318#endif
1319
1320/* TBD: move it to vppcom */
1321static ssize_t
1322vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
1323{
1324  int rv = -1;
1325  /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1326     (int)__n); */
1327  return rv;
1328}
1329
1330ssize_t
1331vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1332{
1333  int rv = -1;
1334  vcom_socket_main_t *vsm = &vcom_socket_main;
1335  uword *p;
1336  vcom_socket_t *vsock;
1337
1338  p = hash_get (vsm->sockidx_by_fd, __fd);
1339  if (!p)
1340    return -EBADF;
1341
1342  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1343  if (!vsock)
1344    return -ENOTSOCK;
1345
1346  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1347    return -EINVAL;
1348
1349  if (!__message)
1350    {
1351      return -EINVAL;
1352    }
1353
1354  /* validate __flags */
1355
1356  rv = vppcom_recvmsg (vsock->sid, __message, __flags);
1357  return rv;
1358}
1359
1360#ifdef __USE_GNU
1361int
1362vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1363		      unsigned int __vlen, int __flags,
1364		      struct timespec *__tmo)
1365{
1366  /* TBD: define a new vppcom api */
1367  return 0;
1368}
1369#endif
1370
1371/* TBD: move it to vppcom */
1372static int
1373vppcom_getsockopt (int __sid, int __level, int __optname,
1374		   void *__restrict __optval, socklen_t * __restrict __optlen)
1375{
1376  /* 1. for socket level options that are NOT socket attributes
1377   *    and that has corresponding vpp options get from vppcom */
1378#if 0
1379  return 0;
1380#endif
1381
1382  /* 2. unhandled options */
1383  return -ENOPROTOOPT;
1384}
1385
1386int
1387vcom_socket_getsockopt (int __fd, int __level, int __optname,
1388			void *__restrict __optval,
1389			socklen_t * __restrict __optlen)
1390{
1391  int rv = -1;
1392  vcom_socket_main_t *vsm = &vcom_socket_main;
1393  uword *p;
1394  vcom_socket_t *vsock;
1395
1396  p = hash_get (vsm->sockidx_by_fd, __fd);
1397  if (!p)
1398    return -EBADF;
1399
1400  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1401  if (!vsock)
1402    return -ENOTSOCK;
1403
1404  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1405    return -EINVAL;
1406
1407  if (!__optval && !__optlen)
1408    return -EFAULT;
1409
1410  if (*__optlen < 0)
1411    {
1412      return -EINVAL;
1413    }
1414
1415  switch (__level)
1416    {
1417      /* handle options at socket level */
1418    case SOL_SOCKET:
1419      switch (__optname)
1420	{
1421/*
1422 *  1. for socket level options that are socket attributes,
1423 *     get from libc_getsockopt.
1424 *  2. for socket level options that are NOT socket
1425 *     attributes and that has corresponding vpp options
1426 *     get from vppcom.
1427 *  3. for socket level options unimplemented
1428 *     return -ENOPROTOOPT */
1429	case SO_DEBUG:
1430	case SO_DONTROUTE:
1431	case SO_BROADCAST:
1432	case SO_SNDBUF:
1433	case SO_RCVBUF:
1434	case SO_REUSEADDR:
1435	case SO_REUSEPORT:
1436	case SO_KEEPALIVE:
1437	case SO_TYPE:
1438	case SO_PROTOCOL:
1439	case SO_DOMAIN:
1440	case SO_ERROR:
1441	case SO_OOBINLINE:
1442	case SO_NO_CHECK:
1443	case SO_PRIORITY:
1444	case SO_LINGER:
1445	case SO_BSDCOMPAT:
1446	case SO_TIMESTAMP:
1447	case SO_TIMESTAMPNS:
1448	case SO_TIMESTAMPING:
1449	case SO_RCVTIMEO:
1450	case SO_SNDTIMEO:
1451	case SO_RCVLOWAT:
1452	case SO_SNDLOWAT:
1453	case SO_PASSCRED:
1454	case SO_PEERCRED:
1455	case SO_PEERNAME:
1456	case SO_ACCEPTCONN:
1457	case SO_PASSSEC:
1458	case SO_PEERSEC:
1459	case SO_MARK:
1460	case SO_RXQ_OVFL:
1461	case SO_WIFI_STATUS:
1462	case SO_PEEK_OFF:
1463	case SO_NOFCS:
1464	case SO_BINDTODEVICE:
1465	case SO_GET_FILTER:
1466	case SO_LOCK_FILTER:
1467	case SO_BPF_EXTENSIONS:
1468	case SO_SELECT_ERR_QUEUE:
1469#ifdef CONFIG_NET_RX_BUSY_POLL
1470	case SO_BUSY_POLL:
1471#endif
1472	case SO_MAX_PACING_RATE:
1473	case SO_INCOMING_CPU:
1474	  rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1475	  if (rv != 0)
1476	    {
1477	      rv = -errno;
1478	      return rv;
1479	    }
1480	  break;
1481
1482	default:
1483	  /* We implement the SO_SNDLOWAT etc to not be settable
1484	   * (1003.1g 7).
1485	   */
1486	  return -ENOPROTOOPT;
1487	}
1488
1489      break;
1490
1491    default:
1492      /* 1. handle options that are NOT socket level options,
1493       *    but have corresponding vpp otions. */
1494      rv = vppcom_getsockopt (vsock->sid, __level, __optname,
1495			      __optval, __optlen);
1496
1497      return rv;
1498#if 0
1499      /* 2. unhandled options */
1500      return -ENOPROTOOPT;
1501#endif
1502    }
1503
1504  return rv;
1505}
1506
1507/* TBD: move it to vppcom */
1508int
1509vppcom_setsockopt (int __fd, int __level, int __optname,
1510		   const void *__optval, socklen_t __optlen)
1511{
1512  /* 1. for socket level options that are NOT socket attributes
1513   *    and that has corresponding vpp options set it from vppcom */
1514#if 0
1515  return 0;
1516#endif
1517
1518  /* 2. unhandled options */
1519  return -ENOPROTOOPT;
1520}
1521
1522int
1523vcom_socket_setsockopt (int __fd, int __level, int __optname,
1524			const void *__optval, socklen_t __optlen)
1525{
1526  int rv = -1;
1527  vcom_socket_main_t *vsm = &vcom_socket_main;
1528  uword *p;
1529  vcom_socket_t *vsock;
1530
1531  p = hash_get (vsm->sockidx_by_fd, __fd);
1532  if (!p)
1533    return -EBADF;
1534
1535  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1536  if (!vsock)
1537    return -ENOTSOCK;
1538
1539  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1540    return -EINVAL;
1541
1542  /*
1543   *      Options without arguments
1544   */
1545
1546  if (__optname == SO_BINDTODEVICE)
1547    {
1548      rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1549      if (rv != 0)
1550	{
1551	  rv = -errno;
1552	}
1553      return rv;
1554    }
1555
1556  if (!__optval)
1557    return -EFAULT;
1558
1559  if ((__optlen < 0) || (__optlen < sizeof (int)))
1560    return -EINVAL;
1561
1562  switch (__level)
1563    {
1564      /* handle options at socket level */
1565    case SOL_SOCKET:
1566      switch (__optname)
1567	{
1568	  /*
1569	   * 1. for socket level options that are socket attributes,
1570	   *    set it from libc_getsockopt
1571	   * 2. for socket level options that are NOT socket
1572	   *    attributes and that has corresponding vpp options
1573	   *    set it from vppcom
1574	   * 3. for socket level options unimplemented
1575	   *    return -ENOPROTOOPT */
1576	case SO_DEBUG:
1577	case SO_DONTROUTE:
1578	case SO_BROADCAST:
1579	case SO_SNDBUF:
1580	case SO_RCVBUF:
1581	case SO_REUSEADDR:
1582	case SO_REUSEPORT:
1583	case SO_KEEPALIVE:
1584	case SO_TYPE:
1585	case SO_PROTOCOL:
1586	case SO_DOMAIN:
1587	case SO_ERROR:
1588	case SO_OOBINLINE:
1589	case SO_NO_CHECK:
1590	case SO_PRIORITY:
1591	case SO_LINGER:
1592	case SO_BSDCOMPAT:
1593	case SO_TIMESTAMP:
1594	case SO_TIMESTAMPNS:
1595	case SO_TIMESTAMPING:
1596	case SO_RCVTIMEO:
1597	case SO_SNDTIMEO:
1598	case SO_RCVLOWAT:
1599	case SO_SNDLOWAT:
1600	case SO_PASSCRED:
1601	case SO_PEERCRED:
1602	case SO_PEERNAME:
1603	case SO_ACCEPTCONN:
1604	case SO_PASSSEC:
1605	case SO_PEERSEC:
1606	case SO_MARK:
1607	case SO_RXQ_OVFL:
1608	case SO_WIFI_STATUS:
1609	case SO_PEEK_OFF:
1610	case SO_NOFCS:
1611	  /*
1612	   * SO_BINDTODEVICE already handled as
1613	   * "Options without arguments" */
1614	  /* case SO_BINDTODEVICE: */
1615	case SO_GET_FILTER:
1616	case SO_LOCK_FILTER:
1617	case SO_BPF_EXTENSIONS:
1618	case SO_SELECT_ERR_QUEUE:
1619#ifdef CONFIG_NET_RX_BUSY_POLL
1620	case SO_BUSY_POLL:
1621#endif
1622	case SO_MAX_PACING_RATE:
1623	case SO_INCOMING_CPU:
1624	  rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1625	  if (rv != 0)
1626	    {
1627	      rv = -errno;
1628	      return rv;
1629	    }
1630	  break;
1631
1632	default:
1633	  /* We implement the SO_SNDLOWAT etc to not be settable
1634	   * (1003.1g 7).
1635	   */
1636	  return -ENOPROTOOPT;
1637	}
1638
1639      break;
1640
1641    default:
1642      /* 1. handle options that are NOT socket level options,
1643       *    but have corresponding vpp otions. */
1644      rv = vppcom_setsockopt (vsock->sid, __level, __optname,
1645			      __optval, __optlen);
1646      return rv;
1647#if 0
1648      /* 2. unhandled options */
1649      return -ENOPROTOOPT;
1650#endif
1651    }
1652
1653  return rv;
1654}
1655
1656int
1657vcom_socket_listen (int __fd, int __n)
1658{
1659  int rv = -1;
1660  vcom_socket_main_t *vsm = &vcom_socket_main;
1661  uword *p;
1662  vcom_socket_t *vsock;
1663
1664  p = hash_get (vsm->sockidx_by_fd, __fd);
1665  if (p)
1666    {
1667      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1668
1669      /* TBD vppcom to accept __n parameter */
1670      rv = vppcom_session_listen (vsock->sid, __n);
1671    }
1672
1673  return rv;
1674}
1675
1676static int
1677vcom_socket_connected_socket (int __fd, int __sid,
1678			      int *__domain,
1679			      int *__type, int *__protocol, int flags)
1680{
1681  int rv = -1;
1682  vcom_socket_main_t *vsm = &vcom_socket_main;
1683  vcom_socket_t *vsock;
1684
1685  i32 fd;
1686  i32 sockidx;
1687
1688  socklen_t optlen;
1689
1690  optlen = sizeof (*__domain);
1691  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
1692  if (rv != 0)
1693    {
1694      rv = -errno;
1695      goto out;
1696    }
1697
1698  optlen = sizeof (*__type);
1699  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
1700  if (rv != 0)
1701    {
1702      rv = -errno;
1703      goto out;
1704    }
1705
1706  optlen = sizeof (*__protocol);
1707  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
1708  if (rv != 0)
1709    {
1710      rv = -errno;
1711      goto out;
1712    }
1713
1714  fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
1715  if (fd < 0)
1716    {
1717      rv = fd;
1718      goto out;
1719    }
1720
1721  pool_get (vsm->vsockets, vsock);
1722  sockidx = vsock - vsm->vsockets;
1723  hash_set (vsm->sockidx_by_fd, fd, sockidx);
1724
1725  vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
1726  return fd;
1727
1728out:
1729  return rv;
1730}
1731
1732/* If flag is 0, then accept4() is the same as accept().
1733 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
1734 */
1735static int
1736vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
1737			  socklen_t * __restrict __addr_len, int flags)
1738{
1739  int rv = -1;
1740  vcom_socket_main_t *vsm = &vcom_socket_main;
1741  uword *p;
1742  vcom_socket_t *vsock;
1743
1744  int fd;
1745  int sid;
1746  int domain;
1747  int type;
1748  int protocol;
1749
1750  uint8_t addr8[sizeof (struct in6_addr)];
1751  vppcom_endpt_t ep;
1752
1753  ep.ip = addr8;
1754
1755  /* validate flags */
1756
1757  /*
1758   * for documentation
1759   *  switch (flags)
1760   *   {
1761   *   case 0:
1762   *   case SOCK_NONBLOCK:
1763   *   case SOCK_CLOEXEC:
1764   *   case SOCK_NONBLOCK | SOCK_CLOEXEC:
1765   *     break;
1766   *
1767   *   default:
1768   *     return -1;
1769   *   }
1770   */
1771  /* flags can be 0 or can be bitwise OR
1772   * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
1773
1774  if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
1775    {
1776      /* TBD: return proper error code */
1777      return -1;
1778    }
1779
1780  /* TBD: return proper error code */
1781
1782  if (!vcom_socket_is_connection_mode_socket (__fd))
1783    {
1784      return -EOPNOTSUPP;
1785    }
1786
1787  p = hash_get (vsm->sockidx_by_fd, __fd);
1788  if (p)
1789    {
1790      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1791
1792
1793      rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
1794      if (rv < 0)
1795	{
1796	  return rv;
1797	}
1798
1799      /* is blocking */
1800      if (!(rv & O_NONBLOCK))
1801	{
1802	  /* socket is not marked as nonblocking
1803	   * and no pending connections are present
1804	   * on the queue, accept () blocks the caller
1805	   * until a connection is present.
1806	   */
1807	  rv = vppcom_session_accept (vsock->sid, &ep,
1808				      -1.0 /* wait forever */ );
1809	}
1810      else
1811	{
1812	  /* The file descriptor refers to a socket and has been
1813	   * marked nonblocking(O_NONBLOCK) and the accept would
1814	   * block.
1815	   * */
1816	  /* is non blocking */
1817	  rv = vppcom_session_accept (vsock->sid, &ep, 0);
1818	  /* If the socket is marked nonblocking and
1819	   * no pending connections are present on the
1820	   * queue, accept fails with the error
1821	   * EAGAIN or EWOULDBLOCK
1822	   */
1823	  if (rv == VPPCOM_ETIMEDOUT)
1824	    {
1825	      rv = VPPCOM_EAGAIN;
1826	    }
1827	}
1828      if (rv < 0)
1829	{
1830	  return rv;
1831	}
1832
1833      sid = rv;
1834
1835      /* create a new connected socket resource and set flags
1836       * on the new file descriptor.
1837       * update vsockets and sockidx_by_fd table
1838       * */
1839      fd = vcom_socket_connected_socket (__fd, sid,
1840					 &domain, &type, &protocol, flags);
1841      if (fd < 0)
1842	{
1843	  return fd;
1844	}
1845
1846      rv = fd;
1847
1848      /* TBD populate __addr and __addr_len */
1849      /* TBD: The returned address is truncated if the buffer
1850       * provided is too small, in this case, __addr_len will
1851       * return a value greater than was supplied to the call.*/
1852      if (__addr)
1853	{
1854	  if (ep.is_cut_thru)
1855	    {
1856	      /* TBD populate __addr and __addr_len */
1857	      switch (domain)
1858		{
1859		case AF_INET:
1860		  ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1861		  ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1862		  memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
1863			  addr8, sizeof (struct in_addr));
1864		  /* TBD: populate __addr_len */
1865		  if (__addr_len)
1866		    {
1867		      *__addr_len = sizeof (struct sockaddr_in);
1868		    }
1869		  break;
1870
1871		case AF_INET6:
1872		  ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
1873		  ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1874		  memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1875			  __in6_u.__u6_addr8, addr8,
1876			  sizeof (struct in6_addr));
1877		  /* TBD: populate __addr_len */
1878		  if (__addr_len)
1879		    {
1880		      *__addr_len = sizeof (struct sockaddr_in6);
1881		    }
1882		  break;
1883
1884		default:
1885		  return -EAFNOSUPPORT;
1886		}
1887	    }
1888	  else
1889	    {
1890	      switch (ep.is_ip4)
1891		{
1892		case VPPCOM_IS_IP4:
1893		  ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1894		  ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1895		  memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
1896			  addr8, sizeof (struct in_addr));
1897		  /* TBD: populate __addr_len */
1898		  if (__addr_len)
1899		    {
1900		      *__addr_len = sizeof (struct sockaddr_in);
1901		    }
1902		  break;
1903
1904		case VPPCOM_IS_IP6:
1905		  ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
1906		  ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1907		  memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1908			  __in6_u.__u6_addr8, addr8,
1909			  sizeof (struct in6_addr));
1910		  /* TBD: populate __addr_len */
1911		  if (__addr_len)
1912		    {
1913		      *__addr_len = sizeof (struct sockaddr_in6);
1914		    }
1915		  break;
1916
1917		default:
1918		  return -EAFNOSUPPORT;
1919		}
1920	    }
1921	}
1922      else
1923	{
1924	  /* when __addr is NULL, nothing is filled in,
1925	   * in this case, __addr_len is not used,
1926	   * and should also be null
1927	   * */
1928	  if (__addr_len)
1929	    {
1930	      /* TBD: return proper error code */
1931	      return -1;
1932	    }
1933	}
1934    }
1935
1936  return rv;
1937}
1938
1939int
1940vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
1941		    socklen_t * __restrict __addr_len)
1942{
1943  /* set flags to 0 for accept() */
1944  return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
1945}
1946
1947#ifdef __USE_GNU
1948int
1949vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
1950		     socklen_t * __restrict __addr_len, int __flags)
1951{
1952  /*  SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
1953  return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
1954}
1955#endif
1956
1957/* TBD: move it to vppcom */
1958int
1959vppcom_session_shutdown (int __fd, int __how)
1960{
1961  return 0;
1962}
1963
1964int
1965vcom_socket_shutdown (int __fd, int __how)
1966{
1967  int rv = -1;
1968  vcom_socket_main_t *vsm = &vcom_socket_main;
1969  uword *p;
1970  vcom_socket_t *vsock;
1971
1972  p = hash_get (vsm->sockidx_by_fd, __fd);
1973  if (p)
1974    {
1975      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1976      switch (__how)
1977	{
1978	case SHUT_RD:
1979	case SHUT_WR:
1980	case SHUT_RDWR:
1981	  rv = vppcom_session_shutdown (vsock->sid, __how);
1982	  return rv;
1983	  break;
1984
1985	default:
1986	  return -EINVAL;
1987	  break;
1988	}
1989    }
1990
1991  return rv;
1992}
1993
1994/*
1995 * fd.io coding-style-patch-verification: ON
1996 *
1997 * Local Variables:
1998 * eval: (c-set-style "gnu")
1999 * End:
2000 */
2001