1 /* $NetBSD: raw_usrreq.c,v 1.34 2008/04/24 11:38:37 ad 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.34 2008/04/24 11:38:37 ad 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 #include <machine/stdarg.h> 54 55 /* 56 * Initialize raw connection block q. 57 */ 58 void 59 raw_init(void) 60 { 61 62 LIST_INIT(&rawcb); 63 } 64 65 static inline int 66 equal(const struct sockaddr *a1, const struct sockaddr *a2) 67 { 68 return memcmp(a1, a2, a1->sa_len) == 0; 69 } 70 71 /* 72 * Raw protocol input routine. Find the socket 73 * associated with the packet(s) and move them over. If 74 * nothing exists for this packet, drop it. 75 */ 76 /* 77 * Raw protocol interface. 78 */ 79 void 80 raw_input(struct mbuf *m0, ...) 81 { 82 struct rawcb *rp; 83 struct mbuf *m = m0; 84 int sockets = 0; 85 struct socket *last; 86 va_list ap; 87 struct sockproto *proto; 88 struct sockaddr *src, *dst; 89 90 KASSERT(mutex_owned(softnet_lock)); 91 92 va_start(ap, m0); 93 proto = va_arg(ap, struct sockproto *); 94 src = va_arg(ap, struct sockaddr *); 95 dst = va_arg(ap, struct sockaddr *); 96 va_end(ap); 97 98 last = NULL; 99 LIST_FOREACH(rp, &rawcb, rcb_list) { 100 if (rp->rcb_proto.sp_family != proto->sp_family) 101 continue; 102 if (rp->rcb_proto.sp_protocol && 103 rp->rcb_proto.sp_protocol != proto->sp_protocol) 104 continue; 105 /* 106 * We assume the lower level routines have 107 * placed the address in a canonical format 108 * suitable for a structure comparison. 109 * 110 * Note that if the lengths are not the same 111 * the comparison will fail at the first byte. 112 */ 113 if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) 114 continue; 115 if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) 116 continue; 117 if (last != NULL) { 118 struct mbuf *n; 119 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) 120 ; 121 else if (sbappendaddr(&last->so_rcv, src, n, NULL) == 0) 122 /* should notify about lost packet */ 123 m_freem(n); 124 else { 125 sorwakeup(last); 126 sockets++; 127 } 128 } 129 last = rp->rcb_socket; 130 } 131 if (last == NULL || sbappendaddr(&last->so_rcv, src, m, NULL) == 0) 132 m_freem(m); 133 else { 134 sorwakeup(last); 135 sockets++; 136 } 137 } 138 139 /*ARGSUSED*/ 140 void * 141 raw_ctlinput(int cmd, const struct sockaddr *arg, void *d) 142 { 143 144 if ((unsigned)cmd >= PRC_NCMDS) 145 return NULL; 146 return NULL; 147 /* INCOMPLETE */ 148 } 149 150 void 151 raw_setsockaddr(struct rawcb *rp, struct mbuf *nam) 152 { 153 154 nam->m_len = rp->rcb_laddr->sa_len; 155 memcpy(mtod(nam, void *), rp->rcb_laddr, (size_t)nam->m_len); 156 } 157 158 void 159 raw_setpeeraddr(struct rawcb *rp, struct mbuf *nam) 160 { 161 162 nam->m_len = rp->rcb_faddr->sa_len; 163 memcpy(mtod(nam, void *), rp->rcb_faddr, (size_t)nam->m_len); 164 } 165 166 /*ARGSUSED*/ 167 int 168 raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 169 struct mbuf *control, struct lwp *l) 170 { 171 struct rawcb *rp; 172 int s; 173 int error = 0; 174 175 if (req == PRU_CONTROL) 176 return (EOPNOTSUPP); 177 178 s = splsoftnet(); 179 KERNEL_LOCK(1, NULL); 180 rp = sotorawcb(so); 181 #ifdef DIAGNOSTIC 182 if (req != PRU_SEND && req != PRU_SENDOOB && control) 183 panic("raw_usrreq: unexpected control mbuf"); 184 #endif 185 if (rp == NULL && req != PRU_ATTACH) { 186 error = EINVAL; 187 goto release; 188 } 189 190 switch (req) { 191 192 /* 193 * Allocate a raw control block and fill in the 194 * necessary info to allow packets to be routed to 195 * the appropriate raw interface routine. 196 */ 197 case PRU_ATTACH: 198 sosetlock(so); 199 if (l == NULL) 200 break; 201 202 /* XXX: raw socket permissions are checked in socreate() */ 203 204 error = raw_attach(so, (int)(long)nam); 205 break; 206 207 /* 208 * Destroy state just before socket deallocation. 209 * Flush data or not depending on the options. 210 */ 211 case PRU_DETACH: 212 raw_detach(rp); 213 break; 214 215 /* 216 * If a socket isn't bound to a single address, 217 * the raw input routine will hand it anything 218 * within that protocol family (assuming there's 219 * nothing else around it should go to). 220 */ 221 case PRU_BIND: 222 case PRU_LISTEN: 223 case PRU_CONNECT: 224 case PRU_CONNECT2: 225 error = EOPNOTSUPP; 226 break; 227 228 case PRU_DISCONNECT: 229 soisdisconnected(so); 230 raw_disconnect(rp); 231 break; 232 233 /* 234 * Mark the connection as being incapable of further input. 235 */ 236 case PRU_SHUTDOWN: 237 socantsendmore(so); 238 break; 239 240 case PRU_RCVD: 241 error = EOPNOTSUPP; 242 break; 243 244 /* 245 * Ship a packet out. The appropriate raw output 246 * routine handles any massaging necessary. 247 */ 248 case PRU_SEND: 249 if (control && control->m_len) { 250 m_freem(control); 251 m_freem(m); 252 error = EINVAL; 253 break; 254 } 255 if (nam) { 256 if ((so->so_state & SS_ISCONNECTED) != 0) { 257 error = EISCONN; 258 goto die; 259 } 260 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 261 NULL, nam, NULL, l); 262 if (error) { 263 die: 264 m_freem(m); 265 break; 266 } 267 } else { 268 if ((so->so_state & SS_ISCONNECTED) == 0) { 269 error = ENOTCONN; 270 goto die; 271 } 272 } 273 error = (*so->so_proto->pr_output)(m, so); 274 if (nam) 275 raw_disconnect(rp); 276 break; 277 278 case PRU_SENSE: 279 /* 280 * stat: don't bother with a blocksize. 281 */ 282 return (0); 283 284 /* 285 * Not supported. 286 */ 287 case PRU_RCVOOB: 288 error = EOPNOTSUPP; 289 break; 290 291 case PRU_SENDOOB: 292 m_freem(control); 293 m_freem(m); 294 error = EOPNOTSUPP; 295 break; 296 297 case PRU_SOCKADDR: 298 if (rp->rcb_laddr == NULL) { 299 error = EINVAL; 300 break; 301 } 302 raw_setsockaddr(rp, nam); 303 break; 304 305 case PRU_PEERADDR: 306 if (rp->rcb_faddr == NULL) { 307 error = ENOTCONN; 308 break; 309 } 310 raw_setpeeraddr(rp, nam); 311 break; 312 313 default: 314 panic("raw_usrreq"); 315 } 316 317 release: 318 KERNEL_UNLOCK_ONE(NULL); 319 splx(s); 320 return (error); 321 } 322