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