1 /* $NetBSD: raw_usrreq.c,v 1.33 2007/05/06 06:21:26 dyoung 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.33 2007/05/06 06:21:26 dyoung 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 * Initialize raw connection block q. 56 */ 57 void 58 raw_init(void) 59 { 60 61 LIST_INIT(&rawcb); 62 } 63 64 static inline int 65 equal(const struct sockaddr *a1, const struct sockaddr *a2) 66 { 67 return memcmp(a1, a2, a1->sa_len) == 0; 68 } 69 70 /* 71 * Raw protocol input routine. Find the socket 72 * associated with the packet(s) and move them over. If 73 * nothing exists for this packet, drop it. 74 */ 75 /* 76 * Raw protocol interface. 77 */ 78 void 79 raw_input(struct mbuf *m0, ...) 80 { 81 struct rawcb *rp; 82 struct mbuf *m = m0; 83 int sockets = 0; 84 struct socket *last; 85 va_list ap; 86 struct sockproto *proto; 87 struct sockaddr *src, *dst; 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 sockets++; 124 } 125 } 126 last = rp->rcb_socket; 127 } 128 if (last == NULL || sbappendaddr(&last->so_rcv, src, m, NULL) == 0) 129 m_freem(m); 130 else { 131 sorwakeup(last); 132 sockets++; 133 } 134 } 135 136 /*ARGSUSED*/ 137 void * 138 raw_ctlinput(int cmd, const struct sockaddr *arg, void *d) 139 { 140 141 if ((unsigned)cmd >= PRC_NCMDS) 142 return NULL; 143 return NULL; 144 /* INCOMPLETE */ 145 } 146 147 void 148 raw_setsockaddr(struct rawcb *rp, struct mbuf *nam) 149 { 150 151 nam->m_len = rp->rcb_laddr->sa_len; 152 memcpy(mtod(nam, void *), rp->rcb_laddr, (size_t)nam->m_len); 153 } 154 155 void 156 raw_setpeeraddr(struct rawcb *rp, struct mbuf *nam) 157 { 158 159 nam->m_len = rp->rcb_faddr->sa_len; 160 memcpy(mtod(nam, void *), rp->rcb_faddr, (size_t)nam->m_len); 161 } 162 163 /*ARGSUSED*/ 164 int 165 raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 166 struct mbuf *control, struct lwp *l) 167 { 168 struct rawcb *rp; 169 int s; 170 int error = 0; 171 172 if (req == PRU_CONTROL) 173 return (EOPNOTSUPP); 174 175 s = splsoftnet(); 176 rp = sotorawcb(so); 177 #ifdef DIAGNOSTIC 178 if (req != PRU_SEND && req != PRU_SENDOOB && control) 179 panic("raw_usrreq: unexpected control mbuf"); 180 #endif 181 if (rp == NULL && req != PRU_ATTACH) { 182 error = EINVAL; 183 goto release; 184 } 185 186 switch (req) { 187 188 /* 189 * Allocate a raw control block and fill in the 190 * necessary info to allow packets to be routed to 191 * the appropriate raw interface routine. 192 */ 193 case PRU_ATTACH: 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 return (0); 278 279 /* 280 * Not supported. 281 */ 282 case PRU_RCVOOB: 283 error = EOPNOTSUPP; 284 break; 285 286 case PRU_SENDOOB: 287 m_freem(control); 288 m_freem(m); 289 error = EOPNOTSUPP; 290 break; 291 292 case PRU_SOCKADDR: 293 if (rp->rcb_laddr == NULL) { 294 error = EINVAL; 295 break; 296 } 297 raw_setsockaddr(rp, nam); 298 break; 299 300 case PRU_PEERADDR: 301 if (rp->rcb_faddr == NULL) { 302 error = ENOTCONN; 303 break; 304 } 305 raw_setpeeraddr(rp, nam); 306 break; 307 308 default: 309 panic("raw_usrreq"); 310 } 311 312 release: 313 splx(s); 314 return (error); 315 } 316