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 * 3. 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: src/sys/net/raw_usrreq.c,v 1.18 1999/08/28 00:48:28 peter Exp $ 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/mbuf.h> 36 #include <sys/proc.h> 37 #include <sys/priv.h> 38 #include <sys/protosw.h> 39 #include <sys/socket.h> 40 #include <sys/socketvar.h> 41 42 #include <sys/socketvar2.h> 43 #include <sys/msgport2.h> 44 45 #include <net/raw_cb.h> 46 #include <net/netisr2.h> 47 48 /* 49 * Except from the raw_init(), rest of interfaces must be called 50 * from netisr0. 51 */ 52 53 /* 54 * Initialize raw connection block q. 55 */ 56 void 57 raw_init(void) 58 { 59 LIST_INIT(&rawcb_list); 60 } 61 62 /************************************************************************ 63 * RAW PROTOCOL INTERFACE * 64 ************************************************************************/ 65 66 /* 67 * Raw protocol input routine. Find the socket associated with the packet(s) 68 * and move them over. If nothing exists for this packet, drop it. This 69 * routine is indirect called via rts_input() and will be serialized on 70 * cpu 0. 71 * 72 * Most other raw protocol interface functions are also serialized XXX. 73 */ 74 void 75 raw_input(struct mbuf *m0, const struct sockproto *proto, 76 const struct sockaddr *src, const struct sockaddr *dst, 77 const struct rawcb *skip) 78 { 79 struct rawcb *rp; 80 struct mbuf *m = m0; 81 struct socket *last; 82 83 ASSERT_NETISR0; 84 85 last = NULL; 86 87 LIST_FOREACH(rp, &rawcb_list, list) { 88 if (rp == skip) 89 continue; 90 if (rp->rcb_proto.sp_family != proto->sp_family) 91 continue; 92 if (rp->rcb_proto.sp_protocol && 93 rp->rcb_proto.sp_protocol != proto->sp_protocol) 94 continue; 95 /* 96 * We assume the lower level routines have 97 * placed the address in a canonical format 98 * suitable for a structure comparison. 99 * 100 * Note that if the lengths are not the same 101 * the comparison will fail at the first byte. 102 */ 103 if (rp->rcb_laddr && !sa_equal(rp->rcb_laddr, dst)) 104 continue; 105 if (rp->rcb_faddr && !sa_equal(rp->rcb_faddr, src)) 106 continue; 107 /* Run any filtering that may have been installed. */ 108 if (rp->rcb_filter != NULL && rp->rcb_filter(m, proto, rp) != 0) 109 continue; 110 if (last) { 111 struct mbuf *n; 112 113 n = m_copypacket(m, M_NOWAIT); 114 if (n != NULL) { 115 lwkt_gettoken(&last->so_rcv.ssb_token); 116 if (ssb_appendaddr(&last->so_rcv, src, n, 117 NULL) == 0) { 118 m_freem(n); 119 soroverflow(last); 120 } else { 121 sorwakeup(last); 122 } 123 lwkt_reltoken(&last->so_rcv.ssb_token); 124 } 125 } 126 last = rp->rcb_socket; 127 } 128 if (last) { 129 lwkt_gettoken(&last->so_rcv.ssb_token); 130 if (ssb_appendaddr(&last->so_rcv, src, m, NULL) == 0) { 131 m_freem(m); 132 soroverflow(last); 133 } else 134 sorwakeup(last); 135 lwkt_reltoken(&last->so_rcv.ssb_token); 136 } else { 137 m_freem(m); 138 } 139 } 140 141 /* 142 * nm_cmd, nm_arg, nm_extra 143 */ 144 void 145 raw_ctlinput(netmsg_t msg) 146 { 147 int error = 0; 148 149 ASSERT_NETISR0; 150 151 if (msg->ctlinput.nm_cmd < 0 || msg->ctlinput.nm_cmd > PRC_NCMDS) { 152 ; /* no-op */ 153 } 154 lwkt_replymsg(&msg->lmsg, error); 155 } 156 157 /* 158 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 159 * will sofree() it when we return. 160 */ 161 static void 162 raw_uabort(netmsg_t msg) 163 { 164 struct rawcb *rp = sotorawcb(msg->base.nm_so); 165 int error; 166 167 ASSERT_NETISR0; 168 169 if (rp) { 170 raw_disconnect(rp); 171 soisdisconnected(msg->base.nm_so); 172 error = 0; 173 } else { 174 error = EINVAL; 175 } 176 lwkt_replymsg(&msg->lmsg, error); 177 } 178 179 /* pru_accept is EOPNOTSUPP */ 180 181 static void 182 raw_uattach(netmsg_t msg) 183 { 184 struct socket *so = msg->base.nm_so; 185 int proto = msg->attach.nm_proto; 186 struct pru_attach_info *ai = msg->attach.nm_ai; 187 struct rawcb *rp; 188 int error; 189 190 ASSERT_NETISR0; 191 192 rp = sotorawcb(so); 193 if (rp) { 194 error = priv_check_cred(ai->p_ucred, PRIV_ROOT, NULL_CRED_OKAY); 195 if (error == 0) 196 error = raw_attach(so, proto, ai->sb_rlimit); 197 } else { 198 error = EINVAL; 199 } 200 lwkt_replymsg(&msg->lmsg, error); 201 } 202 203 static void 204 raw_ubind(netmsg_t msg) 205 { 206 ASSERT_NETISR0; 207 lwkt_replymsg(&msg->lmsg, EINVAL); 208 } 209 210 static void 211 raw_uconnect(netmsg_t msg) 212 { 213 ASSERT_NETISR0; 214 lwkt_replymsg(&msg->lmsg, EINVAL); 215 } 216 217 /* pru_connect2 is EOPNOTSUPP */ 218 /* pru_control is EOPNOTSUPP */ 219 220 static void 221 raw_udetach(netmsg_t msg) 222 { 223 struct rawcb *rp = sotorawcb(msg->base.nm_so); 224 int error; 225 226 ASSERT_NETISR0; 227 228 if (rp) { 229 raw_detach(rp); 230 error = 0; 231 } else { 232 error = EINVAL; 233 } 234 lwkt_replymsg(&msg->lmsg, error); 235 } 236 237 static void 238 raw_udisconnect(netmsg_t msg) 239 { 240 struct socket *so = msg->base.nm_so; 241 struct rawcb *rp; 242 int error; 243 244 ASSERT_NETISR0; 245 246 rp = sotorawcb(so); 247 if (rp == NULL) { 248 error = EINVAL; 249 } else if (rp->rcb_faddr == NULL) { 250 error = ENOTCONN; 251 } else { 252 soreference(so); 253 raw_disconnect(rp); 254 soisdisconnected(so); 255 sofree(so); 256 error = 0; 257 } 258 lwkt_replymsg(&msg->lmsg, error); 259 } 260 261 /* pru_listen is EOPNOTSUPP */ 262 263 static void 264 raw_upeeraddr(netmsg_t msg) 265 { 266 struct rawcb *rp = sotorawcb(msg->base.nm_so); 267 int error; 268 269 ASSERT_NETISR0; 270 271 if (rp == NULL) { 272 error = EINVAL; 273 } else if (rp->rcb_faddr == NULL) { 274 error = ENOTCONN; 275 } else { 276 *msg->peeraddr.nm_nam = dup_sockaddr(rp->rcb_faddr); 277 error = 0; 278 } 279 lwkt_replymsg(&msg->lmsg, error); 280 } 281 282 /* pru_rcvd is EOPNOTSUPP */ 283 /* pru_rcvoob is EOPNOTSUPP */ 284 285 static void 286 raw_usend(netmsg_t msg) 287 { 288 struct socket *so = msg->base.nm_so; 289 struct mbuf *m = msg->send.nm_m; 290 struct mbuf *control = msg->send.nm_control; 291 struct rawcb *rp = sotorawcb(so); 292 struct pr_output_info oi; 293 int flags = msg->send.nm_flags; 294 int error; 295 296 ASSERT_NETISR0; 297 298 if (rp == NULL) { 299 error = EINVAL; 300 goto release; 301 } 302 303 if (flags & PRUS_OOB) { 304 error = EOPNOTSUPP; 305 goto release; 306 } 307 308 if (control && control->m_len) { 309 error = EOPNOTSUPP; 310 goto release; 311 } 312 if (msg->send.nm_addr) { 313 if (rp->rcb_faddr) { 314 error = EISCONN; 315 goto release; 316 } 317 rp->rcb_faddr = msg->send.nm_addr; 318 } else if (rp->rcb_faddr == NULL) { 319 error = ENOTCONN; 320 goto release; 321 } 322 oi.p_pid = msg->send.nm_td->td_proc->p_pid; 323 error = (*so->so_proto->pr_output)(m, so, &oi); 324 m = NULL; 325 if (msg->send.nm_addr) 326 rp->rcb_faddr = NULL; 327 release: 328 if (m != NULL) 329 m_freem(m); 330 lwkt_replymsg(&msg->lmsg, error); 331 } 332 333 /* pru_sense is null */ 334 335 static void 336 raw_ushutdown(netmsg_t msg) 337 { 338 struct rawcb *rp = sotorawcb(msg->base.nm_so); 339 int error; 340 341 ASSERT_NETISR0; 342 343 if (rp) { 344 socantsendmore(msg->base.nm_so); 345 error = 0; 346 } else { 347 error = EINVAL; 348 } 349 lwkt_replymsg(&msg->lmsg, error); 350 } 351 352 static void 353 raw_usockaddr(netmsg_t msg) 354 { 355 struct rawcb *rp = sotorawcb(msg->base.nm_so); 356 int error; 357 358 ASSERT_NETISR0; 359 360 if (rp == NULL) { 361 error = EINVAL; 362 } else if (rp->rcb_laddr == NULL) { 363 error = EINVAL; 364 } else { 365 *msg->sockaddr.nm_nam = dup_sockaddr(rp->rcb_laddr); 366 error = 0; 367 } 368 lwkt_replymsg(&msg->lmsg, error); 369 } 370 371 struct pr_usrreqs raw_usrreqs = { 372 .pru_abort = raw_uabort, 373 .pru_accept = pr_generic_notsupp, 374 .pru_attach = raw_uattach, 375 .pru_bind = raw_ubind, 376 .pru_connect = raw_uconnect, 377 .pru_connect2 = pr_generic_notsupp, 378 .pru_control = pr_generic_notsupp, 379 .pru_detach = raw_udetach, 380 .pru_disconnect = raw_udisconnect, 381 .pru_listen = pr_generic_notsupp, 382 .pru_peeraddr = raw_upeeraddr, 383 .pru_rcvd = pr_generic_notsupp, 384 .pru_rcvoob = pr_generic_notsupp, 385 .pru_send = raw_usend, 386 .pru_sense = pru_sense_null, 387 .pru_shutdown = raw_ushutdown, 388 .pru_sockaddr = raw_usockaddr, 389 .pru_sosend = sosend, 390 .pru_soreceive = soreceive 391 }; 392