Fix mbuf leaks in various pru_send implementations
The various protocol implementations are not very consistent about freeing mbufs in error paths. In general, all protocols must free both "m" and "control" upon an error, except if PRUS_NOTREADY is specified (this is only implemented by TCP and unix(4) and requires further work not handled in this diff), in which case "control" still must be freed. This diff plugs various leaks in the pru_send implementations. Reviewed by: tuexen MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D30151
This commit is contained in:
parent
c1dd4d642f
commit
d8acd2681b
@ -3741,7 +3741,11 @@ pru_send_notsupp(struct socket *so, int flags, struct mbuf *m,
|
|||||||
struct sockaddr *addr, struct mbuf *control, struct thread *td)
|
struct sockaddr *addr, struct mbuf *control, struct thread *td)
|
||||||
{
|
{
|
||||||
|
|
||||||
return EOPNOTSUPP;
|
if (control != NULL)
|
||||||
|
m_freem(control);
|
||||||
|
if ((flags & PRUS_NOTREADY) == 0)
|
||||||
|
m_freem(m);
|
||||||
|
return (EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -677,6 +677,8 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
if (m->m_len < sizeof (struct ip) &&
|
if (m->m_len < sizeof (struct ip) &&
|
||||||
(m = m_pullup(m, sizeof (struct ip))) == NULL) {
|
(m = m_pullup(m, sizeof (struct ip))) == NULL) {
|
||||||
KMOD_IPSTAT_INC(ips_toosmall);
|
KMOD_IPSTAT_INC(ips_toosmall);
|
||||||
|
if (control != NULL)
|
||||||
|
m_freem(control);
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1077,13 +1077,18 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
inp = sotoinpcb(so);
|
inp = sotoinpcb(so);
|
||||||
KASSERT(inp != NULL, ("rip_send: inp == NULL"));
|
KASSERT(inp != NULL, ("rip_send: inp == NULL"));
|
||||||
|
|
||||||
|
if (control != NULL) {
|
||||||
|
m_freem(control);
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: 'dst' reads below are unlocked.
|
* Note: 'dst' reads below are unlocked.
|
||||||
*/
|
*/
|
||||||
if (so->so_state & SS_ISCONNECTED) {
|
if (so->so_state & SS_ISCONNECTED) {
|
||||||
if (nam) {
|
if (nam) {
|
||||||
m_freem(m);
|
error = EISCONN;
|
||||||
return (EISCONN);
|
goto release;
|
||||||
}
|
}
|
||||||
dst = inp->inp_faddr.s_addr; /* Unlocked read. */
|
dst = inp->inp_faddr.s_addr; /* Unlocked read. */
|
||||||
} else {
|
} else {
|
||||||
@ -1094,13 +1099,15 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
else if (nam->sa_len != sizeof(struct sockaddr_in))
|
else if (nam->sa_len != sizeof(struct sockaddr_in))
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
if (error != 0) {
|
if (error != 0)
|
||||||
m_freem(m);
|
goto release;
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
|
dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
|
||||||
}
|
}
|
||||||
return (rip_output(m, so, dst));
|
return (rip_output(m, so, dst));
|
||||||
|
|
||||||
|
release:
|
||||||
|
m_freem(m);
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
#endif /* INET */
|
#endif /* INET */
|
||||||
|
|
||||||
|
@ -993,21 +993,31 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
|
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
|
||||||
if (control)
|
if (control)
|
||||||
m_freem(control);
|
m_freem(control);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of PRUS_NOTREADY, tcp_usr_ready() is responsible
|
* In case of PRUS_NOTREADY, tcp_usr_ready() is responsible
|
||||||
* for freeing memory.
|
* for freeing memory.
|
||||||
*/
|
*/
|
||||||
if (m && (flags & PRUS_NOTREADY) == 0)
|
if ((flags & PRUS_NOTREADY) == 0)
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = ECONNRESET;
|
error = ECONNRESET;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (control != NULL) {
|
||||||
|
/* TCP doesn't do control messages (rights, creds, etc) */
|
||||||
|
if (control->m_len) {
|
||||||
|
m_freem(control);
|
||||||
|
m_freem(m);
|
||||||
|
error = EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
m_freem(control); /* empty control, just free it */
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
tp = intotcpcb(inp);
|
tp = intotcpcb(inp);
|
||||||
if (flags & PRUS_OOB) {
|
if (flags & PRUS_OOB) {
|
||||||
if ((error = tcp_pru_options_support(tp, PRUS_OOB)) != 0) {
|
if ((error = tcp_pru_options_support(tp, PRUS_OOB)) != 0) {
|
||||||
if (control)
|
if ((flags & PRUS_NOTREADY) == 0)
|
||||||
m_freem(control);
|
|
||||||
if (m && (flags & PRUS_NOTREADY) == 0)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1019,32 +1029,27 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
case AF_INET:
|
case AF_INET:
|
||||||
sinp = (struct sockaddr_in *)nam;
|
sinp = (struct sockaddr_in *)nam;
|
||||||
if (sinp->sin_len != sizeof(struct sockaddr_in)) {
|
if (sinp->sin_len != sizeof(struct sockaddr_in)) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((inp->inp_vflag & INP_IPV6) != 0) {
|
if ((inp->inp_vflag & INP_IPV6) != 0) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
|
if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ntohl(sinp->sin_addr.s_addr) == INADDR_BROADCAST) {
|
if (ntohl(sinp->sin_addr.s_addr) == INADDR_BROADCAST) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EACCES;
|
error = EACCES;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((error = prison_remote_ip4(td->td_ucred,
|
if ((error = prison_remote_ip4(td->td_ucred,
|
||||||
&sinp->sin_addr))) {
|
&sinp->sin_addr))) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1060,19 +1065,16 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
|
|
||||||
sin6 = (struct sockaddr_in6 *)nam;
|
sin6 = (struct sockaddr_in6 *)nam;
|
||||||
if (sin6->sin6_len != sizeof(*sin6)) {
|
if (sin6->sin6_len != sizeof(*sin6)) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((inp->inp_vflag & INP_IPV6PROTO) == 0) {
|
if ((inp->inp_vflag & INP_IPV6PROTO) == 0) {
|
||||||
if (m != NULL)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
|
if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
@ -1081,13 +1083,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
#ifdef INET
|
#ifdef INET
|
||||||
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
|
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((inp->inp_vflag & INP_IPV4) == 0) {
|
if ((inp->inp_vflag & INP_IPV4) == 0) {
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1098,26 +1098,22 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
if (IN_MULTICAST(
|
if (IN_MULTICAST(
|
||||||
ntohl(sinp->sin_addr.s_addr))) {
|
ntohl(sinp->sin_addr.s_addr))) {
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((error = prison_remote_ip4(td->td_ucred,
|
if ((error = prison_remote_ip4(td->td_ucred,
|
||||||
&sinp->sin_addr))) {
|
&sinp->sin_addr))) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
isipv6 = 0;
|
isipv6 = 0;
|
||||||
#else /* !INET */
|
#else /* !INET */
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
#endif /* INET */
|
#endif /* INET */
|
||||||
} else {
|
} else {
|
||||||
if ((inp->inp_vflag & INP_IPV6) == 0) {
|
if ((inp->inp_vflag & INP_IPV6) == 0) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
@ -1127,7 +1123,6 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
inp->inp_inc.inc_flags |= INC_ISIPV6;
|
inp->inp_inc.inc_flags |= INC_ISIPV6;
|
||||||
if ((error = prison_remote_ip6(td->td_ucred,
|
if ((error = prison_remote_ip6(td->td_ucred,
|
||||||
&sin6->sin6_addr))) {
|
&sin6->sin6_addr))) {
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1137,23 +1132,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
|
|||||||
}
|
}
|
||||||
#endif /* INET6 */
|
#endif /* INET6 */
|
||||||
default:
|
default:
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
error = EAFNOSUPPORT;
|
error = EAFNOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (control) {
|
|
||||||
/* TCP doesn't do control messages (rights, creds, etc) */
|
|
||||||
if (control->m_len) {
|
|
||||||
m_freem(control);
|
|
||||||
if (m)
|
|
||||||
m_freem(m);
|
|
||||||
error = EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
m_freem(control); /* empty control, just free it */
|
|
||||||
}
|
|
||||||
if (!(flags & PRUS_OOB)) {
|
if (!(flags & PRUS_OOB)) {
|
||||||
sbappendstream(&so->so_snd, m, flags);
|
sbappendstream(&so->so_snd, m, flags);
|
||||||
if (nam && tp->t_state < TCPS_SYN_SENT) {
|
if (nam && tp->t_state < TCPS_SYN_SENT) {
|
||||||
|
@ -1273,6 +1273,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_freem(control);
|
m_freem(control);
|
||||||
|
control = NULL;
|
||||||
}
|
}
|
||||||
if (error)
|
if (error)
|
||||||
goto release;
|
goto release;
|
||||||
|
@ -867,7 +867,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
struct sockaddr_in6 tmp;
|
struct sockaddr_in6 tmp;
|
||||||
struct sockaddr_in6 *dst;
|
struct sockaddr_in6 *dst;
|
||||||
int ret;
|
int error;
|
||||||
|
|
||||||
inp = sotoinpcb(so);
|
inp = sotoinpcb(so);
|
||||||
KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
|
KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
|
||||||
@ -876,8 +876,8 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
/* Unlocked read. */
|
/* Unlocked read. */
|
||||||
if (so->so_state & SS_ISCONNECTED) {
|
if (so->so_state & SS_ISCONNECTED) {
|
||||||
if (nam) {
|
if (nam) {
|
||||||
m_freem(m);
|
error = EISCONN;
|
||||||
return (EISCONN);
|
goto release;
|
||||||
}
|
}
|
||||||
/* XXX */
|
/* XXX */
|
||||||
bzero(&tmp, sizeof(tmp));
|
bzero(&tmp, sizeof(tmp));
|
||||||
@ -889,18 +889,15 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
INP_RUNLOCK(inp);
|
INP_RUNLOCK(inp);
|
||||||
dst = &tmp;
|
dst = &tmp;
|
||||||
} else {
|
} else {
|
||||||
if (nam == NULL) {
|
error = 0;
|
||||||
m_freem(m);
|
if (nam == NULL)
|
||||||
return (ENOTCONN);
|
error = ENOTCONN;
|
||||||
}
|
else if (nam->sa_family != AF_INET6)
|
||||||
if (nam->sa_family != AF_INET6) {
|
error = EAFNOSUPPORT;
|
||||||
m_freem(m);
|
else if (nam->sa_len != sizeof(struct sockaddr_in6))
|
||||||
return (EAFNOSUPPORT);
|
error = EINVAL;
|
||||||
}
|
if (error != 0)
|
||||||
if (nam->sa_len != sizeof(struct sockaddr_in6)) {
|
goto release;
|
||||||
m_freem(m);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
tmp = *(struct sockaddr_in6 *)nam;
|
tmp = *(struct sockaddr_in6 *)nam;
|
||||||
dst = &tmp;
|
dst = &tmp;
|
||||||
|
|
||||||
@ -914,12 +911,17 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
"unspec. Assume AF_INET6\n");
|
"unspec. Assume AF_INET6\n");
|
||||||
dst->sin6_family = AF_INET6;
|
dst->sin6_family = AF_INET6;
|
||||||
} else if (dst->sin6_family != AF_INET6) {
|
} else if (dst->sin6_family != AF_INET6) {
|
||||||
|
error = EAFNOSUPPORT;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (rip6_output(m, so, dst, control));
|
||||||
|
|
||||||
|
release:
|
||||||
|
if (control != NULL)
|
||||||
|
m_freem(control);
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
return(EAFNOSUPPORT);
|
return (error);
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = rip6_output(m, so, dst, control);
|
|
||||||
return (ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pr_usrreqs rip6_usrreqs = {
|
struct pr_usrreqs rip6_usrreqs = {
|
||||||
|
@ -713,6 +713,11 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
|||||||
#ifdef INET
|
#ifdef INET
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
if (addr->sa_len != sizeof(struct sockaddr_in)) {
|
if (addr->sa_len != sizeof(struct sockaddr_in)) {
|
||||||
|
if (control) {
|
||||||
|
SCTP_RELEASE_PKT(control);
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
|
SCTP_RELEASE_PKT(m);
|
||||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
@ -721,12 +726,22 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
|||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||||
|
if (control) {
|
||||||
|
SCTP_RELEASE_PKT(control);
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
|
SCTP_RELEASE_PKT(m);
|
||||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
if (control) {
|
||||||
|
SCTP_RELEASE_PKT(control);
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
|
SCTP_RELEASE_PKT(m);
|
||||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
@ -738,10 +753,20 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
|||||||
* v4 addr or v4-mapped addr
|
* v4 addr or v4-mapped addr
|
||||||
*/
|
*/
|
||||||
if (addr->sa_family == AF_INET) {
|
if (addr->sa_family == AF_INET) {
|
||||||
|
if (control) {
|
||||||
|
SCTP_RELEASE_PKT(control);
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
|
SCTP_RELEASE_PKT(m);
|
||||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
||||||
|
if (control) {
|
||||||
|
SCTP_RELEASE_PKT(control);
|
||||||
|
control = NULL;
|
||||||
|
}
|
||||||
|
SCTP_RELEASE_PKT(m);
|
||||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
|
@ -250,8 +250,11 @@ send_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
|||||||
m = NULL;
|
m = NULL;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
if (control != NULL)
|
||||||
|
m_freem(control);
|
||||||
if (m != NULL)
|
if (m != NULL)
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user