# -*- coding: binary -*-
module Msf

###
#
# This module provides methods for sending raw 802.11 frames using the ruby-lorcon extension.
# Please see the ruby-lorcon documentation for more information.
#
###

module Exploit::Lorcon

	#
	# Initializes an instance of an exploit module that accesses a 802.11 network
	#
	def initialize(info = {})
		super


		default_intf   = 'ath0'
		default_driver = 'madwifing'


		if (Rex::Compat.is_windows())
			# Default to the the first airpcap device on Windows
			default_intf = "\\\\.\\airpcap00"

			# Default to the airpcap driver on Windows
			default_driver = 'airpcap'
		end

		register_options(
			[
				OptString.new('INTERFACE', [true, 'The name of the wireless interface', default_intf]),
				OptString.new('DRIVER', [true, 'The name of the wireless driver for lorcon', default_driver]),
				OptInt.new('CHANNEL', [true, 'The default channel number', 11]),
				OptInt.new('TXRATE', [true, 'The injected transmit rate', 2]),
				OptEnum.new('TXMOD', [true, 'The injected modulation type', 'DSSS', %w{DEFAULT FHSS DSSS OFDM TURBO MIMO MIMOGF}])
			], Msf::Exploit::Lorcon
		)


		begin

			if(Rex::Compat.is_windows())
				airpcap = Rex::FileUtils.find_full_path("airpcap.dll")
				if (not airpcap)
					raise RuntimeError, "The airpcap.dll library must be installed"
				end
			end

			require 'Lorcon'
			@lorcon_loaded = true

		rescue ::Exception => e
			@lorcon_loaded = false
			@lorcon_error  = e
		end

	end

	#
	# Opens a handle to the specified wireless device
	#
	def open_wifi

		if (not @lorcon_loaded)
			print_status("The Lorcon module is not available: #{@lorcon_error}")
			raise RuntimeError, "Lorcon not available"
		end

		# XXX: Force the interface to be up
		system("ifconfig", datastore['INTERFACE'], "up")

		self.wifi = ::Lorcon::Device.new(datastore['INTERFACE'], datastore['DRIVER'])
		if (not self.wifi)
			raise RuntimeError, "Could not open the wireless device interface"
		end

		# Configure the card for reliable injection
		self.wifi.fmode      = "INJECT"
		self.wifi.channel    = (datastore['CHANNEL'] || 11).to_i


		# Configure modulation
		begin
			self.wifi.modulation = datastore['TXMOD']
		rescue ::ArgumentError => e
			print_status("Warning: #{e}")
		end

		# Configure the transmission rate
		begin
			self.wifi.txrate     = datastore['TXRATE'].to_i if datastore['TXRATE']
		rescue ::ArgumentError => e
			print_status("Warning: #{e}")
		end

		self.wifi
	end

	def close_wifi
		self.wifi = nil
	end

	#
	# Converts ethernet addresses to binary
	#
	def eton(addr)
		addr.split(':').map { |c| c.hex.chr }.join
	end

	def channel
		self.wifi.channel
	end

	def next_channel
		cur = self.wifi.channel
		nxt = (cur > 10) ? 1 : cur + 1
		self.wifi.channel = nxt
	end

	attr_accessor :wifi

end

end
