Rename min/max -> uimin/uimax for better honesty.
These functions are defined on unsigned int. The generic name
min/max should not silently truncate to 32 bits on 64-bit systems.
This is purely a name change -- no functional change intended.
HOWEVER! Some subsystems have
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
even though our standard name for that is MIN/MAX. Although these
may invite multiple evaluation bugs, these do _not_ cause integer
truncation.
To avoid `fixing' these cases, I first changed the name in libkern,
and then compile-tested every file where min/max occurred in order to
confirm that it failed -- and thus confirm that nothing shadowed
min/max -- before changing it.
I have left a handful of bootloaders that are too annoying to
compile-test, and some dead code:
cobalt ews4800mips hp300 hppa ia64 luna68k vax
acorn32/if_ie.c (not included in any kernels)
macppc/if_gm.c (superseded by gem(4))
It should be easy to fix the fallout once identified -- this way of
doing things fails safe, and the goal here, after all, is to _avoid_
silent integer truncations, not introduce them.
Maybe one day we can reintroduce min/max as type-generic things that
never silently truncate. But we should avoid doing that for a while,
so that existing code has a chance to be detected by the compiler for
conversion to uimin/uimax without changing the semantics until we can
properly audit it all. (Who knows, maybe in some cases integer
truncation is actually intended!)
2018-09-03 19:29:22 +03:00
|
|
|
/* $NetBSD: rfcomm_upper.c,v 1.23 2018/09/03 16:29:36 riastradh Exp $ */
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2006 Itronix Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Written by Iain Hibbert for Itronix Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of Itronix Inc. may not be used to endorse
|
|
|
|
* or promote products derived from this software without specific
|
|
|
|
* prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
Rename min/max -> uimin/uimax for better honesty.
These functions are defined on unsigned int. The generic name
min/max should not silently truncate to 32 bits on 64-bit systems.
This is purely a name change -- no functional change intended.
HOWEVER! Some subsystems have
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
even though our standard name for that is MIN/MAX. Although these
may invite multiple evaluation bugs, these do _not_ cause integer
truncation.
To avoid `fixing' these cases, I first changed the name in libkern,
and then compile-tested every file where min/max occurred in order to
confirm that it failed -- and thus confirm that nothing shadowed
min/max -- before changing it.
I have left a handful of bootloaders that are too annoying to
compile-test, and some dead code:
cobalt ews4800mips hp300 hppa ia64 luna68k vax
acorn32/if_ie.c (not included in any kernels)
macppc/if_gm.c (superseded by gem(4))
It should be easy to fix the fallout once identified -- this way of
doing things fails safe, and the goal here, after all, is to _avoid_
silent integer truncations, not introduce them.
Maybe one day we can reintroduce min/max as type-generic things that
never silently truncate. But we should avoid doing that for a while,
so that existing code has a chance to be detected by the compiler for
conversion to uimin/uimax without changing the semantics until we can
properly audit it all. (Who knows, maybe in some cases integer
truncation is actually intended!)
2018-09-03 19:29:22 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.23 2018/09/03 16:29:36 riastradh Exp $");
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/mbuf.h>
|
2014-05-19 06:51:24 +04:00
|
|
|
#include <sys/kmem.h>
|
2008-08-06 19:01:23 +04:00
|
|
|
#include <sys/socketvar.h>
|
2006-06-19 19:44:33 +04:00
|
|
|
#include <sys/systm.h>
|
|
|
|
|
|
|
|
#include <netbt/bluetooth.h>
|
|
|
|
#include <netbt/hci.h>
|
|
|
|
#include <netbt/l2cap.h>
|
|
|
|
#include <netbt/rfcomm.h>
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* RFCOMM DLC - Upper Protocol API
|
|
|
|
*
|
|
|
|
* Currently the only 'Port Emulation Entity' is the RFCOMM socket code
|
|
|
|
* but it is should be possible to provide a pseudo-device for a direct
|
|
|
|
* tty interface.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2014-05-20 22:25:54 +04:00
|
|
|
* rfcomm_attach_pcb(handle, proto, upper)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* attach a new RFCOMM DLC to handle, populate with reasonable defaults
|
|
|
|
*/
|
|
|
|
int
|
2014-05-20 22:25:54 +04:00
|
|
|
rfcomm_attach_pcb(struct rfcomm_dlc **handle,
|
2006-06-19 19:44:33 +04:00
|
|
|
const struct btproto *proto, void *upper)
|
|
|
|
{
|
|
|
|
struct rfcomm_dlc *dlc;
|
|
|
|
|
2007-03-31 00:47:02 +04:00
|
|
|
KASSERT(handle != NULL);
|
|
|
|
KASSERT(proto != NULL);
|
|
|
|
KASSERT(upper != NULL);
|
2006-06-19 19:44:33 +04:00
|
|
|
|
2014-11-17 00:34:27 +03:00
|
|
|
dlc = kmem_intr_zalloc(sizeof(struct rfcomm_dlc), KM_NOSLEEP);
|
|
|
|
if (dlc == NULL)
|
|
|
|
return ENOMEM;
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
dlc->rd_state = RFCOMM_DLC_CLOSED;
|
|
|
|
dlc->rd_mtu = rfcomm_mtu_default;
|
|
|
|
|
|
|
|
dlc->rd_proto = proto;
|
|
|
|
dlc->rd_upper = upper;
|
|
|
|
|
|
|
|
dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
|
|
|
|
dlc->rd_laddr.bt_family = AF_BLUETOOTH;
|
|
|
|
dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
|
|
|
|
|
|
|
|
dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
|
|
|
|
dlc->rd_raddr.bt_family = AF_BLUETOOTH;
|
|
|
|
dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
|
|
|
|
|
|
|
|
dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
|
|
|
|
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&dlc->rd_timeout, 0);
|
2006-06-19 19:44:33 +04:00
|
|
|
callout_setfunc(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc);
|
|
|
|
|
|
|
|
*handle = dlc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-07-24 19:12:03 +04:00
|
|
|
* rfcomm_bind_pcb(dlc, sockaddr)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* bind DLC to local address
|
|
|
|
*/
|
|
|
|
int
|
2014-07-24 19:12:03 +04:00
|
|
|
rfcomm_bind_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
|
2010-01-04 22:20:05 +03:00
|
|
|
if (dlc->rd_state != RFCOMM_DLC_CLOSED)
|
|
|
|
return EINVAL;
|
|
|
|
|
2006-06-19 19:44:33 +04:00
|
|
|
memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic()
usrreq switches and put into separate functions
xxx_{peer,sock}addr(struct socket *, struct mbuf *).
- KASSERT(solocked(so)) always in new functions even if request
is not implemented
- KASSERT(pcb != NULL) and KASSERT(nam) if the request is
implemented and not for tcp.
* for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into
easier to cut & paste functions tcp_debug_capture() and
tcp_debug_trace()
- functions provided by rmind
- remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a
future commit.
* rename netbt functions to permit consistency of pru function names
(as has been done with other requests already split out).
- l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb()
- rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb()
- sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb()
* split/refactor do_sys_getsockname(lwp, fd, which, nam) into
two functions do_sys_get{peer,sock}name(fd, nam).
- move PRU_PEERADDR handling into do_sys_getpeername() from
do_sys_getsockname()
- have svr4_stream directly call do_sys_get{sock,peer}name()
respectively instead of providing `which' & fix a DPRINTF string
that incorrectly wrote "getpeername" when it meant "getsockname"
- fix sys_getpeername() and sys_getsockname() to call
do_sys_get{sock,peer}name() without `which' and `lwp' & adjust
comments
- bump kernel version for removal of lwp & which parameters from
do_sys_getsockname()
note: future cleanup to remove struct mbuf * abuse in
xxx_{peer,sock}name()
still to come, not done in this commit since it is easier to do post
split.
patch reviewed by rmind
welcome to 6.99.47
2014-07-09 08:54:03 +04:00
|
|
|
* rfcomm_sockaddr_pcb(dlc, sockaddr)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* return local address
|
|
|
|
*/
|
|
|
|
int
|
* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic()
usrreq switches and put into separate functions
xxx_{peer,sock}addr(struct socket *, struct mbuf *).
- KASSERT(solocked(so)) always in new functions even if request
is not implemented
- KASSERT(pcb != NULL) and KASSERT(nam) if the request is
implemented and not for tcp.
* for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into
easier to cut & paste functions tcp_debug_capture() and
tcp_debug_trace()
- functions provided by rmind
- remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a
future commit.
* rename netbt functions to permit consistency of pru function names
(as has been done with other requests already split out).
- l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb()
- rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb()
- sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb()
* split/refactor do_sys_getsockname(lwp, fd, which, nam) into
two functions do_sys_get{peer,sock}name(fd, nam).
- move PRU_PEERADDR handling into do_sys_getpeername() from
do_sys_getsockname()
- have svr4_stream directly call do_sys_get{sock,peer}name()
respectively instead of providing `which' & fix a DPRINTF string
that incorrectly wrote "getpeername" when it meant "getsockname"
- fix sys_getpeername() and sys_getsockname() to call
do_sys_get{sock,peer}name() without `which' and `lwp' & adjust
comments
- bump kernel version for removal of lwp & which parameters from
do_sys_getsockname()
note: future cleanup to remove struct mbuf * abuse in
xxx_{peer,sock}name()
still to come, not done in this commit since it is easier to do post
split.
patch reviewed by rmind
welcome to 6.99.47
2014-07-09 08:54:03 +04:00
|
|
|
rfcomm_sockaddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-07-30 14:04:25 +04:00
|
|
|
* rfcomm_connect_pcb(dlc, sockaddr)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* Initiate connection of RFCOMM DLC to remote address.
|
|
|
|
*/
|
|
|
|
int
|
2014-07-30 14:04:25 +04:00
|
|
|
rfcomm_connect_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
struct rfcomm_session *rs;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (dlc->rd_state != RFCOMM_DLC_CLOSED)
|
|
|
|
return EISCONN;
|
|
|
|
|
|
|
|
memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
|
|
|
|
|
|
|
|
if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
|
|
|
|
|| dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
|
|
|
|
|| bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
|
|
|
|
return EDESTADDRREQ;
|
|
|
|
|
|
|
|
if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
|
|
|
|
dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
|
|
|
|
else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
|
|
|
|
&& (dlc->rd_raddr.bt_psm < 0x1001
|
|
|
|
|| L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We are allowed only one RFCOMM session between any 2 Bluetooth
|
|
|
|
* devices, so see if there is a session already otherwise create
|
|
|
|
* one and set it connecting.
|
|
|
|
*/
|
|
|
|
rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
|
|
|
|
if (rs == NULL) {
|
|
|
|
rs = rfcomm_session_alloc(&rfcomm_session_active,
|
|
|
|
&dlc->rd_laddr);
|
|
|
|
if (rs == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
|
|
|
|
rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
|
|
|
|
rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
|
|
|
|
|
2014-07-30 14:04:25 +04:00
|
|
|
err = l2cap_connect_pcb(rs->rs_l2cap, &dlc->rd_raddr);
|
2006-06-19 19:44:33 +04:00
|
|
|
if (err) {
|
|
|
|
rfcomm_session_free(rs);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This session will start up automatically when its
|
|
|
|
* L2CAP channel is connected.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/* construct DLC */
|
|
|
|
dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
|
|
|
|
if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
|
|
|
|
return EBUSY;
|
|
|
|
|
* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic()
usrreq switches and put into separate functions
xxx_{peer,sock}addr(struct socket *, struct mbuf *).
- KASSERT(solocked(so)) always in new functions even if request
is not implemented
- KASSERT(pcb != NULL) and KASSERT(nam) if the request is
implemented and not for tcp.
* for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into
easier to cut & paste functions tcp_debug_capture() and
tcp_debug_trace()
- functions provided by rmind
- remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a
future commit.
* rename netbt functions to permit consistency of pru function names
(as has been done with other requests already split out).
- l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb()
- rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb()
- sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb()
* split/refactor do_sys_getsockname(lwp, fd, which, nam) into
two functions do_sys_get{peer,sock}name(fd, nam).
- move PRU_PEERADDR handling into do_sys_getpeername() from
do_sys_getsockname()
- have svr4_stream directly call do_sys_get{sock,peer}name()
respectively instead of providing `which' & fix a DPRINTF string
that incorrectly wrote "getpeername" when it meant "getsockname"
- fix sys_getpeername() and sys_getsockname() to call
do_sys_get{sock,peer}name() without `which' and `lwp' & adjust
comments
- bump kernel version for removal of lwp & which parameters from
do_sys_getsockname()
note: future cleanup to remove struct mbuf * abuse in
xxx_{peer,sock}name()
still to come, not done in this commit since it is easier to do post
split.
patch reviewed by rmind
welcome to 6.99.47
2014-07-09 08:54:03 +04:00
|
|
|
l2cap_sockaddr_pcb(rs->rs_l2cap, &dlc->rd_laddr);
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* attach the DLC to the session and start it off
|
|
|
|
*/
|
|
|
|
dlc->rd_session = rs;
|
|
|
|
dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
|
|
|
|
LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
|
|
|
|
|
|
|
|
if (rs->rs_state == RFCOMM_SESSION_OPEN)
|
|
|
|
err = rfcomm_dlc_connect(dlc);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic()
usrreq switches and put into separate functions
xxx_{peer,sock}addr(struct socket *, struct mbuf *).
- KASSERT(solocked(so)) always in new functions even if request
is not implemented
- KASSERT(pcb != NULL) and KASSERT(nam) if the request is
implemented and not for tcp.
* for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into
easier to cut & paste functions tcp_debug_capture() and
tcp_debug_trace()
- functions provided by rmind
- remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a
future commit.
* rename netbt functions to permit consistency of pru function names
(as has been done with other requests already split out).
- l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb()
- rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb()
- sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb()
* split/refactor do_sys_getsockname(lwp, fd, which, nam) into
two functions do_sys_get{peer,sock}name(fd, nam).
- move PRU_PEERADDR handling into do_sys_getpeername() from
do_sys_getsockname()
- have svr4_stream directly call do_sys_get{sock,peer}name()
respectively instead of providing `which' & fix a DPRINTF string
that incorrectly wrote "getpeername" when it meant "getsockname"
- fix sys_getpeername() and sys_getsockname() to call
do_sys_get{sock,peer}name() without `which' and `lwp' & adjust
comments
- bump kernel version for removal of lwp & which parameters from
do_sys_getsockname()
note: future cleanup to remove struct mbuf * abuse in
xxx_{peer,sock}name()
still to come, not done in this commit since it is easier to do post
split.
patch reviewed by rmind
welcome to 6.99.47
2014-07-09 08:54:03 +04:00
|
|
|
* rfcomm_peeraddr_pcb(dlc, sockaddr)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* return remote address
|
|
|
|
*/
|
|
|
|
int
|
* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic()
usrreq switches and put into separate functions
xxx_{peer,sock}addr(struct socket *, struct mbuf *).
- KASSERT(solocked(so)) always in new functions even if request
is not implemented
- KASSERT(pcb != NULL) and KASSERT(nam) if the request is
implemented and not for tcp.
* for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into
easier to cut & paste functions tcp_debug_capture() and
tcp_debug_trace()
- functions provided by rmind
- remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a
future commit.
* rename netbt functions to permit consistency of pru function names
(as has been done with other requests already split out).
- l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb()
- rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb()
- sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb()
* split/refactor do_sys_getsockname(lwp, fd, which, nam) into
two functions do_sys_get{peer,sock}name(fd, nam).
- move PRU_PEERADDR handling into do_sys_getpeername() from
do_sys_getsockname()
- have svr4_stream directly call do_sys_get{sock,peer}name()
respectively instead of providing `which' & fix a DPRINTF string
that incorrectly wrote "getpeername" when it meant "getsockname"
- fix sys_getpeername() and sys_getsockname() to call
do_sys_get{sock,peer}name() without `which' and `lwp' & adjust
comments
- bump kernel version for removal of lwp & which parameters from
do_sys_getsockname()
note: future cleanup to remove struct mbuf * abuse in
xxx_{peer,sock}name()
still to come, not done in this commit since it is easier to do post
split.
patch reviewed by rmind
welcome to 6.99.47
2014-07-09 08:54:03 +04:00
|
|
|
rfcomm_peeraddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
split PRU_DISCONNECT, PRU_SHUTDOWN and PRU_ABORT function out of
pr_generic() usrreq switches and put into separate functions
xxx_disconnect(struct socket *)
xxx_shutdown(struct socket *)
xxx_abort(struct socket *)
- always KASSERT(solocked(so)) even if not implemented
- replace calls to pr_generic() with req =
PRU_{DISCONNECT,SHUTDOWN,ABORT}
with calls to pr_{disconnect,shutdown,abort}() respectively
rename existing internal functions used to implement above functionality
to permit use of the names for xxx_{disconnect,shutdown,abort}().
- {l2cap,sco,rfcomm}_disconnect() ->
{l2cap,sco,rfcomm}_disconnect_pcb()
- {unp,rip,tcp}_disconnect() -> {unp,rip,tcp}_disconnect1()
- unp_shutdown() -> unp_shutdown1()
patch reviewed by rmind
2014-07-31 07:39:35 +04:00
|
|
|
* rfcomm_disconnect_pcb(dlc, linger)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* disconnect RFCOMM DLC
|
|
|
|
*/
|
|
|
|
int
|
split PRU_DISCONNECT, PRU_SHUTDOWN and PRU_ABORT function out of
pr_generic() usrreq switches and put into separate functions
xxx_disconnect(struct socket *)
xxx_shutdown(struct socket *)
xxx_abort(struct socket *)
- always KASSERT(solocked(so)) even if not implemented
- replace calls to pr_generic() with req =
PRU_{DISCONNECT,SHUTDOWN,ABORT}
with calls to pr_{disconnect,shutdown,abort}() respectively
rename existing internal functions used to implement above functionality
to permit use of the names for xxx_{disconnect,shutdown,abort}().
- {l2cap,sco,rfcomm}_disconnect() ->
{l2cap,sco,rfcomm}_disconnect_pcb()
- {unp,rip,tcp}_disconnect() -> {unp,rip,tcp}_disconnect1()
- unp_shutdown() -> unp_shutdown1()
patch reviewed by rmind
2014-07-31 07:39:35 +04:00
|
|
|
rfcomm_disconnect_pcb(struct rfcomm_dlc *dlc, int linger)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
struct rfcomm_session *rs = dlc->rd_session;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
KASSERT(dlc != NULL);
|
|
|
|
|
|
|
|
switch (dlc->rd_state) {
|
|
|
|
case RFCOMM_DLC_CLOSED:
|
|
|
|
case RFCOMM_DLC_LISTEN:
|
|
|
|
return EINVAL;
|
|
|
|
|
2007-04-21 10:15:22 +04:00
|
|
|
case RFCOMM_DLC_WAIT_SEND_UA:
|
|
|
|
err = rfcomm_session_send_frame(rs,
|
|
|
|
RFCOMM_FRAME_DM, dlc->rd_dlci);
|
|
|
|
|
|
|
|
/* fall through */
|
2006-06-19 19:44:33 +04:00
|
|
|
case RFCOMM_DLC_WAIT_SESSION:
|
2007-04-21 10:15:22 +04:00
|
|
|
case RFCOMM_DLC_WAIT_CONNECT:
|
|
|
|
case RFCOMM_DLC_WAIT_SEND_SABM:
|
2006-06-19 19:44:33 +04:00
|
|
|
rfcomm_dlc_close(dlc, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RFCOMM_DLC_OPEN:
|
|
|
|
if (dlc->rd_txbuf != NULL && linger != 0) {
|
|
|
|
dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* else fall through */
|
2007-04-21 10:15:22 +04:00
|
|
|
case RFCOMM_DLC_WAIT_RECV_UA:
|
2006-06-19 19:44:33 +04:00
|
|
|
dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
|
|
|
|
err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
|
|
|
|
dlc->rd_dlci);
|
|
|
|
callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RFCOMM_DLC_WAIT_DISCONNECT:
|
|
|
|
err = EALREADY;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
UNKNOWN(dlc->rd_state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-05-20 22:25:54 +04:00
|
|
|
* rfcomm_detach_pcb(handle)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* detach RFCOMM DLC from handle
|
|
|
|
*/
|
2014-05-19 06:51:24 +04:00
|
|
|
void
|
2014-05-20 22:25:54 +04:00
|
|
|
rfcomm_detach_pcb(struct rfcomm_dlc **handle)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
struct rfcomm_dlc *dlc = *handle;
|
|
|
|
|
|
|
|
if (dlc->rd_state != RFCOMM_DLC_CLOSED)
|
|
|
|
rfcomm_dlc_close(dlc, 0);
|
|
|
|
|
|
|
|
if (dlc->rd_txbuf != NULL) {
|
|
|
|
m_freem(dlc->rd_txbuf);
|
|
|
|
dlc->rd_txbuf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
dlc->rd_upper = NULL;
|
|
|
|
*handle = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If callout is invoking we can't free the DLC so
|
|
|
|
* mark it and let the callout release it.
|
|
|
|
*/
|
|
|
|
if (callout_invoking(&dlc->rd_timeout))
|
|
|
|
dlc->rd_flags |= RFCOMM_DLC_DETACH;
|
2007-11-03 20:20:17 +03:00
|
|
|
else {
|
|
|
|
callout_destroy(&dlc->rd_timeout);
|
2014-11-17 00:34:27 +03:00
|
|
|
kmem_intr_free(dlc, sizeof(*dlc));
|
2007-11-03 20:20:17 +03:00
|
|
|
}
|
2006-06-19 19:44:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-07-24 19:12:03 +04:00
|
|
|
* rfcomm_listen_pcb(dlc)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* This DLC is a listener. We look for an existing listening session
|
|
|
|
* with a matching address to attach to or else create a new one on
|
2007-11-20 23:25:57 +03:00
|
|
|
* the listeners list. If the ANY channel is given, allocate the first
|
|
|
|
* available for the session.
|
2006-06-19 19:44:33 +04:00
|
|
|
*/
|
|
|
|
int
|
2014-07-24 19:12:03 +04:00
|
|
|
rfcomm_listen_pcb(struct rfcomm_dlc *dlc)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
2007-11-20 23:19:24 +03:00
|
|
|
struct rfcomm_session *rs;
|
2007-11-20 23:25:57 +03:00
|
|
|
struct rfcomm_dlc *used;
|
2006-06-19 19:44:33 +04:00
|
|
|
struct sockaddr_bt addr;
|
2007-11-20 23:25:57 +03:00
|
|
|
int err, channel;
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
if (dlc->rd_state != RFCOMM_DLC_CLOSED)
|
|
|
|
return EISCONN;
|
|
|
|
|
2007-11-20 23:25:57 +03:00
|
|
|
if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
|
|
|
|
&& (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
|
|
|
|
|| dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
|
2006-06-19 19:44:33 +04:00
|
|
|
return EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
|
|
|
|
dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
|
|
|
|
else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
|
|
|
|
&& (dlc->rd_laddr.bt_psm < 0x1001
|
|
|
|
|| L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
|
|
|
|
return EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
|
* split PRU_PEERADDR and PRU_SOCKADDR function out of pr_generic()
usrreq switches and put into separate functions
xxx_{peer,sock}addr(struct socket *, struct mbuf *).
- KASSERT(solocked(so)) always in new functions even if request
is not implemented
- KASSERT(pcb != NULL) and KASSERT(nam) if the request is
implemented and not for tcp.
* for tcp roll #ifdef KPROF and #ifdef DEBUG code from tcp_usrreq() into
easier to cut & paste functions tcp_debug_capture() and
tcp_debug_trace()
- functions provided by rmind
- remaining use of PRU_{PEER,SOCK}ADDR #define to be removed in a
future commit.
* rename netbt functions to permit consistency of pru function names
(as has been done with other requests already split out).
- l2cap_{peer,sock}addr() -> l2cap_{peer,sock}_addr_pcb()
- rfcomm_{peer,sock}addr() -> rfcomm_{peer,sock}_addr_pcb()
- sco_{peer,sock}addr() -> sco_{peer,sock}_addr_pcb()
* split/refactor do_sys_getsockname(lwp, fd, which, nam) into
two functions do_sys_get{peer,sock}name(fd, nam).
- move PRU_PEERADDR handling into do_sys_getpeername() from
do_sys_getsockname()
- have svr4_stream directly call do_sys_get{sock,peer}name()
respectively instead of providing `which' & fix a DPRINTF string
that incorrectly wrote "getpeername" when it meant "getsockname"
- fix sys_getpeername() and sys_getsockname() to call
do_sys_get{sock,peer}name() without `which' and `lwp' & adjust
comments
- bump kernel version for removal of lwp & which parameters from
do_sys_getsockname()
note: future cleanup to remove struct mbuf * abuse in
xxx_{peer,sock}name()
still to come, not done in this commit since it is easier to do post
split.
patch reviewed by rmind
welcome to 6.99.47
2014-07-09 08:54:03 +04:00
|
|
|
l2cap_sockaddr_pcb(rs->rs_l2cap, &addr);
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
if (addr.bt_psm != dlc->rd_laddr.bt_psm)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
|
2007-11-20 23:19:24 +03:00
|
|
|
break;
|
2006-06-19 19:44:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rs == NULL) {
|
|
|
|
rs = rfcomm_session_alloc(&rfcomm_session_listen,
|
|
|
|
&dlc->rd_laddr);
|
|
|
|
if (rs == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
|
|
|
|
rs->rs_state = RFCOMM_SESSION_LISTEN;
|
|
|
|
|
2014-07-24 19:12:03 +04:00
|
|
|
err = l2cap_listen_pcb(rs->rs_l2cap);
|
2006-06-19 19:44:33 +04:00
|
|
|
if (err) {
|
|
|
|
rfcomm_session_free(rs);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-20 23:25:57 +03:00
|
|
|
if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
|
|
|
|
channel = RFCOMM_CHANNEL_MIN;
|
|
|
|
used = LIST_FIRST(&rs->rs_dlcs);
|
|
|
|
|
|
|
|
while (used != NULL) {
|
|
|
|
if (used->rd_laddr.bt_channel == channel) {
|
|
|
|
if (channel++ == RFCOMM_CHANNEL_MAX)
|
|
|
|
return EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
used = LIST_FIRST(&rs->rs_dlcs);
|
|
|
|
} else {
|
|
|
|
used = LIST_NEXT(used, rd_next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dlc->rd_laddr.bt_channel = channel;
|
|
|
|
}
|
|
|
|
|
2006-06-19 19:44:33 +04:00
|
|
|
dlc->rd_session = rs;
|
|
|
|
dlc->rd_state = RFCOMM_DLC_LISTEN;
|
|
|
|
LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-08-05 11:55:31 +04:00
|
|
|
* rfcomm_send_pcb(dlc, mbuf)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* Output data on DLC. This is streamed data, so we add it
|
2009-11-22 22:09:15 +03:00
|
|
|
* to our buffer and start the DLC, which will assemble
|
2006-06-19 19:44:33 +04:00
|
|
|
* packets and send them if it can.
|
|
|
|
*/
|
|
|
|
int
|
2014-08-05 11:55:31 +04:00
|
|
|
rfcomm_send_pcb(struct rfcomm_dlc *dlc, struct mbuf *m)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
if (dlc->rd_txbuf != NULL) {
|
|
|
|
dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
|
|
|
|
m_cat(dlc->rd_txbuf, m);
|
|
|
|
} else {
|
|
|
|
dlc->rd_txbuf = m;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dlc->rd_state == RFCOMM_DLC_OPEN)
|
|
|
|
rfcomm_dlc_start(dlc);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-08-08 07:05:44 +04:00
|
|
|
* rfcomm_rcvd_pcb(dlc, space)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* Indicate space now available in receive buffer
|
|
|
|
*
|
|
|
|
* This should be used to give an initial value of the receive buffer
|
|
|
|
* size when the DLC is attached and anytime data is cleared from the
|
|
|
|
* buffer after that.
|
|
|
|
*/
|
|
|
|
int
|
2014-08-08 07:05:44 +04:00
|
|
|
rfcomm_rcvd_pcb(struct rfcomm_dlc *dlc, size_t space)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
KASSERT(dlc != NULL);
|
|
|
|
|
|
|
|
dlc->rd_rxsize = space;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if we are using credit based flow control, we may
|
|
|
|
* want to send some credits..
|
|
|
|
*/
|
|
|
|
if (dlc->rd_state == RFCOMM_DLC_OPEN
|
|
|
|
&& (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
|
|
|
|
rfcomm_dlc_start(dlc);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-08-06 19:01:23 +04:00
|
|
|
* rfcomm_setopt(dlc, sopt)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* set DLC options
|
|
|
|
*/
|
|
|
|
int
|
2008-08-06 19:01:23 +04:00
|
|
|
rfcomm_setopt(struct rfcomm_dlc *dlc, const struct sockopt *sopt)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
2007-04-21 10:15:22 +04:00
|
|
|
int mode, err = 0;
|
2007-03-06 22:04:31 +03:00
|
|
|
uint16_t mtu;
|
2006-06-19 19:44:33 +04:00
|
|
|
|
2008-08-06 19:01:23 +04:00
|
|
|
switch (sopt->sopt_name) {
|
2006-06-19 19:44:33 +04:00
|
|
|
case SO_RFCOMM_MTU:
|
2008-08-06 19:01:23 +04:00
|
|
|
err = sockopt_get(sopt, &mtu, sizeof(mtu));
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
|
2007-03-06 22:04:31 +03:00
|
|
|
if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
|
2006-06-19 19:44:33 +04:00
|
|
|
err = EINVAL;
|
2007-04-06 21:09:00 +04:00
|
|
|
else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
|
2007-03-06 22:04:31 +03:00
|
|
|
dlc->rd_mtu = mtu;
|
2007-04-06 21:09:00 +04:00
|
|
|
else
|
|
|
|
err = EBUSY;
|
2007-03-06 22:04:31 +03:00
|
|
|
|
2006-06-19 19:44:33 +04:00
|
|
|
break;
|
|
|
|
|
2007-04-21 10:15:22 +04:00
|
|
|
case SO_RFCOMM_LM:
|
2008-08-06 19:01:23 +04:00
|
|
|
err = sockopt_getint(sopt, &mode);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
|
2007-04-21 10:15:22 +04:00
|
|
|
mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
|
|
|
|
|
|
|
|
if (mode & RFCOMM_LM_SECURE)
|
|
|
|
mode |= RFCOMM_LM_ENCRYPT;
|
|
|
|
|
|
|
|
if (mode & RFCOMM_LM_ENCRYPT)
|
|
|
|
mode |= RFCOMM_LM_AUTH;
|
|
|
|
|
|
|
|
dlc->rd_mode = mode;
|
|
|
|
|
|
|
|
if (dlc->rd_state == RFCOMM_DLC_OPEN)
|
|
|
|
err = rfcomm_dlc_setmode(dlc);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2006-06-19 19:44:33 +04:00
|
|
|
default:
|
2007-03-05 22:11:54 +03:00
|
|
|
err = ENOPROTOOPT;
|
2006-06-19 19:44:33 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-08-06 19:01:23 +04:00
|
|
|
* rfcomm_getopt(dlc, sopt)
|
2006-06-19 19:44:33 +04:00
|
|
|
*
|
|
|
|
* get DLC options
|
|
|
|
*/
|
|
|
|
int
|
2008-08-06 19:01:23 +04:00
|
|
|
rfcomm_getopt(struct rfcomm_dlc *dlc, struct sockopt *sopt)
|
2006-06-19 19:44:33 +04:00
|
|
|
{
|
2008-08-06 19:01:23 +04:00
|
|
|
struct rfcomm_fc_info fc;
|
2006-06-19 19:44:33 +04:00
|
|
|
|
2008-08-06 19:01:23 +04:00
|
|
|
switch (sopt->sopt_name) {
|
2006-06-19 19:44:33 +04:00
|
|
|
case SO_RFCOMM_MTU:
|
2008-08-06 19:01:23 +04:00
|
|
|
return sockopt_set(sopt, &dlc->rd_mtu, sizeof(uint16_t));
|
2006-06-19 19:44:33 +04:00
|
|
|
|
|
|
|
case SO_RFCOMM_FC_INFO:
|
2008-08-06 19:01:23 +04:00
|
|
|
memset(&fc, 0, sizeof(fc));
|
|
|
|
fc.lmodem = dlc->rd_lmodem;
|
|
|
|
fc.rmodem = dlc->rd_rmodem;
|
Rename min/max -> uimin/uimax for better honesty.
These functions are defined on unsigned int. The generic name
min/max should not silently truncate to 32 bits on 64-bit systems.
This is purely a name change -- no functional change intended.
HOWEVER! Some subsystems have
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
even though our standard name for that is MIN/MAX. Although these
may invite multiple evaluation bugs, these do _not_ cause integer
truncation.
To avoid `fixing' these cases, I first changed the name in libkern,
and then compile-tested every file where min/max occurred in order to
confirm that it failed -- and thus confirm that nothing shadowed
min/max -- before changing it.
I have left a handful of bootloaders that are too annoying to
compile-test, and some dead code:
cobalt ews4800mips hp300 hppa ia64 luna68k vax
acorn32/if_ie.c (not included in any kernels)
macppc/if_gm.c (superseded by gem(4))
It should be easy to fix the fallout once identified -- this way of
doing things fails safe, and the goal here, after all, is to _avoid_
silent integer truncations, not introduce them.
Maybe one day we can reintroduce min/max as type-generic things that
never silently truncate. But we should avoid doing that for a while,
so that existing code has a chance to be detected by the compiler for
conversion to uimin/uimax without changing the semantics until we can
properly audit it all. (Who knows, maybe in some cases integer
truncation is actually intended!)
2018-09-03 19:29:22 +03:00
|
|
|
fc.tx_cred = uimax(dlc->rd_txcred, 0xff);
|
|
|
|
fc.rx_cred = uimax(dlc->rd_rxcred, 0xff);
|
2006-06-19 19:44:33 +04:00
|
|
|
if (dlc->rd_session
|
|
|
|
&& (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
|
2008-08-06 19:01:23 +04:00
|
|
|
fc.cfc = 1;
|
2006-06-19 19:44:33 +04:00
|
|
|
|
2008-08-06 19:01:23 +04:00
|
|
|
return sockopt_set(sopt, &fc, sizeof(fc));
|
2006-06-19 19:44:33 +04:00
|
|
|
|
2007-04-21 10:15:22 +04:00
|
|
|
case SO_RFCOMM_LM:
|
2008-08-06 19:01:23 +04:00
|
|
|
return sockopt_setint(sopt, dlc->rd_mode);
|
2007-04-21 10:15:22 +04:00
|
|
|
|
2006-06-19 19:44:33 +04:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-08-06 19:01:23 +04:00
|
|
|
return ENOPROTOOPT;
|
2006-06-19 19:44:33 +04:00
|
|
|
}
|