1 /* udp_usrreq.c 4.26 82/04/10 */ 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/route.h" 12 #include "../net/in_pcb.h" 13 #include "../net/in_systm.h" 14 #include "../net/ip.h" 15 #include "../net/ip_var.h" 16 #include "../net/udp.h" 17 #include "../net/udp_var.h" 18 #include <errno.h> 19 20 /* 21 * UDP protocol implementation. 22 * Per RFC 768, August, 1980. 23 */ 24 udp_init() 25 { 26 27 COUNT(UDP_INIT); 28 udb.inp_next = udb.inp_prev = &udb; 29 } 30 31 int udpcksum; 32 struct sockaddr_in udp_in = { AF_INET }; 33 34 udp_input(m0) 35 struct mbuf *m0; 36 { 37 register struct udpiphdr *ui; 38 register struct inpcb *inp; 39 register struct mbuf *m; 40 int len, ulen; 41 42 COUNT(UDP_INPUT); 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 ulen = ntohs((u_short)ui->ui_ulen); 61 len = sizeof (struct udphdr) + ulen; 62 if (((struct ip *)ui)->ip_len != len) { 63 if (len > ((struct ip *)ui)->ip_len) { 64 udpstat.udps_badlen++; 65 goto bad; 66 } 67 m_adj(m, ((struct ip *)ui)->ip_len - len); 68 /* (struct ip *)ui->ip_len = len; */ 69 } 70 71 /* 72 * Checksum extended UDP header and data. 73 */ 74 if (udpcksum) { 75 ui->ui_next = ui->ui_prev = 0; 76 ui->ui_x1 = 0; 77 ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); 78 if (ui->ui_sum = in_cksum(m, len)) { 79 udpstat.udps_badsum++; 80 printf("udp cksum %x\n", ui->ui_sum); 81 m_freem(m); 82 return; 83 } 84 } 85 86 /* 87 * Locate pcb for datagram. On wildcard match, update 88 * control block to anchor network and host address. 89 */ 90 inp = in_pcblookup(&udb, 91 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 92 INPLOOKUP_WILDCARD); 93 if (inp == 0) 94 goto bad; 95 96 /* 97 * Construct sockaddr format source address. 98 * Stuff source address and datagram in user buffer. 99 */ 100 udp_in.sin_port = ui->ui_sport; 101 udp_in.sin_addr = ui->ui_src; 102 m->m_len -= sizeof (struct udpiphdr); 103 m->m_off += sizeof (struct udpiphdr); 104 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 105 goto bad; 106 sorwakeup(inp->inp_socket); 107 return; 108 bad: 109 m_freem(m); 110 } 111 112 udp_ctlinput(m) 113 struct mbuf *m; 114 { 115 116 COUNT(UDP_CTLINPUT); 117 m_freem(m); 118 } 119 120 udp_output(inp, m0) 121 struct inpcb *inp; 122 struct mbuf *m0; 123 { 124 register struct mbuf *m; 125 register struct udpiphdr *ui; 126 register int len = 0; 127 128 COUNT(UDP_OUTPUT); 129 /* 130 * Calculate data length and get a mbuf 131 * for UDP and IP headers. 132 */ 133 for (m = m0; m; m = m->m_next) 134 len += m->m_len; 135 m = m_get(M_DONTWAIT); 136 if (m == 0) { 137 m_freem(m0); 138 return (ENOBUFS); 139 } 140 141 /* 142 * Fill in mbuf with extended UDP header 143 * and addresses and length put into network format. 144 */ 145 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 146 m->m_len = sizeof (struct udpiphdr); 147 m->m_next = m0; 148 ui = mtod(m, struct udpiphdr *); 149 ui->ui_next = ui->ui_prev = 0; 150 ui->ui_x1 = 0; 151 ui->ui_pr = IPPROTO_UDP; 152 ui->ui_len = sizeof (struct udpiphdr) + len; 153 ui->ui_src = inp->inp_laddr; 154 ui->ui_dst = inp->inp_faddr; 155 ui->ui_sport = inp->inp_lport; 156 ui->ui_dport = inp->inp_fport; 157 ui->ui_ulen = htons((u_short)len); 158 159 /* 160 * Stuff checksum and output datagram. 161 */ 162 ui->ui_sum = 0; 163 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 164 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 165 ((struct ip *)ui)->ip_ttl = MAXTTL; 166 return (ip_output(m, (struct mbuf *)0, 0, 167 inp->inp_socket->so_state & SS_PRIV)); 168 } 169 170 udp_usrreq(so, req, m, addr) 171 struct socket *so; 172 int req; 173 struct mbuf *m; 174 caddr_t addr; 175 { 176 struct inpcb *inp = sotoinpcb(so); 177 int error = 0; 178 179 COUNT(UDP_USRREQ); 180 if (inp == 0 && req != PRU_ATTACH) 181 return (EINVAL); 182 switch (req) { 183 184 case PRU_ATTACH: 185 if (inp != 0) 186 return (EINVAL); 187 error = in_pcbattach(so, &udb, 2048, 2048, 188 (struct sockaddr_in *)addr); 189 break; 190 191 case PRU_DETACH: 192 if (inp == 0) 193 return (ENOTCONN); 194 in_pcbdetach(inp); 195 break; 196 197 case PRU_CONNECT: 198 if (inp->inp_faddr.s_addr) 199 return (EISCONN); 200 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 201 if (error == 0) 202 soisconnected(so); 203 break; 204 205 case PRU_ACCEPT: 206 return (EOPNOTSUPP); 207 208 case PRU_DISCONNECT: 209 if (inp->inp_faddr.s_addr == 0) 210 return (ENOTCONN); 211 in_pcbdisconnect(inp); 212 soisdisconnected(so); 213 break; 214 215 case PRU_SHUTDOWN: 216 socantsendmore(so); 217 break; 218 219 case PRU_SEND: { 220 struct in_addr laddr; 221 222 if (addr) { 223 laddr = inp->inp_laddr; 224 if (inp->inp_faddr.s_addr) 225 return (EISCONN); 226 error = in_pcbconnect(inp, (struct sockaddr_in *)addr); 227 if (error) 228 break; 229 } else { 230 if (inp->inp_faddr.s_addr == 0) 231 return (ENOTCONN); 232 } 233 error = udp_output(inp, m); 234 if (addr) { 235 in_pcbdisconnect(inp); 236 inp->inp_laddr = laddr; 237 } 238 } 239 break; 240 241 case PRU_ABORT: 242 in_pcbdetach(inp); 243 sofree(so); 244 soisdisconnected(so); 245 break; 246 247 case PRU_CONTROL: 248 return (EOPNOTSUPP); 249 250 case PRU_SOCKADDR: 251 in_setsockaddr((struct sockaddr_in *)addr, inp); 252 break; 253 254 default: 255 panic("udp_usrreq"); 256 } 257 return (error); 258 } 259