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