diff options
Diffstat (limited to 'net/ipv4/cipso_ipv4.c')
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e13d6dbb66ab..23768b9d6b64 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -1810,6 +1810,80 @@ socket_setattr_failure: | |||
1810 | } | 1810 | } |
1811 | 1811 | ||
1812 | /** | 1812 | /** |
1813 | * cipso_v4_sock_delattr - Delete the CIPSO option from a socket | ||
1814 | * @sk: the socket | ||
1815 | * | ||
1816 | * Description: | ||
1817 | * Removes the CIPSO option from a socket, if present. | ||
1818 | * | ||
1819 | */ | ||
1820 | void cipso_v4_sock_delattr(struct sock *sk) | ||
1821 | { | ||
1822 | u8 hdr_delta; | ||
1823 | struct ip_options *opt; | ||
1824 | struct inet_sock *sk_inet; | ||
1825 | |||
1826 | sk_inet = inet_sk(sk); | ||
1827 | opt = sk_inet->opt; | ||
1828 | if (opt == NULL || opt->cipso == 0) | ||
1829 | return; | ||
1830 | |||
1831 | if (opt->srr || opt->rr || opt->ts || opt->router_alert) { | ||
1832 | u8 cipso_len; | ||
1833 | u8 cipso_off; | ||
1834 | unsigned char *cipso_ptr; | ||
1835 | int iter; | ||
1836 | int optlen_new; | ||
1837 | |||
1838 | cipso_off = opt->cipso - sizeof(struct iphdr); | ||
1839 | cipso_ptr = &opt->__data[cipso_off]; | ||
1840 | cipso_len = cipso_ptr[1]; | ||
1841 | |||
1842 | if (opt->srr > opt->cipso) | ||
1843 | opt->srr -= cipso_len; | ||
1844 | if (opt->rr > opt->cipso) | ||
1845 | opt->rr -= cipso_len; | ||
1846 | if (opt->ts > opt->cipso) | ||
1847 | opt->ts -= cipso_len; | ||
1848 | if (opt->router_alert > opt->cipso) | ||
1849 | opt->router_alert -= cipso_len; | ||
1850 | opt->cipso = 0; | ||
1851 | |||
1852 | memmove(cipso_ptr, cipso_ptr + cipso_len, | ||
1853 | opt->optlen - cipso_off - cipso_len); | ||
1854 | |||
1855 | /* determining the new total option length is tricky because of | ||
1856 | * the padding necessary, the only thing i can think to do at | ||
1857 | * this point is walk the options one-by-one, skipping the | ||
1858 | * padding at the end to determine the actual option size and | ||
1859 | * from there we can determine the new total option length */ | ||
1860 | iter = 0; | ||
1861 | optlen_new = 0; | ||
1862 | while (iter < opt->optlen) | ||
1863 | if (opt->__data[iter] != IPOPT_NOP) { | ||
1864 | iter += opt->__data[iter + 1]; | ||
1865 | optlen_new = iter; | ||
1866 | } else | ||
1867 | iter++; | ||
1868 | hdr_delta = opt->optlen; | ||
1869 | opt->optlen = (optlen_new + 3) & ~3; | ||
1870 | hdr_delta -= opt->optlen; | ||
1871 | } else { | ||
1872 | /* only the cipso option was present on the socket so we can | ||
1873 | * remove the entire option struct */ | ||
1874 | sk_inet->opt = NULL; | ||
1875 | hdr_delta = opt->optlen; | ||
1876 | kfree(opt); | ||
1877 | } | ||
1878 | |||
1879 | if (sk_inet->is_icsk && hdr_delta > 0) { | ||
1880 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
1881 | sk_conn->icsk_ext_hdr_len -= hdr_delta; | ||
1882 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
1883 | } | ||
1884 | } | ||
1885 | |||
1886 | /** | ||
1813 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions | 1887 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions |
1814 | * @cipso: the CIPSO v4 option | 1888 | * @cipso: the CIPSO v4 option |
1815 | * @secattr: the security attributes | 1889 | * @secattr: the security attributes |