1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)raw_usrreq.c 6.8 (Berkeley) 06/08/85 7 */ 8 9 #include "param.h" 10 #include "mbuf.h" 11 #include "domain.h" 12 #include "protosw.h" 13 #include "socket.h" 14 #include "socketvar.h" 15 #include "errno.h" 16 17 #include "if.h" 18 #include "route.h" 19 #include "netisr.h" 20 #include "raw_cb.h" 21 22 #include "../vax/mtpr.h" 23 24 /* 25 * Initialize raw connection block q. 26 */ 27 raw_init() 28 { 29 30 rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 31 rawintrq.ifq_maxlen = IFQ_MAXLEN; 32 } 33 34 /* 35 * Raw protocol interface. 36 */ 37 raw_input(m0, proto, src, dst) 38 struct mbuf *m0; 39 struct sockproto *proto; 40 struct sockaddr *src, *dst; 41 { 42 register struct mbuf *m; 43 struct raw_header *rh; 44 int s; 45 46 /* 47 * Rip off an mbuf for a generic header. 48 */ 49 m = m_get(M_DONTWAIT, MT_HEADER); 50 if (m == 0) { 51 m_freem(m0); 52 return; 53 } 54 m->m_next = m0; 55 m->m_len = sizeof(struct raw_header); 56 rh = mtod(m, struct raw_header *); 57 rh->raw_dst = *dst; 58 rh->raw_src = *src; 59 rh->raw_proto = *proto; 60 61 /* 62 * Header now contains enough info to decide 63 * which socket to place packet in (if any). 64 * Queue it up for the raw protocol process 65 * running at software interrupt level. 66 */ 67 s = splimp(); 68 if (IF_QFULL(&rawintrq)) 69 m_freem(m); 70 else 71 IF_ENQUEUE(&rawintrq, m); 72 splx(s); 73 schednetisr(NETISR_RAW); 74 } 75 76 /* 77 * Raw protocol input routine. Process packets entered 78 * into the queue at interrupt time. Find the socket 79 * associated with the packet(s) and move them over. If 80 * nothing exists for this packet, drop it. 81 */ 82 rawintr() 83 { 84 int s; 85 struct mbuf *m; 86 register struct rawcb *rp; 87 register struct raw_header *rh; 88 struct socket *last; 89 90 next: 91 s = splimp(); 92 IF_DEQUEUE(&rawintrq, m); 93 splx(s); 94 if (m == 0) 95 return; 96 rh = mtod(m, struct raw_header *); 97 last = 0; 98 for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 99 if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family) 100 continue; 101 if (rp->rcb_proto.sp_protocol && 102 rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol) 103 continue; 104 /* 105 * We assume the lower level routines have 106 * placed the address in a canonical format 107 * suitable for a structure comparison. 108 */ 109 #define equal(a1, a2) \ 110 (bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0) 111 if ((rp->rcb_flags & RAW_LADDR) && 112 !equal(rp->rcb_laddr, rh->raw_dst)) 113 continue; 114 if ((rp->rcb_flags & RAW_FADDR) && 115 !equal(rp->rcb_faddr, rh->raw_src)) 116 continue; 117 if (last) { 118 struct mbuf *n; 119 if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) { 120 if (sbappendaddr(&last->so_rcv, &rh->raw_src, 121 n, (struct mbuf *)0) == 0) 122 /* should notify about lost packet */ 123 m_freem(n); 124 else 125 sorwakeup(last); 126 } 127 } 128 last = rp->rcb_socket; 129 } 130 if (last) { 131 if (sbappendaddr(&last->so_rcv, &rh->raw_src, 132 m->m_next, (struct mbuf *)0) == 0) 133 m_freem(m->m_next); 134 else 135 sorwakeup(last); 136 (void) m_free(m); /* header */ 137 } else 138 m_freem(m); 139 goto next; 140 } 141 142 /*ARGSUSED*/ 143 raw_ctlinput(cmd, arg) 144 int cmd; 145 caddr_t arg; 146 { 147 148 if (cmd < 0 || cmd > PRC_NCMDS) 149 return; 150 /* INCOMPLETE */ 151 } 152 153 /*ARGSUSED*/ 154 raw_usrreq(so, req, m, nam, rights) 155 struct socket *so; 156 int req; 157 struct mbuf *m, *nam, *rights; 158 { 159 register struct rawcb *rp = sotorawcb(so); 160 register int error = 0; 161 162 if (rights && rights->m_len) { 163 error = EOPNOTSUPP; 164 goto release; 165 } 166 if (rp == 0 && req != PRU_ATTACH) { 167 error = EINVAL; 168 goto release; 169 } 170 switch (req) { 171 172 /* 173 * Allocate a raw control block and fill in the 174 * necessary info to allow packets to be routed to 175 * the appropriate raw interface routine. 176 */ 177 case PRU_ATTACH: 178 if ((so->so_state & SS_PRIV) == 0) { 179 error = EACCES; 180 break; 181 } 182 if (rp) { 183 error = EINVAL; 184 break; 185 } 186 error = raw_attach(so, (int)nam); 187 break; 188 189 /* 190 * Destroy state just before socket deallocation. 191 * Flush data or not depending on the options. 192 */ 193 case PRU_DETACH: 194 if (rp == 0) { 195 error = ENOTCONN; 196 break; 197 } 198 raw_detach(rp); 199 break; 200 201 /* 202 * If a socket isn't bound to a single address, 203 * the raw input routine will hand it anything 204 * within that protocol family (assuming there's 205 * nothing else around it should go to). 206 */ 207 case PRU_CONNECT: 208 if (rp->rcb_flags & RAW_FADDR) { 209 error = EISCONN; 210 break; 211 } 212 raw_connaddr(rp, nam); 213 soisconnected(so); 214 break; 215 216 case PRU_CONNECT2: 217 error = EOPNOTSUPP; 218 goto release; 219 220 case PRU_BIND: 221 if (rp->rcb_flags & RAW_LADDR) { 222 error = EINVAL; /* XXX */ 223 break; 224 } 225 error = raw_bind(so, nam); 226 break; 227 228 case PRU_DISCONNECT: 229 if ((rp->rcb_flags & RAW_FADDR) == 0) { 230 error = ENOTCONN; 231 break; 232 } 233 if (rp->rcb_route.ro_rt) 234 rtfree(rp->rcb_route.ro_rt); 235 raw_disconnect(rp); 236 soisdisconnected(so); 237 break; 238 239 /* 240 * Mark the connection as being incapable of further input. 241 */ 242 case PRU_SHUTDOWN: 243 socantsendmore(so); 244 break; 245 246 /* 247 * Ship a packet out. The appropriate raw output 248 * routine handles any massaging necessary. 249 */ 250 case PRU_SEND: 251 if (nam) { 252 if (rp->rcb_flags & RAW_FADDR) { 253 error = EISCONN; 254 break; 255 } 256 raw_connaddr(rp, nam); 257 } else if ((rp->rcb_flags & RAW_FADDR) == 0) { 258 error = ENOTCONN; 259 break; 260 } 261 /* 262 * Check for routing. If new foreign address, or 263 * no route presently in use, try to allocate new 264 * route. On failure, just hand packet to output 265 * routine anyway in case it can handle it. 266 */ 267 if ((rp->rcb_flags & RAW_DONTROUTE) == 0) 268 if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) || 269 rp->rcb_route.ro_rt == 0) { 270 if (rp->rcb_route.ro_rt) { 271 RTFREE(rp->rcb_route.ro_rt); 272 rp->rcb_route.ro_rt = NULL; 273 } 274 rp->rcb_route.ro_dst = rp->rcb_faddr; 275 rtalloc(&rp->rcb_route); 276 } 277 error = (*so->so_proto->pr_output)(m, so); 278 m = NULL; 279 if (nam) 280 rp->rcb_flags &= ~RAW_FADDR; 281 break; 282 283 case PRU_ABORT: 284 raw_disconnect(rp); 285 sofree(so); 286 soisdisconnected(so); 287 break; 288 289 case PRU_SENSE: 290 /* 291 * stat: don't bother with a blocksize. 292 */ 293 return (0); 294 295 /* 296 * Not supported. 297 */ 298 case PRU_CONTROL: 299 case PRU_RCVOOB: 300 case PRU_RCVD: 301 return(EOPNOTSUPP); 302 303 case PRU_ACCEPT: 304 case PRU_SENDOOB: 305 error = EOPNOTSUPP; 306 break; 307 308 case PRU_SOCKADDR: 309 bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t), 310 sizeof (struct sockaddr)); 311 nam->m_len = sizeof (struct sockaddr); 312 break; 313 314 case PRU_PEERADDR: 315 bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t), 316 sizeof (struct sockaddr)); 317 nam->m_len = sizeof (struct sockaddr); 318 break; 319 320 default: 321 panic("raw_usrreq"); 322 } 323 release: 324 if (m != NULL) 325 m_freem(m); 326 return (error); 327 } 328