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