1 /* raw_usrreq.c 4.8 82/03/05 */ 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/mtpr.h" 9 #include "../net/in.h" 10 #include "../net/in_systm.h" 11 #include "../net/if.h" 12 #include "../net/raw_cb.h" 13 #include "../errno.h" 14 15 /* 16 * Initialize raw connection block q. 17 */ 18 raw_init() 19 { 20 COUNT(RAW_INIT); 21 rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 22 } 23 24 /* 25 * Raw protocol interface. 26 */ 27 raw_input(m0, pf, daf, saf) 28 struct mbuf *m0; 29 struct sockproto *pf; 30 struct sockaddr *daf, *saf; 31 { 32 register struct mbuf *m; 33 struct raw_header *rh; 34 int s; 35 36 COUNT(RAW_INPUT); 37 /* 38 * Rip off an mbuf for a generic header. 39 */ 40 m = m_get(M_DONTWAIT); 41 if (m == 0) { 42 m_freem(m0); 43 return; 44 } 45 m->m_next = m0; 46 m->m_off = MMINOFF; 47 m->m_len = sizeof(struct raw_header); 48 rh = mtod(m, struct raw_header *); 49 rh->raw_dst = *daf; 50 rh->raw_src = *saf; 51 rh->raw_protocol = *pf; 52 53 /* 54 * Header now contains enough info to decide 55 * which socket to place packet in (if any). 56 * Queue it up for the raw protocol process 57 * running at software interrupt level. 58 */ 59 s = splimp(); 60 IF_ENQUEUE(&rawintrq, m); 61 splx(s); 62 setrawintr(); 63 } 64 65 /* 66 * Raw protocol input routine. Process packets entered 67 * into the queue at interrupt time. Find the socket 68 * associated with the packet(s) and move them over. If 69 * nothing exists for this packet, drop it. 70 */ 71 rawintr() 72 { 73 int s; 74 struct mbuf *m; 75 register struct rawcb *rp; 76 register struct socket *so; 77 register struct protosw *pr; 78 register struct sockproto *sp; 79 register struct sockaddr *sa; 80 struct raw_header *rawp; 81 struct socket *last; 82 83 COUNT(RAWINTR); 84 next: 85 s = splimp(); 86 IF_DEQUEUE(&rawintrq, m); 87 splx(s); 88 if (m == 0) 89 return; 90 rawp = mtod(m, struct raw_header *); 91 sp = &rawp->raw_protocol; 92 sa = &rawp->raw_dst; 93 94 /* 95 * Find the appropriate socket(s) in which to place this 96 * packet. This is done by matching the protocol and 97 * address information prepended by raw_input against 98 * the info stored in the control block structures. 99 */ 100 last = 0; 101 for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 102 so = rp->rcb_socket; 103 pr = so->so_proto; 104 if (pr->pr_family != sp->sp_family || 105 (pr->pr_protocol && pr->pr_protocol != sp->sp_protocol)) 106 continue; 107 if (so->so_addr.sa_family && 108 sa->sa_family != so->so_addr.sa_family) 109 continue; 110 /* 111 * We assume the lower level routines have 112 * placed the address in a canonical format 113 * suitable for a structure comparison. Packets 114 * are duplicated for each receiving socket. 115 * 116 * SHOULD HAVE A NUMBER OF MECHANISMS FOR 117 * MATCHING BASED ON rcb_flags 118 */ 119 if ((rp->rcb_flags & RAW_ADDR) && 120 bcmp(sa->sa_data, so->so_addr.sa_data, 14) != 0) 121 continue; 122 /* 123 * To avoid extraneous packet copies, we keep 124 * track of the last socket the packet should be 125 * placed in, and make copies only after finding a 126 * socket which "collides". 127 */ 128 if (last) { 129 struct mbuf *n; 130 131 if (n = m_copy(m->m_next, 0, M_COPYALL)) 132 goto nospace; 133 if (sbappendaddr(&last->so_rcv, &rawp->raw_src, n) == 0) { 134 /* 135 * Should drop notification of lost packet 136 * into this guy's queue, but... 137 */ 138 m_freem(n); 139 goto nospace; 140 } 141 sorwakeup(last); 142 } 143 nospace: 144 last = so; 145 } 146 if (last == 0) 147 goto drop; 148 if (sbappendaddr(&last->so_rcv, &rawp->raw_src, m->m_next) == 0) 149 { 150 printf("rawintr: sbappendaddr failed\n"); 151 goto drop; 152 } 153 (void) m_free(m); /* generic header */ 154 sorwakeup(last); 155 goto next; 156 drop: 157 m_freem(m); 158 goto next; 159 } 160 161 /*ARGSUSED*/ 162 raw_usrreq(so, req, m, addr) 163 struct socket *so; 164 int req; 165 struct mbuf *m; 166 caddr_t addr; 167 { 168 register struct rawcb *rp = sotorawcb(so); 169 int error = 0; 170 171 COUNT(RAW_USRREQ); 172 if (rp == 0 && req != PRU_ATTACH) 173 return (EINVAL); 174 175 switch (req) { 176 177 /* 178 * Allocate a raw control block and fill in the 179 * necessary info to allow packets to be routed to 180 * the appropriate raw interface routine. 181 */ 182 case PRU_ATTACH: 183 if (rp) 184 return (EINVAL);; 185 error = raw_attach(so, (struct sockaddr *)addr); 186 break; 187 188 /* 189 * Destroy state just before socket deallocation. 190 * Flush data or not depending on the options. 191 */ 192 case PRU_DETACH: 193 if (rp == 0) 194 return (ENOTCONN); 195 raw_detach(rp); 196 break; 197 198 /* 199 * If a socket isn't bound to a single address, 200 * the raw input routine will hand it anything 201 * within that protocol family (assuming there's 202 * nothing else around it should go to). 203 */ 204 case PRU_CONNECT: 205 if (rp->rcb_flags & RAW_ADDR) 206 return (EISCONN); 207 raw_connaddr(rp, (struct sockaddr *)addr); 208 soisconnected(so); 209 break; 210 211 case PRU_DISCONNECT: 212 if ((rp->rcb_flags & RAW_ADDR) == 0) 213 return (ENOTCONN); 214 raw_disconnect(rp); 215 soisdisconnected(so); 216 break; 217 218 /* 219 * Mark the connection as being incapable of further input. 220 */ 221 case PRU_SHUTDOWN: 222 socantsendmore(so); 223 break; 224 225 /* 226 * Ship a packet out. The appropriate raw output 227 * routine handles any massaging necessary. 228 */ 229 case PRU_SEND: 230 if (addr) { 231 if (rp->rcb_flags & RAW_ADDR) 232 return (EISCONN); 233 raw_connaddr(rp, (struct sockaddr *)addr); 234 } else if ((rp->rcb_flags & RAW_ADDR) == 0) 235 return (ENOTCONN); 236 (void) (*so->so_proto->pr_output)(m, so); 237 if (addr) 238 rp->rcb_flags &= ~RAW_ADDR; 239 break; 240 241 case PRU_ABORT: 242 raw_disconnect(rp); 243 sofree(so); 244 soisdisconnected(so); 245 break; 246 247 /* 248 * Not supported. 249 */ 250 case PRU_ACCEPT: 251 case PRU_RCVD: 252 case PRU_CONTROL: 253 case PRU_SENSE: 254 case PRU_RCVOOB: 255 case PRU_SENDOOB: 256 error = EOPNOTSUPP; 257 break; 258 259 default: 260 panic("raw_usrreq"); 261 } 262 return (error); 263 } 264