예제 #1
0
/*! Perform system bind on the OS backing socket.
 * \param ep       Endpoint context
 * \param fd       Callers FD
 * \param ip_addr_be32  Local address to which to bind
 * \param port_be16     [in] requested port [out] assigned port
 * \return         0 - success & [port_be16] updated
 *                 CI_SOCKET_HANDOVER, Pass to OS, OS bound ok, (no error)
 *                 CI_SOCKET_ERROR & errno set
 */
ci_inline int __ci_bind(ci_netif *ni, ci_sock_cmn *s,
                        ci_uint32 ip_addr_be32, ci_uint16* port_be16 )
{
  int rc;
  ci_uint16 user_port; /* Port number specified by user, not by OS.
                        * See bug 4015 for details */
  union ci_sockaddr_u sa_u;

  ci_assert(s->domain == AF_INET || s->domain == AF_INET6);

  ci_assert( port_be16 );

  user_port = *port_be16;
#if CI_CFG_FAKE_IPV6
  ci_assert(s->domain == AF_INET || s->domain == AF_INET6);
  if( s->domain == AF_INET )
    ci_make_sockaddr(&sa_u.sin, s->domain, user_port, ip_addr_be32);
  else
    ci_make_sockaddr6(&sa_u.sin6, s->domain, user_port, ip_addr_be32);
#else
  ci_assert(s->domain == AF_INET);
  ci_make_sockaddr(&sa_u.sin, s->domain, user_port, ip_addr_be32);
#endif

#ifdef __ci_driver__
  rc = efab_tcp_helper_bind_os_sock(netif2tcp_helper_resource(ni),
                                    SC_SP(s),
                                    &sa_u.sa, sizeof(sa_u), port_be16);
#else
  rc = ci_tcp_helper_bind_os_sock(ni, SC_SP(s), &sa_u.sa,
                                  sizeof(sa_u), port_be16);
#endif

  /* bug1781: only do this if the earlier bind succeeded. 
   * check if we can handle this socket */
  if( rc != 0 )
    return rc;
  if( user_port != 0 )
    s->s_flags |= CI_SOCK_FLAG_PORT_BOUND;
  if( ip_addr_be32 != INADDR_ANY )
    s->s_flags |= CI_SOCK_FLAG_ADDR_BOUND;
  s->s_flags &= ~CI_SOCK_FLAG_CONNECT_MUST_BIND;

#ifndef __ci_driver__
  /* We do not call bind() to alien address from in-kernel code */
  if( ip_addr_be32 != INADDR_ANY &&
      !cicp_user_addr_is_local_efab(CICP_HANDLE(ni), &ip_addr_be32) )
    s->s_flags |= CI_SOCK_FLAG_BOUND_ALIEN;
#endif
  
  return rc;
}
예제 #2
0
static int __ci_udp_recvmsg_try_os(ci_netif *ni, ci_udp_state *us,
                                   struct msghdr* msg, int flags, int* prc)
{
  int rc;

  rc = oo_os_sock_recvmsg(ni, SC_SP(&us->s), msg, flags | MSG_DONTWAIT);

  if( rc >= 0 ) {
    ++us->stats.n_rx_os;
    us->udpflags &= ~CI_UDPF_LAST_RECV_ON;
    if( ! (flags & MSG_PEEK) )
      us->udpflags &=~ CI_UDPF_PEEK_FROM_OS;
    else
      us->udpflags |=  CI_UDPF_PEEK_FROM_OS;
  }
  else {
    if( rc == -EAGAIN )
      return 0;
    ci_assert(-rc == errno);
    rc = -1;
    ++us->stats.n_rx_os_error;
  }

  *prc = rc;
  return 1;
}
예제 #3
0
void sig_handler_common_tt(int sig, void *sc_ptr)
{
	struct sigcontext *sc = sc_ptr;
	struct tt_regs save_regs, *r;
	struct signal_info *info;
	int save_errno = errno, is_user;

	unprotect_kernel_mem();

	r = &TASK_REGS(get_current())->tt;
	save_regs = *r;
	is_user = user_context(SC_SP(sc));
	r->sc = sc;
	if(sig != SIGUSR2) 
		r->syscall = -1;

	change_sig(SIGUSR1, 1);
	info = &sig_info[sig];
	if(!info->is_irq) unblock_signals();

	(*info->handler)(sig, (union uml_pt_regs *) r);

	if(is_user){
		interrupt_end();
		block_signals();
		change_sig(SIGUSR1, 0);
		set_user_mode(NULL);
	}
	*r = save_regs;
	errno = save_errno;
	if(is_user) protect_kernel_mem();
}
예제 #4
0
int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
		   unsigned long stack_top, struct task_struct * p, 
		   struct pt_regs *regs)
{
	int (*tramp)(void *);
	int new_pid, err;
	unsigned long stack;
	
	if(current->thread.forking)
		tramp = fork_tramp;
	else {
		tramp = new_thread_proc;
		p->thread.request.u.thread = current->thread.request.u.thread;
	}

	err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
	if(err < 0){
		printk("copy_thread : pipe failed, err = %d\n", -err);
		return(err);
	}

	stack = alloc_stack(0, 0);
	if(stack == 0){
		printk(KERN_ERR "copy_thread : failed to allocate "
		       "temporary stack\n");
		return(-ENOMEM);
	}

	clone_flags &= CLONE_VM;
	p->thread.temp_stack = stack;
	new_pid = start_fork_tramp(task_stack_page(p), stack, clone_flags, tramp);
	if(new_pid < 0){
		printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", 
		       -new_pid);
		return(new_pid);
	}

	if(current->thread.forking){
		sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(&regs->regs));
		SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
		if(sp != 0)
			SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
	}
	p->thread.mode.tt.extern_pid = new_pid;

	current->thread.request.op = OP_FORK;
	current->thread.request.u.fork.pid = new_pid;
	os_usr1_process(os_getpid());

	/* Enable the signal and then disable it to ensure that it is handled
	 * here, and nowhere else.
	 */
	change_sig(SIGUSR1, 1);

	change_sig(SIGUSR1, 0);
	err = 0;
	return(err);
}
예제 #5
0
파일: udp.c 프로젝트: majek/openonload
ci_fd_t ci_udp_ep_ctor(citp_socket* ep, ci_netif* netif, int domain, int type)
{
  ci_udp_state* us;
  ci_fd_t fd;

  VERB( log(LPFIN "ctor( )" ) );

  ci_assert(ep);
  ci_assert(netif);

  ci_netif_lock(netif);
  us = ci_udp_get_state_buf(netif);
  if (!us) {
    ci_netif_unlock(netif);
    LOG_E(ci_log("%s: [%d] out of socket buffers", __FUNCTION__,NI_ID(netif)));
    return -ENOMEM;
  }

  /* It's required to set protocol before ci_tcp_helper_sock_attach()
   * since it's used to determine if TCP or UDP file operations should be
   * attached to the file descriptor in kernel. */
   sock_protocol(&us->s) = IPPROTO_UDP;

  /* NB: this attach will close the os_sock_fd */
  fd = ci_tcp_helper_sock_attach(ci_netif_get_driver_handle(netif),  
                                 SC_SP(&us->s), domain, type);
  if( fd < 0 ) {
    if( fd == -EAFNOSUPPORT )
      LOG_U(ci_log("%s: ci_tcp_helper_sock_attach (domain=%d, type=%d) "
                   "failed %d", __FUNCTION__, domain, type, fd));
    else
      LOG_E(ci_log("%s: ci_tcp_helper_sock_attach (domain=%d, type=%d) "
                   "failed %d", __FUNCTION__, domain, type, fd));
    ci_netif_unlock(netif);
    return fd;
  }

  ci_assert(~us->s.b.sb_aflags & CI_SB_AFLAG_ORPHAN);

  us->s.rx_errno = 0;
  us->s.tx_errno = 0;
  us->s.so_error = 0;
  us->s.cp.sock_cp_flags |= OO_SCP_UDP_WILD;

  ep->s = &us->s;
  ep->netif = netif;
  CHECK_UEP(ep);
  ci_netif_unlock(netif);
  return fd;
}
예제 #6
0
파일: socket.c 프로젝트: ido/openonload
void ci_sock_cmn_init(ci_netif* ni, ci_sock_cmn* s)
{
  oo_p sp;

  /* Poison. */
  CI_DEBUG(memset(&s->b + 1, 0xf0, (char*) (s + 1) - (char*) (&s->b + 1)));

  citp_waitable_reinit(ni, &s->b);
  oo_sock_cplane_init(&s->cp);
  s->local_peer = OO_SP_NULL;

  s->s_flags = CI_SOCK_FLAG_CONNECT_MUST_BIND | CI_SOCK_FLAG_PMTU_DO;
  s->s_aflags = 0u;

  ci_assert_equal( 0, CI_IP_DFLT_TOS );
  s->so_priority = 0;

  /* SO_SNDBUF & SO_RCVBUF.  See also ci_tcp_set_established_state() which
   * may modify these values.
   */
  memset(&s->so, 0, sizeof(s->so));
  s->so.sndbuf = NI_OPTS(ni).tcp_sndbuf_def;
  s->so.rcvbuf = NI_OPTS(ni).tcp_rcvbuf_def;

  s->rx_bind2dev_ifindex = CI_IFID_BAD;
  /* These don't really need to be initialised, as only significant when
   * rx_bind2dev_ifindex != CI_IFID_BAD.  But makes stackdump output
   * cleaner this way...
   */
  s->rx_bind2dev_base_ifindex = 0;
  s->rx_bind2dev_vlan = 0;

  s->cmsg_flags = 0u;
  s->timestamping_flags = 0u;
  s->os_sock_status = OO_OS_STATUS_TX;

  ci_ip_queue_init(&s->timestamp_q);
  s->timestamp_q_extract = OO_PP_NULL;


  ci_sock_cmn_reinit(ni, s);

  sp = oo_sockp_to_statep(ni, SC_SP(s));
  OO_P_ADD(sp, CI_MEMBER_OFFSET(ci_sock_cmn, reap_link));
  ci_ni_dllist_link_init(ni, &s->reap_link, sp, "reap");
  ci_ni_dllist_self_link(ni, &s->reap_link);
}
예제 #7
0
static int __ci_udp_recvmsg_try_os(ci_netif *ni, ci_udp_state *us,
                                   ci_msghdr* msg, int flags, int* prc)
{
  int rc, total_bytes, i;
  tcp_helper_endpoint_t *ep;
  struct socket *sock;
  struct file *os_sock;
  struct msghdr kmsg;

  total_bytes = 0;
  for( i = 0; i < msg->msg_iovlen; ++i )
    total_bytes += msg->msg_iov[i].iov_len;
  rc = -EMSGSIZE;
  if( total_bytes < 0 )
    return -EINVAL;

  ep = ci_netif_ep_get(ni, SC_SP(&us->s));
  os_sock = ep->os_socket->file;
  ci_assert(S_ISSOCK(os_sock->f_dentry->d_inode->i_mode));
  sock = SOCKET_I(os_sock->f_dentry->d_inode);

  oo_msg_iov_init(&kmsg, READ, msg->msg_iov, msg->msg_iovlen, total_bytes);
  kmsg.msg_namelen = 0;
  kmsg.msg_controllen = 0;
  rc = sock_recvmsg(sock, &kmsg, total_bytes, flags | MSG_DONTWAIT);
  /* Clear OS RX flag if we've got everything  */
  oo_os_sock_status_bit_clear(&us->s, OO_OS_STATUS_RX,
                              os_sock->f_op->poll(os_sock, NULL) & POLLIN);
  if( rc >= 0 ) {
    ++us->stats.n_rx_os;
  }
  else {
    if( rc == -EAGAIN )
      return 0;
    ++us->stats.n_rx_os_error;
  }

  if( rc >= 0 ) {
    us->udpflags &= ~CI_UDPF_LAST_RECV_ON;
    if( ! (flags & MSG_PEEK) )
      us->udpflags &=~ CI_UDPF_PEEK_FROM_OS;
    else
      us->udpflags |=  CI_UDPF_PEEK_FROM_OS;
  }
  *prc = rc;
  return 1;
}
예제 #8
0
void sig_handler_common_tt(int sig, void *sc_ptr)
{
	struct sigcontext *sc = sc_ptr;
	struct tt_regs save_regs, *r;
	struct signal_info *info;
	int save_errno = errno, is_user;

	unprotect_kernel_mem();

	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
	 * handler.  This can happen in copy_user, and if SEGV is disabled,
	 * the process will die.
	 */
	if(sig == SIGSEGV)
		change_sig(SIGSEGV, 1);

	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
	 * handler.  This can happen in copy_user, and if SEGV is disabled,
	 * the process will die.
	 */
	if(sig == SIGSEGV)
		change_sig(SIGSEGV, 1);

	r = &TASK_REGS(get_current())->tt;
	save_regs = *r;
	is_user = user_context(SC_SP(sc));
	r->sc = sc;
	if(sig != SIGUSR2) 
		r->syscall = -1;

	info = &sig_info[sig];
	if(!info->is_irq) unblock_signals();

	(*info->handler)(sig, (union uml_pt_regs *) r);

	if(is_user){
		interrupt_end();
		block_signals();
		set_user_mode(NULL);
	}
	*r = save_regs;
	errno = save_errno;
	if(is_user) protect_kernel_mem();
}
예제 #9
0
int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
		       struct sigcontext *from, int fpsize, unsigned long sp)
{
	struct _fpstate __user *to_fp;
	struct _fpstate *from_fp;
	int err;

	to_fp =	(fp ? fp : (struct _fpstate __user *) (to + 1));
	from_fp = from->fpstate;
	err = copy_to_user(to, from, sizeof(*to));

	/* The SP in the sigcontext is the updated one for the signal
	 * delivery.  The sp passed in is the original, and this needs
	 * to be restored, so we stick it in separately.
	 */
	err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp));

	if(from_fp != NULL){
		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
		err |= copy_to_user(to_fp, from_fp, fpsize);
	}
	return err;
}
예제 #10
0
파일: x86-arch.c 프로젝트: Distrotech/cmucl
void
sigtrap_handler(HANDLER_ARGS)
{
    unsigned int trap;
    os_context_t* os_context = (os_context_t *) context;
#if 0
    fprintf(stderr, "x86sigtrap: %8x %x\n",
            SC_PC(os_os_context), *(unsigned char *) (SC_PC(os_context) - 1));
    fprintf(stderr, "sigtrap(%d %d %x)\n", signal, CODE(code), os_context);
#endif

    if (single_stepping && (signal == SIGTRAP)) {
#if 0
	fprintf(stderr, "* Single step trap %p\n", single_stepping);
#endif

#ifdef SC_EFLAGS
	/* Disable single-stepping */
	SC_EFLAGS(os_context) ^= 0x100;
#else
	/* Un-install single step helper instructions. */
	*(single_stepping - 3) = single_step_save1;
	*(single_stepping - 2) = single_step_save2;
	*(single_stepping - 1) = single_step_save3;
        DPRINTF(0, (stderr, "Uninstalling helper instructions\n"));
#endif

	/*
	 * Re-install the breakpoint if possible.
	 */
	if ((int) SC_PC(os_context) == (int) single_stepping + 1)
	    fprintf(stderr, "* Breakpoint not re-install\n");
	else {
	    char *ptr = (char *) single_stepping;

	    ptr[0] = BREAKPOINT_INST;	/* x86 INT3 */
	    ptr[1] = trap_Breakpoint;
	}

	single_stepping = NULL;
	return;
    }

    /* This is just for info in case monitor wants to print an approx */
    current_control_stack_pointer = (unsigned long *) SC_SP(os_context);

    RESTORE_FPU(os_context);

    /*
     * On entry %eip points just after the INT3 byte and aims at the
     * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
     * number of bytes will follow, the first is the length of the byte
     * arguments to follow.
     */

    trap = *(unsigned char *) SC_PC(os_context);

    switch (trap) {
      case trap_PendingInterrupt:
	  DPRINTF(0, (stderr, "<trap Pending Interrupt.>\n"));
	  arch_skip_instruction(os_context);
	  interrupt_handle_pending(os_context);
	  break;

      case trap_Halt:
	  {
              FPU_STATE(fpu_state);
              save_fpu_state(fpu_state);

	      fake_foreign_function_call(os_context);
	      lose("%%primitive halt called; the party is over.\n");
	      undo_fake_foreign_function_call(os_context);

              restore_fpu_state(fpu_state);
	      arch_skip_instruction(os_context);
	      break;
	  }

      case trap_Error:
      case trap_Cerror:
	  DPRINTF(0, (stderr, "<trap Error %x>\n", CODE(code)));
	  interrupt_internal_error(signal, code, os_context, CODE(code) == trap_Cerror);
	  break;

      case trap_Breakpoint:
#if 0
	  fprintf(stderr, "*C break\n");
#endif
	  SC_PC(os_context) -= 1;

	  handle_breakpoint(signal, CODE(code), os_context);
#if 0
	  fprintf(stderr, "*C break return\n");
#endif
	  break;

      case trap_FunctionEndBreakpoint:
	  SC_PC(os_context) -= 1;
	  SC_PC(os_context) =
	      (int) handle_function_end_breakpoint(signal, CODE(code), os_context);
	  break;

#ifdef trap_DynamicSpaceOverflowWarning
      case trap_DynamicSpaceOverflowWarning:
	  interrupt_handle_space_overflow(SymbolFunction
					  (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
					  os_context);
	  break;
#endif
#ifdef trap_DynamicSpaceOverflowError
      case trap_DynamicSpaceOverflowError:
	  interrupt_handle_space_overflow(SymbolFunction
					  (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
					  os_context);
	  break;
#endif
      default:
	  DPRINTF(0,
		  (stderr, "[C--trap default %d %d %p]\n", signal, CODE(code),
		   os_context));
	  interrupt_handle_now(signal, code, os_context);
	  break;
    }
}
예제 #11
0
static int ci_udp_recvmsg_socklocked_slowpath(ci_udp_iomsg_args* a, 
                                              ci_msghdr* msg,
                                              ci_iovec_ptr *piov, int flags)
{
  int rc = 0;
  ci_netif* ni = a->ni;
  ci_udp_state* us = a->us;

  if(CI_UNLIKELY( ni->state->rxq_low ))
    ci_netif_rxq_low_on_recv(ni, &us->s,
                             1 /* assume at least one pkt freed */);
  /* In the kernel recv() with flags is not called.
   * only read(). So flags may only contain MSG_DONTWAIT */
#ifdef __KERNEL__
  ci_assert_equal(flags, 0);
#endif

#ifndef __KERNEL__
  if( flags & MSG_ERRQUEUE_CHK ) {
    if( OO_PP_NOT_NULL(us->timestamp_q.extract) ) {
      ci_ip_pkt_fmt* pkt;
      struct timespec ts[3];
      struct cmsg_state cmsg_state;
      ci_udp_hdr* udp;
      int paylen;

      /* TODO is this necessary? - mirroring ci_udp_recvmsg_get() */
      ci_rmb();
      
      pkt = PKT_CHK_NNL(ni, us->timestamp_q.extract);
      if( pkt->tx_hw_stamp.tv_sec == CI_PKT_TX_HW_STAMP_CONSUMED ) {
        if( OO_PP_IS_NULL(pkt->tsq_next) )
          goto errqueue_empty;
        us->timestamp_q.extract = pkt->tsq_next;
        pkt = PKT_CHK_NNL(ni, us->timestamp_q.extract);
        ci_assert(pkt->tx_hw_stamp.tv_sec != CI_PKT_TX_HW_STAMP_CONSUMED);
      }

      udp = oo_ip_data(pkt);
      paylen = CI_BSWAP_BE16(oo_ip_hdr(pkt)->ip_tot_len_be16) -
                        sizeof(ci_ip4_hdr) - sizeof(udp);

      msg->msg_flags = 0;
      cmsg_state.msg = msg;
      cmsg_state.cm = msg->msg_control;
      cmsg_state.cmsg_bytes_used = 0;
      ci_iovec_ptr_init_nz(piov, msg->msg_iov, msg->msg_iovlen);
      memset(ts, 0, sizeof(ts));

      if( us->s.timestamping_flags & ONLOAD_SOF_TIMESTAMPING_RAW_HARDWARE ) {
        ts[2].tv_sec = pkt->tx_hw_stamp.tv_sec;
        ts[2].tv_nsec = pkt->tx_hw_stamp.tv_nsec;
      }
      if( (us->s.timestamping_flags & ONLOAD_SOF_TIMESTAMPING_SYS_HARDWARE) &&
          (pkt->tx_hw_stamp.tv_nsec & CI_IP_PKT_HW_STAMP_FLAG_IN_SYNC) ) {
        ts[1].tv_sec = pkt->tx_hw_stamp.tv_sec;
        ts[1].tv_nsec = pkt->tx_hw_stamp.tv_nsec;
      }
      ci_put_cmsg(&cmsg_state, SOL_SOCKET, ONLOAD_SCM_TIMESTAMPING,
                  sizeof(ts), &ts);
      oo_offbuf_set_start(&pkt->buf, udp + 1);
      oo_offbuf_set_len(&pkt->buf, paylen);
      rc = oo_copy_pkt_to_iovec_no_adv(ni, pkt, piov, paylen);

      /* Mark this packet/timestamp as consumed */
      pkt->tx_hw_stamp.tv_sec = CI_PKT_TX_HW_STAMP_CONSUMED;

      ci_ip_cmsg_finish(&cmsg_state);
      msg->msg_flags |= MSG_ERRQUEUE_CHK;
      return rc;
    }
  errqueue_empty:
    /* ICMP is handled via OS, so get OS error */
    rc = oo_os_sock_recvmsg(ni, SC_SP(&us->s), msg, flags);
    if( rc < 0 ) {
      ci_assert(-rc == errno);
      return -1;
    }
    else
      return rc;
  }
#endif
  if( (rc = ci_get_so_error(&us->s)) != 0 ) {
    CI_SET_ERROR(rc, rc);
    return rc;
  }
  if( msg->msg_iovlen > 0 && msg->msg_iov == NULL ) {
    CI_SET_ERROR(rc, EFAULT);
    return rc;
  }
#if MSG_OOB_CHK
  if( flags & MSG_OOB_CHK ) {
    CI_SET_ERROR(rc, EOPNOTSUPP);
    return rc;
  }
#endif
#if CI_CFG_POSIX_RECV  
  if( ! udp_lport_be16(us)) {
    LOG_UV(log("%s: -1 (ENOTCONN)", __FUNCTION__));
    CI_SET_ERROR(rc, ENOTCONN);
    return rc;
  }
#endif
  if( msg->msg_iovlen == 0 ) {
    /* We have a difference in behaviour from the Linux stack here.  When
    ** msg_iovlen is 0 Linux 2.4.21-15.EL does not set MSG_TRUNC when a
    ** datagram has non-zero length.  We do. */
    CI_IOVEC_LEN(&piov->io) = piov->iovlen = 0;
    return IOVLEN_WORKAROUND_RC_VALUE;
  }
  return 0;
}
예제 #12
0
파일: socket.c 프로젝트: bmschwa/openonload
  s->rx_bind2dev_ifindex = CI_IFID_BAD;
  /* These don't really need to be initialised, as only significant when
   * rx_bind2dev_ifindex != CI_IFID_BAD.  But makes stackdump output
   * cleaner this way...
   */
  s->rx_bind2dev_base_ifindex = 0;
  s->rx_bind2dev_vlan = 0;

  s->cmsg_flags = 0u;
  s->timestamping_flags = 0u;
  s->os_sock_status = OO_OS_STATUS_TX;


  ci_sock_cmn_reinit(ni, s);

  sp = oo_sockp_to_statep(ni, SC_SP(s));
  OO_P_ADD(sp, CI_MEMBER_OFFSET(ci_sock_cmn, reap_link));
  ci_ni_dllist_link_init(ni, &s->reap_link, sp, "reap");
  ci_ni_dllist_self_link(ni, &s->reap_link);
}




void ci_sock_cmn_dump(ci_netif* ni, ci_sock_cmn* s, const char* pf,
                      oo_dump_log_fn_t logger, void* log_arg)
{
  logger(log_arg, "%s  uid=%d"CI_DEBUG(" pid=%d")
         " s_flags: "CI_SOCK_FLAGS_FMT, pf,
         (int) s->uid CI_DEBUG_ARG((int)s->pid),
         CI_SOCK_FLAGS_PRI_ARG(s));