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