1 /* $NetBSD: raw_usrreq.c,v 1.37 2011/07/17 20:54:52 joerg Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)raw_usrreq.c 8.1 (Berkeley) 6/10/93 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: raw_usrreq.c,v 1.37 2011/07/17 20:54:52 joerg Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/mbuf.h> 39 #include <sys/domain.h> 40 #include <sys/protosw.h> 41 #include <sys/socket.h> 42 #include <sys/socketvar.h> 43 #include <sys/errno.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/kauth.h> 47 48 #include <net/if.h> 49 #include <net/route.h> 50 #include <net/netisr.h> 51 #include <net/raw_cb.h> 52 53 /* 54 * Initialize raw connection block q. 55 */ 56 void 57 raw_init(void) 58 { 59 60 LIST_INIT(&rawcb); 61 } 62 63 static inline int 64 equal(const struct sockaddr *a1, const struct sockaddr *a2) 65 { 66 return memcmp(a1, a2, a1->sa_len) == 0; 67 } 68 69 /* 70 * Raw protocol input routine. Find the socket 71 * associated with the packet(s) and move them over. If 72 * nothing exists for this packet, drop it. 73 */ 74 /* 75 * Raw protocol interface. 76 */ 77 void 78 raw_input(struct mbuf *m0, ...) 79 { 80 struct rawcb *rp; 81 struct mbuf *m = m0; 82 struct socket *last; 83 va_list ap; 84 struct sockproto *proto; 85 struct sockaddr *src, *dst; 86 87 KASSERT(mutex_owned(softnet_lock)); 88 89 va_start(ap, m0); 90 proto = va_arg(ap, struct sockproto *); 91 src = va_arg(ap, struct sockaddr *); 92 dst = va_arg(ap, struct sockaddr *); 93 va_end(ap); 94 95 last = NULL; 96 LIST_FOREACH(rp, &rawcb, rcb_list) { 97 if (rp->rcb_proto.sp_family != proto->sp_family) 98 continue; 99 if (rp->rcb_proto.sp_protocol && 100 rp->rcb_proto.sp_protocol != proto->sp_protocol) 101 continue; 102 /* 103 * We assume the lower level routines have 104 * placed the address in a canonical format 105 * suitable for a structure comparison. 106 * 107 * Note that if the lengths are not the same 108 * the comparison will fail at the first byte. 109 */ 110 if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) 111 continue; 112 if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) 113 continue; 114 if (last != NULL) { 115 struct mbuf *n; 116 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) 117 ; 118 else if (sbappendaddr(&last->so_rcv, src, n, NULL) == 0) 119 /* should notify about lost packet */ 120 m_freem(n); 121 else { 122 sorwakeup(last); 123 } 124 } 125 last = rp->rcb_socket; 126 } 127 if (last == NULL || sbappendaddr(&last->so_rcv, src, m, NULL) == 0) 128 m_freem(m); 129 else { 130 sorwakeup(last); 131 } 132 } 133 134 /*ARGSUSED*/ 135 void * 136 raw_ctlinput(int cmd, const struct sockaddr *arg, void *d) 137 { 138 139 if ((unsigned)cmd >= PRC_NCMDS) 140 return NULL; 141 return NULL; 142 /* INCOMPLETE */ 143 } 144 145 void 146 raw_setsockaddr(struct rawcb *rp, struct mbuf *nam) 147 { 148 149 nam->m_len = rp->rcb_laddr->sa_len; 150 memcpy(mtod(nam, void *), rp->rcb_laddr, (size_t)nam->m_len); 151 } 152 153 void 154 raw_setpeeraddr(struct rawcb *rp, struct mbuf *nam) 155 { 156 157 nam->m_len = rp->rcb_faddr->sa_len; 158 memcpy(mtod(nam, void *), rp->rcb_faddr, (size_t)nam->m_len); 159 } 160 161 /*ARGSUSED*/ 162 int 163 raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 164 struct mbuf *control, struct lwp *l) 165 { 166 struct rawcb *rp; 167 int s; 168 int error = 0; 169 170 if (req == PRU_CONTROL) 171 return (EOPNOTSUPP); 172 173 s = splsoftnet(); 174 KERNEL_LOCK(1, NULL); 175 rp = sotorawcb(so); 176 #ifdef DIAGNOSTIC 177 if (req != PRU_SEND && req != PRU_SENDOOB && control) 178 panic("raw_usrreq: unexpected control mbuf"); 179 #endif 180 if (rp == NULL && req != PRU_ATTACH) { 181 error = EINVAL; 182 goto release; 183 } 184 185 switch (req) { 186 187 /* 188 * Allocate a raw control block and fill in the 189 * necessary info to allow packets to be routed to 190 * the appropriate raw interface routine. 191 */ 192 case PRU_ATTACH: 193 sosetlock(so); 194 if (l == NULL) 195 break; 196 197 /* XXX: raw socket permissions are checked in socreate() */ 198 199 error = raw_attach(so, (int)(long)nam); 200 break; 201 202 /* 203 * Destroy state just before socket deallocation. 204 * Flush data or not depending on the options. 205 */ 206 case PRU_DETACH: 207 raw_detach(rp); 208 break; 209 210 /* 211 * If a socket isn't bound to a single address, 212 * the raw input routine will hand it anything 213 * within that protocol family (assuming there's 214 * nothing else around it should go to). 215 */ 216 case PRU_BIND: 217 case PRU_LISTEN: 218 case PRU_CONNECT: 219 case PRU_CONNECT2: 220 error = EOPNOTSUPP; 221 break; 222 223 case PRU_DISCONNECT: 224 soisdisconnected(so); 225 raw_disconnect(rp); 226 break; 227 228 /* 229 * Mark the connection as being incapable of further input. 230 */ 231 case PRU_SHUTDOWN: 232 socantsendmore(so); 233 break; 234 235 case PRU_RCVD: 236 error = EOPNOTSUPP; 237 break; 238 239 /* 240 * Ship a packet out. The appropriate raw output 241 * routine handles any massaging necessary. 242 */ 243 case PRU_SEND: 244 if (control && control->m_len) { 245 m_freem(control); 246 m_freem(m); 247 error = EINVAL; 248 break; 249 } 250 if (nam) { 251 if ((so->so_state & SS_ISCONNECTED) != 0) { 252 error = EISCONN; 253 goto die; 254 } 255 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 256 NULL, nam, NULL, l); 257 if (error) { 258 die: 259 m_freem(m); 260 break; 261 } 262 } else { 263 if ((so->so_state & SS_ISCONNECTED) == 0) { 264 error = ENOTCONN; 265 goto die; 266 } 267 } 268 error = (*so->so_proto->pr_output)(m, so); 269 if (nam) 270 raw_disconnect(rp); 271 break; 272 273 case PRU_SENSE: 274 /* 275 * stat: don't bother with a blocksize. 276 */ 277 error = 0; 278 break; 279 280 /* 281 * Not supported. 282 */ 283 case PRU_RCVOOB: 284 error = EOPNOTSUPP; 285 break; 286 287 case PRU_SENDOOB: 288 m_freem(control); 289 m_freem(m); 290 error = EOPNOTSUPP; 291 break; 292 293 case PRU_SOCKADDR: 294 if (rp->rcb_laddr == NULL) { 295 error = EINVAL; 296 break; 297 } 298 raw_setsockaddr(rp, nam); 299 break; 300 301 case PRU_PEERADDR: 302 if (rp->rcb_faddr == NULL) { 303 error = ENOTCONN; 304 break; 305 } 306 raw_setpeeraddr(rp, nam); 307 break; 308 309 default: 310 panic("raw_usrreq"); 311 } 312 313 release: 314 KERNEL_UNLOCK_ONE(NULL); 315 splx(s); 316 return (error); 317 } 318