1 /* udp_usrreq.c 4.37 82/10/20 */ 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 = 95 if_makeaddr(in_netof((int)ui->ui_dst.s_net), INADDR_ANY); 96 if (ui->ui_dst.s_addr == broadcastaddr.s_addr) 97 goto bad; 98 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 99 return; 100 } 101 102 /* 103 * Construct sockaddr format source address. 104 * Stuff source address and datagram in user buffer. 105 */ 106 udp_in.sin_port = ui->ui_sport; 107 udp_in.sin_addr = ui->ui_src; 108 m->m_len -= sizeof (struct udpiphdr); 109 m->m_off += sizeof (struct udpiphdr); 110 SBCHECK(&inp->inp_socket->so_rcv, "udpinput before"); 111 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 112 goto bad; 113 SBCHECK(&inp->inp_socket->so_rcv, "udpinput after"); 114 sorwakeup(inp->inp_socket); 115 return; 116 bad: 117 m_freem(m); 118 } 119 120 udp_abort(inp) 121 struct inpcb *inp; 122 { 123 struct socket *so = inp->inp_socket; 124 125 in_pcbdisconnect(inp); 126 soisdisconnected(so); 127 } 128 129 udp_ctlinput(cmd, arg) 130 int cmd; 131 caddr_t arg; 132 { 133 struct in_addr *sin; 134 extern u_char inetctlerrmap[]; 135 136 if (cmd < 0 || cmd > PRC_NCMDS) 137 return; 138 switch (cmd) { 139 140 case PRC_ROUTEDEAD: 141 break; 142 143 case PRC_QUENCH: 144 break; 145 146 /* these are handled by ip */ 147 case PRC_IFDOWN: 148 case PRC_HOSTDEAD: 149 case PRC_HOSTUNREACH: 150 break; 151 152 default: 153 sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 154 in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort); 155 } 156 } 157 158 udp_output(inp, m0) 159 struct inpcb *inp; 160 struct mbuf *m0; 161 { 162 register struct mbuf *m; 163 register struct udpiphdr *ui; 164 register struct socket *so; 165 register int len = 0; 166 167 /* 168 * Calculate data length and get a mbuf 169 * for UDP and IP headers. 170 */ 171 for (m = m0; m; m = m->m_next) 172 len += m->m_len; 173 m = m_get(M_DONTWAIT); 174 if (m == 0) { 175 m_freem(m0); 176 return (ENOBUFS); 177 } 178 179 /* 180 * Fill in mbuf with extended UDP header 181 * and addresses and length put into network format. 182 */ 183 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 184 m->m_len = sizeof (struct udpiphdr); 185 m->m_next = m0; 186 ui = mtod(m, struct udpiphdr *); 187 ui->ui_next = ui->ui_prev = 0; 188 ui->ui_x1 = 0; 189 ui->ui_pr = IPPROTO_UDP; 190 ui->ui_len = len + sizeof (struct udphdr); 191 ui->ui_src = inp->inp_laddr; 192 ui->ui_dst = inp->inp_faddr; 193 ui->ui_sport = inp->inp_lport; 194 ui->ui_dport = inp->inp_fport; 195 ui->ui_ulen = htons((u_short)ui->ui_len); 196 197 /* 198 * Stuff checksum and output datagram. 199 */ 200 ui->ui_sum = 0; 201 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 202 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 203 ((struct ip *)ui)->ip_ttl = MAXTTL; 204 so = inp->inp_socket; 205 return (ip_output(m, (struct mbuf *)0, 206 (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0, 207 so->so_state & SS_PRIV)); 208 } 209 210 /*ARGSUSED*/ 211 udp_usrreq(so, req, m, nam, opt) 212 struct socket *so; 213 int req; 214 struct mbuf *m, *nam; 215 struct socketopt *opt; 216 { 217 struct inpcb *inp = sotoinpcb(so); 218 int error = 0; 219 220 if (inp == 0 && req != PRU_ATTACH) 221 return (EINVAL); 222 switch (req) { 223 224 case PRU_ATTACH: 225 if (inp != 0) 226 return (EINVAL); 227 error = in_pcballoc(so, &udb); 228 if (error) 229 break; 230 error = in_pcbreserve(so, 2048, 2048); 231 if (error) 232 break; 233 break; 234 235 case PRU_DETACH: 236 if (inp == 0) 237 return (ENOTCONN); 238 in_pcbdetach(inp); 239 break; 240 241 case PRU_BIND: 242 error = in_pcbbind(inp, nam); 243 break; 244 245 case PRU_LISTEN: 246 error = EOPNOTSUPP; 247 break; 248 249 case PRU_CONNECT: 250 if (inp->inp_faddr.s_addr) 251 return (EISCONN); 252 error = in_pcbconnect(inp, nam); 253 if (error == 0) 254 soisconnected(so); 255 break; 256 257 case PRU_ACCEPT: 258 return (EOPNOTSUPP); 259 260 case PRU_DISCONNECT: 261 if (inp->inp_faddr.s_addr == 0) 262 return (ENOTCONN); 263 in_pcbdisconnect(inp); 264 soisdisconnected(so); 265 break; 266 267 case PRU_SHUTDOWN: 268 socantsendmore(so); 269 break; 270 271 case PRU_SEND: { 272 struct in_addr laddr; 273 274 if (nam) { 275 laddr = inp->inp_laddr; 276 if (inp->inp_faddr.s_addr) 277 return (EISCONN); 278 error = in_pcbconnect(inp, nam); 279 if (error) 280 break; 281 } else { 282 if (inp->inp_faddr.s_addr == 0) 283 return (ENOTCONN); 284 } 285 error = udp_output(inp, m); 286 if (nam) { 287 in_pcbdisconnect(inp); 288 inp->inp_laddr = laddr; 289 } 290 } 291 break; 292 293 case PRU_ABORT: 294 in_pcbdetach(inp); 295 sofree(so); 296 soisdisconnected(so); 297 break; 298 299 case PRU_CONTROL: 300 return (EOPNOTSUPP); 301 302 case PRU_SOCKADDR: 303 in_setsockaddr(inp, nam); 304 break; 305 306 default: 307 panic("udp_usrreq"); 308 } 309 return (error); 310 } 311