raw_usrreq.c revision 139823
1/*- 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)raw_usrreq.c 8.1 (Berkeley) 6/10/93 30 * $FreeBSD: head/sys/net/raw_usrreq.c 139823 2005-01-07 01:45:51Z imp $ 31 */ 32 33#include <sys/param.h> 34#include <sys/kernel.h> 35#include <sys/lock.h> 36#include <sys/malloc.h> 37#include <sys/mbuf.h> 38#include <sys/mutex.h> 39#include <sys/protosw.h> 40#include <sys/signalvar.h> 41#include <sys/socket.h> 42#include <sys/socketvar.h> 43#include <sys/sx.h> 44#include <sys/systm.h> 45 46#include <net/raw_cb.h> 47 48MTX_SYSINIT(rawcb_mtx, &rawcb_mtx, "rawcb", MTX_DEF); 49 50/* 51 * Initialize raw connection block q. 52 */ 53void 54raw_init() 55{ 56 57 LIST_INIT(&rawcb_list); 58} 59 60 61/* 62 * Raw protocol input routine. Find the socket 63 * associated with the packet(s) and move them over. If 64 * nothing exists for this packet, drop it. 65 */ 66/* 67 * Raw protocol interface. 68 */ 69void 70raw_input(m0, proto, src, dst) 71 struct mbuf *m0; 72 register struct sockproto *proto; 73 struct sockaddr *src, *dst; 74{ 75 register struct rawcb *rp; 76 register struct mbuf *m = m0; 77 struct socket *last; 78 79 last = 0; 80 mtx_lock(&rawcb_mtx); 81 LIST_FOREACH(rp, &rawcb_list, list) { 82 if (rp->rcb_proto.sp_family != proto->sp_family) 83 continue; 84 if (rp->rcb_proto.sp_protocol && 85 rp->rcb_proto.sp_protocol != proto->sp_protocol) 86 continue; 87 /* 88 * We assume the lower level routines have 89 * placed the address in a canonical format 90 * suitable for a structure comparison. 91 * 92 * Note that if the lengths are not the same 93 * the comparison will fail at the first byte. 94 */ 95#define equal(a1, a2) \ 96 (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) 97 if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) 98 continue; 99 if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) 100 continue; 101 if (last) { 102 struct mbuf *n; 103 n = m_copy(m, 0, (int)M_COPYALL); 104 if (n) { 105 if (sbappendaddr(&last->so_rcv, src, 106 n, (struct mbuf *)0) == 0) 107 /* should notify about lost packet */ 108 m_freem(n); 109 else { 110 sorwakeup(last); 111 } 112 } 113 } 114 last = rp->rcb_socket; 115 } 116 if (last) { 117 if (sbappendaddr(&last->so_rcv, src, 118 m, (struct mbuf *)0) == 0) 119 m_freem(m); 120 else { 121 sorwakeup(last); 122 } 123 } else 124 m_freem(m); 125 mtx_unlock(&rawcb_mtx); 126} 127 128/*ARGSUSED*/ 129void 130raw_ctlinput(cmd, arg, dummy) 131 int cmd; 132 struct sockaddr *arg; 133 void *dummy; 134{ 135 136 if (cmd < 0 || cmd >= PRC_NCMDS) 137 return; 138 /* INCOMPLETE */ 139} 140 141static int 142raw_uabort(struct socket *so) 143{ 144 struct rawcb *rp = sotorawcb(so); 145 146 if (rp == 0) 147 return EINVAL; 148 raw_disconnect(rp); 149 soisdisconnected(so); 150 ACCEPT_LOCK(); 151 SOCK_LOCK(so); 152 sotryfree(so); 153 return 0; 154} 155 156/* pru_accept is EOPNOTSUPP */ 157 158static int 159raw_uattach(struct socket *so, int proto, struct thread *td) 160{ 161 struct rawcb *rp = sotorawcb(so); 162 int error; 163 164 if (rp == 0) 165 return EINVAL; 166 if (td && (error = suser(td)) != 0) 167 return error; 168 return raw_attach(so, proto); 169} 170 171static int 172raw_ubind(struct socket *so, struct sockaddr *nam, struct thread *td) 173{ 174 return EINVAL; 175} 176 177static int 178raw_uconnect(struct socket *so, struct sockaddr *nam, struct thread *td) 179{ 180 return EINVAL; 181} 182 183/* pru_connect2 is EOPNOTSUPP */ 184/* pru_control is EOPNOTSUPP */ 185 186static int 187raw_udetach(struct socket *so) 188{ 189 struct rawcb *rp = sotorawcb(so); 190 191 if (rp == 0) 192 return EINVAL; 193 194 raw_detach(rp); 195 return 0; 196} 197 198static int 199raw_udisconnect(struct socket *so) 200{ 201 struct rawcb *rp = sotorawcb(so); 202 203 if (rp == 0) 204 return EINVAL; 205 if (rp->rcb_faddr == 0) { 206 return ENOTCONN; 207 } 208 raw_disconnect(rp); 209 soisdisconnected(so); 210 return 0; 211} 212 213/* pru_listen is EOPNOTSUPP */ 214 215static int 216raw_upeeraddr(struct socket *so, struct sockaddr **nam) 217{ 218 struct rawcb *rp = sotorawcb(so); 219 220 if (rp == 0) 221 return EINVAL; 222 if (rp->rcb_faddr == 0) { 223 return ENOTCONN; 224 } 225 *nam = sodupsockaddr(rp->rcb_faddr, M_WAITOK); 226 return 0; 227} 228 229/* pru_rcvd is EOPNOTSUPP */ 230/* pru_rcvoob is EOPNOTSUPP */ 231 232static int 233raw_usend(struct socket *so, int flags, struct mbuf *m, 234 struct sockaddr *nam, struct mbuf *control, struct thread *td) 235{ 236 int error; 237 struct rawcb *rp = sotorawcb(so); 238 239 if (rp == 0) { 240 error = EINVAL; 241 goto release; 242 } 243 244 if (flags & PRUS_OOB) { 245 error = EOPNOTSUPP; 246 goto release; 247 } 248 249 if (control && control->m_len) { 250 error = EOPNOTSUPP; 251 goto release; 252 } 253 if (nam) { 254 if (rp->rcb_faddr) { 255 error = EISCONN; 256 goto release; 257 } 258 rp->rcb_faddr = nam; 259 } else if (rp->rcb_faddr == 0) { 260 error = ENOTCONN; 261 goto release; 262 } 263 error = (*so->so_proto->pr_output)(m, so); 264 m = NULL; 265 if (nam) 266 rp->rcb_faddr = 0; 267release: 268 if (m != NULL) 269 m_freem(m); 270 return (error); 271} 272 273/* pru_sense is null */ 274 275static int 276raw_ushutdown(struct socket *so) 277{ 278 struct rawcb *rp = sotorawcb(so); 279 280 if (rp == 0) 281 return EINVAL; 282 socantsendmore(so); 283 return 0; 284} 285 286static int 287raw_usockaddr(struct socket *so, struct sockaddr **nam) 288{ 289 struct rawcb *rp = sotorawcb(so); 290 291 if (rp == 0) 292 return EINVAL; 293 if (rp->rcb_laddr == 0) 294 return EINVAL; 295 *nam = sodupsockaddr(rp->rcb_laddr, M_WAITOK); 296 return 0; 297} 298 299struct pr_usrreqs raw_usrreqs = { 300 .pru_abort = raw_uabort, 301 .pru_attach = raw_uattach, 302 .pru_bind = raw_ubind, 303 .pru_connect = raw_uconnect, 304 .pru_detach = raw_udetach, 305 .pru_disconnect = raw_udisconnect, 306 .pru_peeraddr = raw_upeeraddr, 307 .pru_send = raw_usend, 308 .pru_shutdown = raw_ushutdown, 309 .pru_sockaddr = raw_usockaddr, 310}; 311