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