udp_usrreq.c
上传用户:tjbfgc
上传日期:2013-03-31
资源大小:140k
文件大小:16k
源码类别:

网络编程

开发平台:

C/C++

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988, 1990, 1993
  3.  * The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  * This product includes software developed by the University of
  16.  * California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
  34.  */
  35. #include <sys/param.h>
  36. #include <sys/malloc.h>
  37. #include <sys/mbuf.h>
  38. #include <sys/protosw.h>
  39. #include <sys/socket.h>
  40. #include <sys/socketvar.h>
  41. #include <sys/errno.h>
  42. #include <sys/stat.h>
  43. #include <net/if.h>
  44. #include <net/route.h>
  45. #include <netinet/in.h>
  46. #include <netinet/in_systm.h>
  47. #include <netinet/ip.h>
  48. #include <netinet/in_pcb.h>
  49. #include <netinet/ip_var.h>
  50. #include <netinet/ip_icmp.h>
  51. #include <netinet/udp.h>
  52. #include <netinet/udp_var.h>
  53. /*
  54.  * UDP protocol implementation.
  55.  * Per RFC 768, August, 1980.
  56.  */
  57. #ifndef COMPAT_42
  58. int udpcksum = 1;
  59. #else
  60. int udpcksum = 0; /* XXX */
  61. #endif
  62. struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
  63. struct inpcb *udp_last_inpcb = &udb;
  64. static void udp_detach __P((struct inpcb *));
  65. static void udp_notify __P((struct inpcb *, int));
  66. static struct mbuf *udp_saveopt __P((caddr_t, int, int));
  67. void
  68. udp_init()
  69. {
  70. udb.inp_next = udb.inp_prev = &udb;
  71. }
  72. void
  73. udp_input(m, iphlen)
  74. register struct mbuf *m;
  75. int iphlen;
  76. {
  77. register struct ip *ip;
  78. register struct udphdr *uh;
  79. register struct inpcb *inp;
  80. struct mbuf *opts = 0;
  81. int len;
  82. struct ip save_ip;
  83. udpstat.udps_ipackets++;
  84. /*
  85.  * Strip IP options, if any; should skip this,
  86.  * make available to user, and use on returned packets,
  87.  * but we don't yet have a way to check the checksum
  88.  * with options still present.
  89.  */
  90. if (iphlen > sizeof (struct ip)) {
  91. ip_stripoptions(m, (struct mbuf *)0);
  92. iphlen = sizeof(struct ip);
  93. }
  94. /*
  95.  * Get IP and UDP header together in first mbuf.
  96.  */
  97. ip = mtod(m, struct ip *);
  98. if (m->m_len < iphlen + sizeof(struct udphdr)) {
  99. if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
  100. udpstat.udps_hdrops++;
  101. return;
  102. }
  103. ip = mtod(m, struct ip *);
  104. }
  105. uh = (struct udphdr *)((caddr_t)ip + iphlen);
  106. /*
  107.  * Make mbuf data length reflect UDP length.
  108.  * If not enough data to reflect UDP length, drop.
  109.  */
  110. len = ntohs((u_short)uh->uh_ulen);
  111. if (ip->ip_len != len) {
  112. if (len > ip->ip_len) {
  113. udpstat.udps_badlen++;
  114. goto bad;
  115. }
  116. m_adj(m, len - ip->ip_len);
  117. /* ip->ip_len = len; */
  118. }
  119. /*
  120.  * Save a copy of the IP header in case we want restore it
  121.  * for sending an ICMP error message in response.
  122.  */
  123. save_ip = *ip;
  124. /*
  125.  * Checksum extended UDP header and data.
  126.  */
  127. if (udpcksum && uh->uh_sum) {
  128. ((struct ipovly *)ip)->ih_next = 0;
  129. ((struct ipovly *)ip)->ih_prev = 0;
  130. ((struct ipovly *)ip)->ih_x1 = 0;
  131. ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
  132. if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
  133. udpstat.udps_badsum++;
  134. m_freem(m);
  135. return;
  136. }
  137. }
  138. if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
  139.     in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
  140. struct socket *last;
  141. /*
  142.  * Deliver a multicast or broadcast datagram to *all* sockets
  143.  * for which the local and remote addresses and ports match
  144.  * those of the incoming datagram.  This allows more than
  145.  * one process to receive multi/broadcasts on the same port.
  146.  * (This really ought to be done for unicast datagrams as
  147.  * well, but that would cause problems with existing
  148.  * applications that open both address-specific sockets and
  149.  * a wildcard socket listening to the same port -- they would
  150.  * end up receiving duplicates of every unicast datagram.
  151.  * Those applications open the multiple sockets to overcome an
  152.  * inadequacy of the UDP socket interface, but for backwards
  153.  * compatibility we avoid the problem here rather than
  154.  * fixing the interface.  Maybe 4.5BSD will remedy this?)
  155.  */
  156. /*
  157.  * Construct sockaddr format source address.
  158.  */
  159. udp_in.sin_port = uh->uh_sport;
  160. udp_in.sin_addr = ip->ip_src;
  161. m->m_len -= sizeof (struct udpiphdr);
  162. m->m_data += sizeof (struct udpiphdr);
  163. /*
  164.  * Locate pcb(s) for datagram.
  165.  * (Algorithm copied from raw_intr().)
  166.  */
  167. last = NULL;
  168. for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) {
  169. if (inp->inp_lport != uh->uh_dport)
  170. continue;
  171. if (inp->inp_laddr.s_addr != INADDR_ANY) {
  172. if (inp->inp_laddr.s_addr !=
  173.     ip->ip_dst.s_addr)
  174. continue;
  175. }
  176. if (inp->inp_faddr.s_addr != INADDR_ANY) {
  177. if (inp->inp_faddr.s_addr !=
  178.     ip->ip_src.s_addr ||
  179.     inp->inp_fport != uh->uh_sport)
  180. continue;
  181. }
  182. if (last != NULL) {
  183. struct mbuf *n;
  184. if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
  185. if (sbappendaddr(&last->so_rcv,
  186. (struct sockaddr *)&udp_in,
  187. n, (struct mbuf *)0) == 0) {
  188. m_freem(n);
  189. udpstat.udps_fullsock++;
  190. } else
  191. sorwakeup(last);
  192. }
  193. }
  194. last = inp->inp_socket;
  195. /*
  196.  * Don't look for additional matches if this one does
  197.  * not have either the SO_REUSEPORT or SO_REUSEADDR
  198.  * socket options set.  This heuristic avoids searching
  199.  * through all pcbs in the common case of a non-shared
  200.  * port.  It * assumes that an application will never
  201.  * clear these options after setting them.
  202.  */
  203. if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0))
  204. break;
  205. }
  206. if (last == NULL) {
  207. /*
  208.  * No matching pcb found; discard datagram.
  209.  * (No need to send an ICMP Port Unreachable
  210.  * for a broadcast or multicast datgram.)
  211.  */
  212. udpstat.udps_noportbcast++;
  213. goto bad;
  214. }
  215. if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
  216.      m, (struct mbuf *)0) == 0) {
  217. udpstat.udps_fullsock++;
  218. goto bad;
  219. }
  220. sorwakeup(last);
  221. return;
  222. }
  223. /*
  224.  * Locate pcb for datagram.
  225.  */
  226. inp = udp_last_inpcb;
  227. if (inp->inp_lport != uh->uh_dport ||
  228.     inp->inp_fport != uh->uh_sport ||
  229.     inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
  230.     inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
  231. inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
  232.     ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
  233. if (inp)
  234. udp_last_inpcb = inp;
  235. udpstat.udpps_pcbcachemiss++;
  236. }
  237. if (inp == 0) {
  238. udpstat.udps_noport++;
  239. if (m->m_flags & (M_BCAST | M_MCAST)) {
  240. udpstat.udps_noportbcast++;
  241. goto bad;
  242. }
  243. *ip = save_ip;
  244. ip->ip_len += iphlen;
  245. icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
  246. return;
  247. }
  248. /*
  249.  * Construct sockaddr format source address.
  250.  * Stuff source address and datagram in user buffer.
  251.  */
  252. udp_in.sin_port = uh->uh_sport;
  253. udp_in.sin_addr = ip->ip_src;
  254. if (inp->inp_flags & INP_CONTROLOPTS) {
  255. struct mbuf **mp = &opts;
  256. if (inp->inp_flags & INP_RECVDSTADDR) {
  257. *mp = udp_saveopt((caddr_t) &ip->ip_dst,
  258.     sizeof(struct in_addr), IP_RECVDSTADDR);
  259. if (*mp)
  260. mp = &(*mp)->m_next;
  261. }
  262. #ifdef notyet
  263. /* options were tossed above */
  264. if (inp->inp_flags & INP_RECVOPTS) {
  265. *mp = udp_saveopt((caddr_t) opts_deleted_above,
  266.     sizeof(struct in_addr), IP_RECVOPTS);
  267. if (*mp)
  268. mp = &(*mp)->m_next;
  269. }
  270. /* ip_srcroute doesn't do what we want here, need to fix */
  271. if (inp->inp_flags & INP_RECVRETOPTS) {
  272. *mp = udp_saveopt((caddr_t) ip_srcroute(),
  273.     sizeof(struct in_addr), IP_RECVRETOPTS);
  274. if (*mp)
  275. mp = &(*mp)->m_next;
  276. }
  277. #endif
  278. }
  279. iphlen += sizeof(struct udphdr);
  280. m->m_len -= iphlen;
  281. m->m_pkthdr.len -= iphlen;
  282. m->m_data += iphlen;
  283. if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
  284.     m, opts) == 0) {
  285. udpstat.udps_fullsock++;
  286. goto bad;
  287. }
  288. sorwakeup(inp->inp_socket);
  289. return;
  290. bad:
  291. m_freem(m);
  292. if (opts)
  293. m_freem(opts);
  294. }
  295. /*
  296.  * Create a "control" mbuf containing the specified data
  297.  * with the specified type for presentation with a datagram.
  298.  */
  299. struct mbuf *
  300. udp_saveopt(p, size, type)
  301. caddr_t p;
  302. register int size;
  303. int type;
  304. {
  305. register struct cmsghdr *cp;
  306. struct mbuf *m;
  307. if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
  308. return ((struct mbuf *) NULL);
  309. cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
  310. bcopy(p, CMSG_DATA(cp), size);
  311. size += sizeof(*cp);
  312. m->m_len = size;
  313. cp->cmsg_len = size;
  314. cp->cmsg_level = IPPROTO_IP;
  315. cp->cmsg_type = type;
  316. return (m);
  317. }
  318. /*
  319.  * Notify a udp user of an asynchronous error;
  320.  * just wake up so that he can collect error status.
  321.  */
  322. static void
  323. udp_notify(inp, errno)
  324. register struct inpcb *inp;
  325. int errno;
  326. {
  327. inp->inp_socket->so_error = errno;
  328. sorwakeup(inp->inp_socket);
  329. sowwakeup(inp->inp_socket);
  330. }
  331. void
  332. udp_ctlinput(cmd, sa, ip)
  333. int cmd;
  334. struct sockaddr *sa;
  335. register struct ip *ip;
  336. {
  337. register struct udphdr *uh;
  338. extern struct in_addr zeroin_addr;
  339. extern u_char inetctlerrmap[];
  340. if (!PRC_IS_REDIRECT(cmd) &&
  341.     ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
  342. return;
  343. if (ip) {
  344. uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
  345. in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
  346. cmd, udp_notify);
  347. } else
  348. in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
  349. }
  350. int
  351. udp_output(inp, m, addr, control)
  352. register struct inpcb *inp;
  353. register struct mbuf *m;
  354. struct mbuf *addr, *control;
  355. {
  356. register struct udpiphdr *ui;
  357. register int len = m->m_pkthdr.len;
  358. struct in_addr laddr;
  359. int s, error = 0;
  360. if (control)
  361. m_freem(control); /* XXX */
  362. if (addr) {
  363. laddr = inp->inp_laddr;
  364. if (inp->inp_faddr.s_addr != INADDR_ANY) {
  365. error = EISCONN;
  366. goto release;
  367. }
  368. /*
  369.  * Must block input while temporarily connected.
  370.  */
  371. s = splnet();
  372. error = in_pcbconnect(inp, addr);
  373. if (error) {
  374. splx(s);
  375. goto release;
  376. }
  377. } else {
  378. if (inp->inp_faddr.s_addr == INADDR_ANY) {
  379. error = ENOTCONN;
  380. goto release;
  381. }
  382. }
  383. /*
  384.  * Calculate data length and get a mbuf
  385.  * for UDP and IP headers.
  386.  */
  387. M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
  388. if (m == 0) {
  389. error = ENOBUFS;
  390. goto release;
  391. }
  392. /*
  393.  * Fill in mbuf with extended UDP header
  394.  * and addresses and length put into network format.
  395.  */
  396. ui = mtod(m, struct udpiphdr *);
  397. ui->ui_next = ui->ui_prev = 0;
  398. ui->ui_x1 = 0;
  399. ui->ui_pr = IPPROTO_UDP;
  400. ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
  401. ui->ui_src = inp->inp_laddr;
  402. ui->ui_dst = inp->inp_faddr;
  403. ui->ui_sport = inp->inp_lport;
  404. ui->ui_dport = inp->inp_fport;
  405. ui->ui_ulen = ui->ui_len;
  406. /*
  407.  * Stuff checksum and output datagram.
  408.  */
  409. ui->ui_sum = 0;
  410. if (udpcksum) {
  411.     if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
  412. ui->ui_sum = 0xffff;
  413. }
  414. ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
  415. ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
  416. ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
  417. udpstat.udps_opackets++;
  418. error = ip_output(m, inp->inp_options, &inp->inp_route,
  419.     inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
  420.     inp->inp_moptions);
  421. if (addr) {
  422. in_pcbdisconnect(inp);
  423. inp->inp_laddr = laddr;
  424. splx(s);
  425. }
  426. return (error);
  427. release:
  428. m_freem(m);
  429. return (error);
  430. }
  431. u_long udp_sendspace = 9216; /* really max datagram size */
  432. u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
  433. /* 40 1K datagrams */
  434. /*ARGSUSED*/
  435. int
  436. udp_usrreq(so, req, m, addr, control)
  437. struct socket *so;
  438. int req;
  439. struct mbuf *m, *addr, *control;
  440. {
  441. struct inpcb *inp = sotoinpcb(so);
  442. int error = 0;
  443. int s;
  444. if (req == PRU_CONTROL)
  445. return (in_control(so, (int)m, (caddr_t)addr,
  446. (struct ifnet *)control));
  447. if (inp == NULL && req != PRU_ATTACH) {
  448. error = EINVAL;
  449. goto release;
  450. }
  451. /*
  452.  * Note: need to block udp_input while changing
  453.  * the udp pcb queue and/or pcb addresses.
  454.  */
  455. switch (req) {
  456. case PRU_ATTACH:
  457. if (inp != NULL) {
  458. error = EINVAL;
  459. break;
  460. }
  461. s = splnet();
  462. error = in_pcballoc(so, &udb);
  463. splx(s);
  464. if (error)
  465. break;
  466. error = soreserve(so, udp_sendspace, udp_recvspace);
  467. if (error)
  468. break;
  469. ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
  470. break;
  471. case PRU_DETACH:
  472. udp_detach(inp);
  473. break;
  474. case PRU_BIND:
  475. s = splnet();
  476. error = in_pcbbind(inp, addr);
  477. splx(s);
  478. break;
  479. case PRU_LISTEN:
  480. error = EOPNOTSUPP;
  481. break;
  482. case PRU_CONNECT:
  483. if (inp->inp_faddr.s_addr != INADDR_ANY) {
  484. error = EISCONN;
  485. break;
  486. }
  487. s = splnet();
  488. error = in_pcbconnect(inp, addr);
  489. splx(s);
  490. if (error == 0)
  491. soisconnected(so);
  492. break;
  493. case PRU_CONNECT2:
  494. error = EOPNOTSUPP;
  495. break;
  496. case PRU_ACCEPT:
  497. error = EOPNOTSUPP;
  498. break;
  499. case PRU_DISCONNECT:
  500. if (inp->inp_faddr.s_addr == INADDR_ANY) {
  501. error = ENOTCONN;
  502. break;
  503. }
  504. s = splnet();
  505. in_pcbdisconnect(inp);
  506. inp->inp_laddr.s_addr = INADDR_ANY;
  507. splx(s);
  508. so->so_state &= ~SS_ISCONNECTED; /* XXX */
  509. break;
  510. case PRU_SHUTDOWN:
  511. socantsendmore(so);
  512. break;
  513. case PRU_SEND:
  514. return (udp_output(inp, m, addr, control));
  515. case PRU_ABORT:
  516. soisdisconnected(so);
  517. udp_detach(inp);
  518. break;
  519. case PRU_SOCKADDR:
  520. in_setsockaddr(inp, addr);
  521. break;
  522. case PRU_PEERADDR:
  523. in_setpeeraddr(inp, addr);
  524. break;
  525. case PRU_SENSE:
  526. /*
  527.  * stat: don't bother with a blocksize.
  528.  */
  529. return (0);
  530. case PRU_SENDOOB:
  531. case PRU_FASTTIMO:
  532. case PRU_SLOWTIMO:
  533. case PRU_PROTORCV:
  534. case PRU_PROTOSEND:
  535. error =  EOPNOTSUPP;
  536. break;
  537. case PRU_RCVD:
  538. case PRU_RCVOOB:
  539. return (EOPNOTSUPP); /* do not free mbuf's */
  540. default:
  541. panic("udp_usrreq");
  542. }
  543. release:
  544. if (control) {
  545. printf("udp control data unexpectedly retainedn");
  546. m_freem(control);
  547. }
  548. if (m)
  549. m_freem(m);
  550. return (error);
  551. }
  552. static void
  553. udp_detach(inp)
  554. struct inpcb *inp;
  555. {
  556. int s = splnet();
  557. if (inp == udp_last_inpcb)
  558. udp_last_inpcb = &udb;
  559. in_pcbdetach(inp);
  560. splx(s);
  561. }
  562. /*
  563.  * Sysctl for udp variables.
  564.  */
  565. udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
  566. int *name;
  567. u_int namelen;
  568. void *oldp;
  569. size_t *oldlenp;
  570. void *newp;
  571. size_t newlen;
  572. {
  573. /* All sysctl names at this level are terminal. */
  574. if (namelen != 1)
  575. return (ENOTDIR);
  576. switch (name[0]) {
  577. case UDPCTL_CHECKSUM:
  578. return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
  579. default:
  580. return (ENOPROTOOPT);
  581. }
  582. /* NOTREACHED */
  583. }