1 /* udp_usrreq.c 4.34 82/10/16 */ 2 3 #include "../h/param.h" 4 #include "../h/dir.h" 5 #include "../h/user.h" 6 #include "../h/mbuf.h" 7 #include "../h/protosw.h" 8 #include "../h/socket.h" 9 #include "../h/socketvar.h" 10 #include "../netinet/in.h" 11 #include "../net/if.h" 12 #include "../net/route.h" 13 #include "../netinet/in_pcb.h" 14 #include "../netinet/in_systm.h" 15 #include "../netinet/ip.h" 16 #include "../netinet/ip_var.h" 17 #include "../netinet/ip_icmp.h" 18 #include "../netinet/udp.h" 19 #include "../netinet/udp_var.h" 20 #include <errno.h> 21 22 /* 23 * UDP protocol implementation. 24 * Per RFC 768, August, 1980. 25 */ 26 udp_init() 27 { 28 29 udb.inp_next = udb.inp_prev = &udb; 30 } 31 32 int udpcksum; 33 struct sockaddr_in udp_in = { AF_INET }; 34 35 udp_input(m0) 36 struct mbuf *m0; 37 { 38 register struct udpiphdr *ui; 39 register struct inpcb *inp; 40 register struct mbuf *m; 41 int len; 42 43 /* 44 * Get IP and UDP header together in first mbuf. 45 */ 46 m = m0; 47 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 48 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 49 udpstat.udps_hdrops++; 50 return; 51 } 52 ui = mtod(m, struct udpiphdr *); 53 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 54 ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 55 56 /* 57 * Make mbuf data length reflect UDP length. 58 * If not enough data to reflect UDP length, drop. 59 */ 60 len = ntohs((u_short)ui->ui_ulen); 61 if (((struct ip *)ui)->ip_len != len) { 62 if (len > ((struct ip *)ui)->ip_len) { 63 udpstat.udps_badlen++; 64 goto bad; 65 } 66 m_adj(m, ((struct ip *)ui)->ip_len - len); 67 /* (struct ip *)ui->ip_len = len; */ 68 } 69 70 /* 71 * Checksum extended UDP header and data. 72 */ 73 if (udpcksum) { 74 ui->ui_next = ui->ui_prev = 0; 75 ui->ui_x1 = 0; 76 ui->ui_len = htons((u_short)len); 77 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 78 udpstat.udps_badsum++; 79 printf("udp cksum %x\n", ui->ui_sum); 80 m_freem(m); 81 return; 82 } 83 } 84 85 /* 86 * Locate pcb for datagram. 87 */ 88 inp = in_pcblookup(&udb, 89 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 90 INPLOOKUP_WILDCARD); 91 if (inp == 0) { 92 struct in_addr broadcastaddr; 93 94 broadcastaddr = if_makeaddr(ui->ui_dst.s_net, INADDR_ANY); 95 if (ui->ui_dst.s_addr == broadcastaddr.s_addr) 96 goto bad; 97 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 98 return; 99 } 100 101 /* 102 * Construct sockaddr format source address. 103 * Stuff source address and datagram in user buffer. 104 */ 105 udp_in.sin_port = ui->ui_sport; 106 udp_in.sin_addr = ui->ui_src; 107 m->m_len -= sizeof (struct udpiphdr); 108 m->m_off += sizeof (struct udpiphdr); 109 SBCHECK(&inp->inp_socket->so_rcv, "udpinput before"); 110 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 111 goto bad; 112 SBCHECK(&inp->inp_socket->so_rcv, "udpinput after"); 113 sorwakeup(inp->inp_socket); 114 return; 115 bad: 116 m_freem(m); 117 } 118 119 udp_abort(inp) 120 struct inpcb *inp; 121 { 122 struct socket *so = inp->inp_socket; 123 124 in_pcbdisconnect(inp); 125 soisdisconnected(so); 126 } 127 128 udp_ctlinput(cmd, arg) 129 int cmd; 130 caddr_t arg; 131 { 132 struct in_addr *sin; 133 extern u_char inetctlerrmap[]; 134 135 if (cmd < 0 || cmd > PRC_NCMDS) 136 return; 137 switch (cmd) { 138 139 case PRC_ROUTEDEAD: 140 break; 141 142 case PRC_QUENCH: 143 break; 144 145 /* these are handled by ip */ 146 case PRC_IFDOWN: 147 case PRC_HOSTDEAD: 148 case PRC_HOSTUNREACH: 149 break; 150 151 default: 152 sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 153 in_pcbnotify(&udb, sin, inetctlerrmap[cmd], udp_abort); 154 } 155 } 156 157 udp_output(inp, m0) 158 struct inpcb *inp; 159 struct mbuf *m0; 160 { 161 register struct mbuf *m; 162 register struct udpiphdr *ui; 163 register struct socket *so; 164 register int len = 0; 165 166 /* 167 * Calculate data length and get a mbuf 168 * for UDP and IP headers. 169 */ 170 for (m = m0; m; m = m->m_next) 171 len += m->m_len; 172 m = m_get(M_DONTWAIT); 173 if (m == 0) { 174 m_freem(m0); 175 return (ENOBUFS); 176 } 177 178 /* 179 * Fill in mbuf with extended UDP header 180 * and addresses and length put into network format. 181 */ 182 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 183 m->m_len = sizeof (struct udpiphdr); 184 m->m_next = m0; 185 ui = mtod(m, struct udpiphdr *); 186 ui->ui_next = ui->ui_prev = 0; 187 ui->ui_x1 = 0; 188 ui->ui_pr = IPPROTO_UDP; 189 ui->ui_len = len + sizeof (struct udphdr); 190 ui->ui_src = inp->inp_laddr; 191 ui->ui_dst = inp->inp_faddr; 192 ui->ui_sport = inp->inp_lport; 193 ui->ui_dport = inp->inp_fport; 194 ui->ui_ulen = htons((u_short)ui->ui_len); 195 196 /* 197 * Stuff checksum and output datagram. 198 */ 199 ui->ui_sum = 0; 200 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 201 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 202 ((struct ip *)ui)->ip_ttl = MAXTTL; 203 so = inp->inp_socket; 204 return (ip_output(m, (struct mbuf *)0, 205 (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0, 206 so->so_state & SS_PRIV)); 207 } 208 209 udp_usrreq(so, req, m, nam, opt) 210 struct socket *so; 211 int req; 212 struct mbuf *m, *nam; 213 struct socketopt *opt; 214 { 215 struct inpcb *inp = sotoinpcb(so); 216 int error = 0; 217 218 if (inp == 0 && req != PRU_ATTACH) 219 return (EINVAL); 220 switch (req) { 221 222 case PRU_ATTACH: 223 if (inp != 0) 224 return (EINVAL); 225 error = in_pcballoc(so, &udb); 226 if (error) 227 break; 228 error = in_pcbreserve(so, 2048, 2048); 229 if (error) 230 break; 231 break; 232 233 case PRU_DETACH: 234 if (inp == 0) 235 return (ENOTCONN); 236 in_pcbdetach(inp); 237 break; 238 239 case PRU_BIND: 240 error = in_pcbbind(inp, nam); 241 break; 242 243 case PRU_LISTEN: 244 error = EOPNOTSUPP; 245 break; 246 247 case PRU_CONNECT: 248 if (inp->inp_faddr.s_addr) 249 return (EISCONN); 250 error = in_pcbconnect(inp, nam); 251 if (error == 0) 252 soisconnected(so); 253 break; 254 255 case PRU_ACCEPT: 256 return (EOPNOTSUPP); 257 258 case PRU_DISCONNECT: 259 if (inp->inp_faddr.s_addr == 0) 260 return (ENOTCONN); 261 in_pcbdisconnect(inp); 262 soisdisconnected(so); 263 break; 264 265 case PRU_SHUTDOWN: 266 socantsendmore(so); 267 break; 268 269 case PRU_SEND: { 270 struct in_addr laddr; 271 272 if (nam) { 273 laddr = inp->inp_laddr; 274 if (inp->inp_faddr.s_addr) 275 return (EISCONN); 276 error = in_pcbconnect(inp, nam); 277 if (error) 278 break; 279 } else { 280 if (inp->inp_faddr.s_addr == 0) 281 return (ENOTCONN); 282 } 283 error = udp_output(inp, m); 284 if (nam) { 285 in_pcbdisconnect(inp); 286 inp->inp_laddr = laddr; 287 } 288 } 289 break; 290 291 case PRU_ABORT: 292 in_pcbdetach(inp); 293 sofree(so); 294 soisdisconnected(so); 295 break; 296 297 case PRU_CONTROL: 298 return (EOPNOTSUPP); 299 300 case PRU_SOCKADDR: 301 in_setsockaddr(inp, nam); 302 break; 303 304 default: 305 panic("udp_usrreq"); 306 } 307 return (error); 308 } 309