Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/sctp_usrreq.c
Show First 20 Lines • Show All 6,999 Lines • ▼ Show 20 Lines | sctp_listen(struct socket *so, int backlog, struct thread *p) | ||||
struct sctp_inpcb *inp; | struct sctp_inpcb *inp; | ||||
inp = (struct sctp_inpcb *)so->so_pcb; | inp = (struct sctp_inpcb *)so->so_pcb; | ||||
if (inp == NULL) { | if (inp == NULL) { | ||||
/* I made the same as TCP since we are not setup? */ | /* I made the same as TCP since we are not setup? */ | ||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); | ||||
return (ECONNRESET); | return (ECONNRESET); | ||||
} | } | ||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) | |||||
return (EOPNOTSUPP); | |||||
tuexen: Calliing listen() on a 1-to-many style socket is perfectly fine. See [[https://tools.ietf. | |||||
tuexenUnsubmitted Not Done Inline ActionsI meant: Why do you fail it... tuexen: I meant: Why do you fail it... | |||||
glebiusUnsubmitted Not Done Inline ActionsYes, this change is definitely wrong. My understanding of 1-to-many listening is that we just mark the SCTP pcb as open for new connections, and we don't actually do anything to the socket itself, since a 1-to-many can't have an accept queue. So, would the correct fix be to just skip calling solisten_proto() for the 1-to-many sockets? Can you please point me to the code where we will automatically accept (or not accept) new associations? glebius: Yes, this change is definitely wrong.
My understanding of 1-to-many listening is that we just… | |||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { | if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { | ||||
/* See if we have a listener */ | /* See if we have a listener */ | ||||
struct sctp_inpcb *tinp; | struct sctp_inpcb *tinp; | ||||
union sctp_sockstore store; | union sctp_sockstore store; | ||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { | if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { | ||||
/* not bound all */ | /* not bound all */ | ||||
struct sctp_laddr *laddr; | struct sctp_laddr *laddr; | ||||
Show All 13 Lines | |||||
#endif | #endif | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); | tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); | ||||
if (tinp && (tinp != inp) && | if (tinp && (tinp != inp) && | ||||
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && | ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && | ||||
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && | ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && | ||||
(tinp->sctp_socket->so_qlimit)) { | SOLISTENING(tinp->sctp_socket)) { | ||||
/* | /* | ||||
* we have a listener already and | * we have a listener already and | ||||
* its not this inp. | * its not this inp. | ||||
*/ | */ | ||||
SCTP_INP_DECR_REF(tinp); | SCTP_INP_DECR_REF(tinp); | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} else if (tinp) { | } else if (tinp) { | ||||
SCTP_INP_DECR_REF(tinp); | SCTP_INP_DECR_REF(tinp); | ||||
Show All 27 Lines | |||||
#endif | #endif | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); | tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); | ||||
if (tinp && (tinp != inp) && | if (tinp && (tinp != inp) && | ||||
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && | ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && | ||||
((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && | ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && | ||||
(tinp->sctp_socket->so_qlimit)) { | SOLISTENING(tinp->sctp_socket)) { | ||||
/* | /* | ||||
* we have a listener already and its not | * we have a listener already and its not | ||||
* this inp. | * this inp. | ||||
*/ | */ | ||||
SCTP_INP_DECR_REF(tinp); | SCTP_INP_DECR_REF(tinp); | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} else if (tinp) { | } else if (tinp) { | ||||
SCTP_INP_DECR_REF(tinp); | SCTP_INP_DECR_REF(tinp); | ||||
Show All 38 Lines | #endif | ||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { | if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { | ||||
/* We must do a bind. */ | /* We must do a bind. */ | ||||
if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { | if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { | ||||
/* bind error, probably perm */ | /* bind error, probably perm */ | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
/* It appears for 7.0 and on, we must always call this. */ | |||||
solisten_proto(so, backlog); | solisten_proto(so, backlog); | ||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { | |||||
tuexenUnsubmitted Not Done Inline ActionsI think we need to keep this, since you will not be able to call connect() on a 1-to-many style socket after having called listen() if you remove it. tuexen: I think we need to keep this, since you will not be able to call `connect()` on a 1-to-many… | |||||
/* remove the ACCEPTCONN flag for one-to-many sockets */ | |||||
so->so_options &= ~SO_ACCEPTCONN; | |||||
} | |||||
if (backlog == 0) { | |||||
/* turning off listen */ | |||||
so->so_options &= ~SO_ACCEPTCONN; | |||||
} | |||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int sctp_defered_wakeup_cnt = 0; | static int sctp_defered_wakeup_cnt = 0; | ||||
int | int | ||||
sctp_accept(struct socket *so, struct sockaddr **addr) | sctp_accept(struct socket *so, struct sockaddr **addr) | ||||
▲ Show 20 Lines • Show All 289 Lines • Show Last 20 Lines |
Calliing listen() on a 1-to-many style socket is perfectly fine. See RFC 6458. Why don't you fail it indicating EOPNOTSUPP?