1566
1567 len = udp->udp_recv_ipp.ipp_ipv4_options_len;
1568 ASSERT(len != 0);
1569 bcopy(udp->udp_recv_ipp.ipp_ipv4_options, ptr, len);
1570 mutex_exit(&connp->conn_lock);
1571 return (len);
1572 }
1573 break;
1574 case IPPROTO_UDP:
1575 switch (name) {
1576 case UDP_NAT_T_ENDPOINT:
1577 mutex_enter(&connp->conn_lock);
1578 *i1 = udp->udp_nat_t_endpoint;
1579 mutex_exit(&connp->conn_lock);
1580 return (sizeof (int));
1581 case UDP_RCVHDR:
1582 mutex_enter(&connp->conn_lock);
1583 *i1 = udp->udp_rcvhdr ? 1 : 0;
1584 mutex_exit(&connp->conn_lock);
1585 return (sizeof (int));
1586 }
1587 }
1588 mutex_enter(&connp->conn_lock);
1589 retval = conn_opt_get(&coas, level, name, ptr);
1590 mutex_exit(&connp->conn_lock);
1591 return (retval);
1592 }
1593
1594 /*
1595 * This routine retrieves the current status of socket options.
1596 * It returns the size of the option retrieved, or -1.
1597 */
1598 int
1599 udp_tpi_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
1600 {
1601 conn_t *connp = Q_TO_CONN(q);
1602 int err;
1603
1604 err = udp_opt_get(connp, level, name, ptr);
1605 return (err);
1701 * to IPv6.
1702 */
1703 if (connp->conn_family != AF_INET) {
1704 return (EAFNOSUPPORT);
1705 }
1706
1707 if (!checkonly) {
1708 mutex_enter(&connp->conn_lock);
1709 udp->udp_nat_t_endpoint = onoff;
1710 mutex_exit(&connp->conn_lock);
1711 coa->coa_changed |= COA_HEADER_CHANGED;
1712 coa->coa_changed |= COA_WROFF_CHANGED;
1713 }
1714 /* Fully handled this option. */
1715 return (0);
1716 case UDP_RCVHDR:
1717 mutex_enter(&connp->conn_lock);
1718 udp->udp_rcvhdr = onoff;
1719 mutex_exit(&connp->conn_lock);
1720 return (0);
1721 }
1722 break;
1723 }
1724 error = conn_opt_set(coa, level, name, inlen, invalp,
1725 checkonly, cr);
1726 return (error);
1727 }
1728
1729 /*
1730 * This routine sets socket options.
1731 */
1732 int
1733 udp_opt_set(conn_t *connp, uint_t optset_context, int level,
1734 int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
1735 uchar_t *outvalp, void *thisdg_attrs, cred_t *cr)
1736 {
1737 udp_t *udp = connp->conn_udp;
1738 int err;
1739 conn_opt_arg_t coas, *coa;
1740 boolean_t checkonly;
5893 */
5894 udp->udp_state = TS_IDLE;
5895 }
5896 return (error);
5897 }
5898
5899 int
5900 udp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
5901 cred_t *cr)
5902 {
5903 sin6_t *sin6;
5904 sin_t *sin = NULL;
5905 uint_t srcid;
5906 conn_t *connp = (conn_t *)proto_handle;
5907 udp_t *udp = connp->conn_udp;
5908 int error = 0;
5909 udp_stack_t *us = udp->udp_us;
5910 ushort_t ipversion;
5911 pid_t pid = curproc->p_pid;
5912 ip_xmit_attr_t *ixa;
5913
5914 ASSERT(DB_TYPE(mp) == M_DATA);
5915
5916 /* All Solaris components should pass a cred for this operation. */
5917 ASSERT(cr != NULL);
5918
5919 /* do an implicit bind if necessary */
5920 if (udp->udp_state == TS_UNBND) {
5921 error = udp_implicit_bind(connp, cr);
5922 /*
5923 * We could be racing with an actual bind, in which case
5924 * we would see EPROTO. We cross our fingers and try
5925 * to connect.
5926 */
5927 if (!(error == 0 || error == EPROTO)) {
5928 freemsg(mp);
5929 return (error);
5930 }
5931 }
5932
5933 /* Connected? */
5934 if (msg->msg_name == NULL) {
5935 if (udp->udp_state != TS_DATA_XFER) {
5936 UDPS_BUMP_MIB(us, udpOutErrors);
5937 return (EDESTADDRREQ);
5938 }
5939 if (msg->msg_controllen != 0) {
5940 error = udp_output_ancillary(connp, NULL, NULL, mp,
5941 NULL, msg, cr, pid);
5942 } else {
5943 error = udp_output_connected(connp, mp, cr, pid);
5944 }
5945 if (us->us_sendto_ignerr)
5946 return (0);
5947 else
5948 return (error);
5949 }
5950 if (udp->udp_state == TS_DATA_XFER) {
5951 UDPS_BUMP_MIB(us, udpOutErrors);
5952 return (EISCONN);
5953 }
5954 error = proto_verify_ip_addr(connp->conn_family,
5955 (struct sockaddr *)msg->msg_name, msg->msg_namelen);
5956 if (error != 0) {
5957 UDPS_BUMP_MIB(us, udpOutErrors);
5958 return (error);
5959 }
5960 switch (connp->conn_family) {
5961 case AF_INET6:
5962 sin6 = (sin6_t *)msg->msg_name;
5963
5964 srcid = sin6->__sin6_src_id;
5965
5966 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5967 /*
5968 * Destination is a non-IPv4-compatible IPv6 address.
5969 * Send out an IPv6 format packet.
5970 */
5971
5972 /*
5973 * If the local address is a mapped address return
|
1566
1567 len = udp->udp_recv_ipp.ipp_ipv4_options_len;
1568 ASSERT(len != 0);
1569 bcopy(udp->udp_recv_ipp.ipp_ipv4_options, ptr, len);
1570 mutex_exit(&connp->conn_lock);
1571 return (len);
1572 }
1573 break;
1574 case IPPROTO_UDP:
1575 switch (name) {
1576 case UDP_NAT_T_ENDPOINT:
1577 mutex_enter(&connp->conn_lock);
1578 *i1 = udp->udp_nat_t_endpoint;
1579 mutex_exit(&connp->conn_lock);
1580 return (sizeof (int));
1581 case UDP_RCVHDR:
1582 mutex_enter(&connp->conn_lock);
1583 *i1 = udp->udp_rcvhdr ? 1 : 0;
1584 mutex_exit(&connp->conn_lock);
1585 return (sizeof (int));
1586 case UDP_SND_TO_CONNECTED:
1587 mutex_enter(&connp->conn_lock);
1588 *i1 = udp->udp_snd_to_conn ? 1 : 0;
1589 mutex_exit(&connp->conn_lock);
1590 return (sizeof (int));
1591 }
1592 }
1593 mutex_enter(&connp->conn_lock);
1594 retval = conn_opt_get(&coas, level, name, ptr);
1595 mutex_exit(&connp->conn_lock);
1596 return (retval);
1597 }
1598
1599 /*
1600 * This routine retrieves the current status of socket options.
1601 * It returns the size of the option retrieved, or -1.
1602 */
1603 int
1604 udp_tpi_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
1605 {
1606 conn_t *connp = Q_TO_CONN(q);
1607 int err;
1608
1609 err = udp_opt_get(connp, level, name, ptr);
1610 return (err);
1706 * to IPv6.
1707 */
1708 if (connp->conn_family != AF_INET) {
1709 return (EAFNOSUPPORT);
1710 }
1711
1712 if (!checkonly) {
1713 mutex_enter(&connp->conn_lock);
1714 udp->udp_nat_t_endpoint = onoff;
1715 mutex_exit(&connp->conn_lock);
1716 coa->coa_changed |= COA_HEADER_CHANGED;
1717 coa->coa_changed |= COA_WROFF_CHANGED;
1718 }
1719 /* Fully handled this option. */
1720 return (0);
1721 case UDP_RCVHDR:
1722 mutex_enter(&connp->conn_lock);
1723 udp->udp_rcvhdr = onoff;
1724 mutex_exit(&connp->conn_lock);
1725 return (0);
1726 case UDP_SND_TO_CONNECTED:
1727 mutex_enter(&connp->conn_lock);
1728 udp->udp_snd_to_conn = onoff;
1729 mutex_exit(&connp->conn_lock);
1730 return (0);
1731 }
1732 break;
1733 }
1734 error = conn_opt_set(coa, level, name, inlen, invalp,
1735 checkonly, cr);
1736 return (error);
1737 }
1738
1739 /*
1740 * This routine sets socket options.
1741 */
1742 int
1743 udp_opt_set(conn_t *connp, uint_t optset_context, int level,
1744 int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
1745 uchar_t *outvalp, void *thisdg_attrs, cred_t *cr)
1746 {
1747 udp_t *udp = connp->conn_udp;
1748 int err;
1749 conn_opt_arg_t coas, *coa;
1750 boolean_t checkonly;
5903 */
5904 udp->udp_state = TS_IDLE;
5905 }
5906 return (error);
5907 }
5908
5909 int
5910 udp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
5911 cred_t *cr)
5912 {
5913 sin6_t *sin6;
5914 sin_t *sin = NULL;
5915 uint_t srcid;
5916 conn_t *connp = (conn_t *)proto_handle;
5917 udp_t *udp = connp->conn_udp;
5918 int error = 0;
5919 udp_stack_t *us = udp->udp_us;
5920 ushort_t ipversion;
5921 pid_t pid = curproc->p_pid;
5922 ip_xmit_attr_t *ixa;
5923 boolean_t snd_to_conn;
5924
5925 ASSERT(DB_TYPE(mp) == M_DATA);
5926
5927 /* All Solaris components should pass a cred for this operation. */
5928 ASSERT(cr != NULL);
5929
5930 /* do an implicit bind if necessary */
5931 if (udp->udp_state == TS_UNBND) {
5932 error = udp_implicit_bind(connp, cr);
5933 /*
5934 * We could be racing with an actual bind, in which case
5935 * we would see EPROTO. We cross our fingers and try
5936 * to connect.
5937 */
5938 if (!(error == 0 || error == EPROTO)) {
5939 freemsg(mp);
5940 return (error);
5941 }
5942 }
5943
5944 /* Connected? */
5945 if (msg->msg_name == NULL) {
5946 if (udp->udp_state != TS_DATA_XFER) {
5947 UDPS_BUMP_MIB(us, udpOutErrors);
5948 return (EDESTADDRREQ);
5949 }
5950 if (msg->msg_controllen != 0) {
5951 error = udp_output_ancillary(connp, NULL, NULL, mp,
5952 NULL, msg, cr, pid);
5953 } else {
5954 error = udp_output_connected(connp, mp, cr, pid);
5955 }
5956 if (us->us_sendto_ignerr)
5957 return (0);
5958 else
5959 return (error);
5960 }
5961
5962 /*
5963 * Check if we're allowed to send to a connection on which we've
5964 * already called 'connect'. The posix spec. allows both behaviors but
5965 * historically we've returned an error if already connected. The
5966 * client can allow this via a sockopt.
5967 */
5968 mutex_enter(&connp->conn_lock);
5969 snd_to_conn = (udp->udp_snd_to_conn != 0);
5970 mutex_exit(&connp->conn_lock);
5971 if (udp->udp_state == TS_DATA_XFER && !snd_to_conn) {
5972 UDPS_BUMP_MIB(us, udpOutErrors);
5973 return (EISCONN);
5974 }
5975
5976 error = proto_verify_ip_addr(connp->conn_family,
5977 (struct sockaddr *)msg->msg_name, msg->msg_namelen);
5978 if (error != 0) {
5979 UDPS_BUMP_MIB(us, udpOutErrors);
5980 return (error);
5981 }
5982 switch (connp->conn_family) {
5983 case AF_INET6:
5984 sin6 = (sin6_t *)msg->msg_name;
5985
5986 srcid = sin6->__sin6_src_id;
5987
5988 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5989 /*
5990 * Destination is a non-IPv4-compatible IPv6 address.
5991 * Send out an IPv6 format packet.
5992 */
5993
5994 /*
5995 * If the local address is a mapped address return
|